RSI H4 MQL5 Indicator: Swing Trading with Multi-Timeframe RSI Confluence
An H4-only custom RSI indicator with optional completed D1 EMA and H1 RSI filters. The example plots the H4 oscillator and separate up/down markers, with popup and push alerts. It generates observations for a separate strategy; it neither places orders nor supplies verified strategy returns.
How the indicator signal works
Calculation and signal conditions
An up marker requires H4 RSI to cross above the oversold input between completed bars; a down marker requires a cross below the overbought input. If enabled, compare the H4 close with the prior completed D1 EMA and require the prior completed H1 RSI to be above 50 for up or below 50 for down. This is an H1 level test, not an H1 rising/falling test.
Interpretation and limitations
No trade exits, divergence detector, MACD filter or ATR trailing stop are implemented. The code uses the first next available H4 opening time as the historical decision time, maps it to each filter timeframe and reads the preceding source bar. Missing filter data withholds that signal instead of disabling a requested filter. Completed-bar evaluation avoids using the forming H4 bar for alerts, but revised data can still change history.
MQL5 Custom Indicator Code
#property strict
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots 3
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrDodgerBlue
#property indicator_label1 "H4 RSI"
#property indicator_type2 DRAW_ARROW
#property indicator_color2 clrLimeGreen
#property indicator_label2 "Completed-bar up signal"
#property indicator_type3 DRAW_ARROW
#property indicator_color3 clrTomato
#property indicator_label3 "Completed-bar down signal"
input int InpRSIPeriod=14;
input double InpOverbought=70;
input double InpOversold=30;
input bool InpUseHTFFilter=true;
input int InpHTFEMA=200;
input bool InpUseH1Confirmation=true;
input int InpH1RSIPeriod=14;
input bool PopupAlerts=true;
input bool PushAlerts=false;
double rsiLine[],up[],down[];
int hRSI=INVALID_HANDLE,hEMA=INVALID_HANDLE,hH1=INVALID_HANDLE;
datetime lastClosed=0;
int OnInit()
{
if(_Period!=PERIOD_H4 || InpRSIPeriod<2 || InpHTFEMA<2 || InpH1RSIPeriod<2 ||
InpOversold<0 || InpOverbought>100 || InpOversold>=InpOverbought)
return INIT_PARAMETERS_INCORRECT;
SetIndexBuffer(0,rsiLine,INDICATOR_DATA); SetIndexBuffer(1,up,INDICATOR_DATA);
SetIndexBuffer(2,down,INDICATOR_DATA);
ArraySetAsSeries(rsiLine,false); ArraySetAsSeries(up,false); ArraySetAsSeries(down,false);
for(int p=0;p<3;p++) { PlotIndexSetInteger(p,PLOT_DRAW_BEGIN,InpRSIPeriod+1); PlotIndexSetDouble(p,PLOT_EMPTY_VALUE,EMPTY_VALUE); }
PlotIndexSetInteger(1,PLOT_ARROW,233); PlotIndexSetInteger(2,PLOT_ARROW,234);
IndicatorSetInteger(INDICATOR_LEVELS,2);
IndicatorSetDouble(INDICATOR_LEVELVALUE,0,InpOversold); IndicatorSetDouble(INDICATOR_LEVELVALUE,1,InpOverbought);
IndicatorSetInteger(INDICATOR_DIGITS,2);
hRSI=iRSI(_Symbol,PERIOD_H4,InpRSIPeriod,PRICE_CLOSE);
if(InpUseHTFFilter) hEMA=iMA(_Symbol,PERIOD_D1,InpHTFEMA,0,MODE_EMA,PRICE_CLOSE);
if(InpUseH1Confirmation) hH1=iRSI(_Symbol,PERIOD_H1,InpH1RSIPeriod,PRICE_CLOSE);
if(hRSI==INVALID_HANDLE || (InpUseHTFFilter && hEMA==INVALID_HANDLE) ||
(InpUseH1Confirmation && hH1==INVALID_HANDLE)) return INIT_FAILED;
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(hRSI!=INVALID_HANDLE) IndicatorRelease(hRSI);
if(hEMA!=INVALID_HANDLE) IndicatorRelease(hEMA);
if(hH1!=INVALID_HANDLE) IndicatorRelease(hH1);
}
bool PriorCompletedValue(const int handle,const ENUM_TIMEFRAMES tf,const int warmup,
const datetime decisionTime,double &value)
{
int containing=iBarShift(_Symbol,tf,decisionTime,false);
if(containing<0) return false;
int shift=containing+1; // Never use the source bar containing the decision time.
if(BarsCalculated(handle)<=shift+warmup) return false;
double v[1];
if(CopyBuffer(handle,0,shift,1,v)!=1 || v[0]==EMPTY_VALUE || !MathIsValidNumber(v[0])) return false;
value=v[0]; return true;
}
int OnCalculate(const int rates_total,const int prev_calculated,const datetime &time[],
const double &open[],const double &high[],const double &low[],const double &close[],
const long &tick_volume[],const long &volume[],const int &spread[])
{
if(rates_total<InpRSIPeriod+3) return 0;
ArraySetAsSeries(time,false); ArraySetAsSeries(close,false);
double raw[]; ArraySetAsSeries(raw,false);
if(CopyBuffer(hRSI,0,0,rates_total,raw)!=rates_total) return prev_calculated;
ArrayInitialize(up,EMPTY_VALUE); ArrayInitialize(down,EMPTY_VALUE);
for(int i=0;i<rates_total;i++) rsiLine[i]=i>=InpRSIPeriod?raw[i]:EMPTY_VALUE;
bool newestReady=true;
for(int i=InpRSIPeriod+1;i<rates_total-1;i++)
{
bool bull=raw[i-1]<=InpOversold && raw[i]>InpOversold;
bool bear=raw[i-1]>=InpOverbought && raw[i]<InpOverbought;
if(!bull && !bear) continue;
double ema=0,h1=50;
datetime decision=time[i+1]; // First next available H4 bar open.
bool ready=(!InpUseHTFFilter || PriorCompletedValue(hEMA,PERIOD_D1,InpHTFEMA,decision,ema)) &&
(!InpUseH1Confirmation || PriorCompletedValue(hH1,PERIOD_H1,InpH1RSIPeriod,decision,h1));
if(!ready) { if(i==rates_total-2) newestReady=false; continue; }
if(bull && (!InpUseHTFFilter || close[i]>ema) && (!InpUseH1Confirmation || h1>50)) up[i]=raw[i];
if(bear && (!InpUseHTFFilter || close[i]<ema) && (!InpUseH1Confirmation || h1<50)) down[i]=raw[i];
}
int latest=rates_total-2;
if(prev_calculated==0 || lastClosed==0) lastClosed=time[latest];
else if(newestReady && time[latest]!=lastClosed)
{
lastClosed=time[latest];
if(up[latest]!=EMPTY_VALUE || down[latest]!=EMPTY_VALUE)
{
string msg=StringFormat("%s H4 RSI completed-bar %s",_Symbol,up[latest]!=EMPTY_VALUE?"up signal":"down signal");
if(PopupAlerts) Alert(msg);
if(PushAlerts && !SendNotification(msg)) Print("Push failed: ",GetLastError());
}
}
return rates_total;
}Copy this code into MetaEditor, save it in the MQL5/Indicators folder, and compile with F7.
Change the settings or add your own signal filter
Describe the inputs, buffers, alerts, visual style, or confirmation filter you want. Pineify generates editable MQL5 source code that you can inspect and compile in MetaEditor.
Frequently Asked Questions
Related MQL5 pages
Technical references
Risk and testing note
These educational examples require independent compilation and testing. A compile pass or an illustrative setting does not establish execution correctness or profitability. Any reported performance must be supported by reproducible data and test settings; past results do not predict future returns. Trading involves significant risk of loss. This content is not financial advice.