Need help with RSI indicator

Hello Guys,

I am trying to build a RSI EA using iRSI in MQL5.

My strategy is simple. It should take a buy trade if RSI is crossing above level 30 and close buy trade when RSI crossing below level 70.

But currenttly iRSI is taking trades on level 30 no matter if it is crossing level 30 from above or below.

Is there any way to solve this? Attaching my EA below

#include <Trade\Trade.mqh>
input int MagicNumber=10001;
input double StopLoss=0;
input double TakeProfit=0;
input int TrailingStop=0;
input double Prd =2;
input double Buyy =55;
input double Buyystop =45;
input double Sell =45;
input double Sellstop =55;
input double MaximumRisk        = 0.05;    // Maximum Risk in percentage
input double DecreaseFactor     = 0;       // Descrease factor
//+------------------------------------------------------------
//+------------------------------------------------------------------+
//    expert start function
//+------------------------------------------------------------------+

 ENUM_MA_METHOD MethodMigrate(int method)
  {
   switch(method)
     {
      case 0: return(MODE_SMA);
      case 1: return(MODE_EMA);
      case 2: return(MODE_SMMA);
      case 3: return(MODE_LWMA);
      default: return(MODE_SMA);
     }
  }
  
ENUM_STO_PRICE StoFieldMigrate(int field)
  {
   switch(field)
     {
      case 0: return(STO_LOWHIGH);
      case 1: return(STO_CLOSECLOSE);
      default: return(STO_LOWHIGH);
     }
  }
ENUM_APPLIED_PRICE PriceMigrate(int price)
  {
   switch(price)
     {
      case 1: return(PRICE_CLOSE);
      case 2: return(PRICE_OPEN);
      case 3: return(PRICE_HIGH);
      case 4: return(PRICE_LOW);
      case 5: return(PRICE_MEDIAN);
      case 6: return(PRICE_TYPICAL);
      case 7: return(PRICE_WEIGHTED);
      default: return(PRICE_CLOSE);
     }
  }

ENUM_TIMEFRAMES TFMigrate(int tf)
  {
   switch(tf)
     {
      case 0: return(PERIOD_CURRENT);
      case 1: return(PERIOD_M1);
      case 5: return(PERIOD_M5);
      case 15: return(PERIOD_M15);
      case 30: return(PERIOD_M30);
      case 60: return(PERIOD_H1);
      case 240: return(PERIOD_H4);
      case 1440: return(PERIOD_D1);
      case 10080: return(PERIOD_W1);
      case 43200: return(PERIOD_MN1);
      
      case 2: return(PERIOD_M2);
      case 3: return(PERIOD_M3);
      case 4: return(PERIOD_M4);      
      case 6: return(PERIOD_M6);
      case 10: return(PERIOD_M10);
      case 12: return(PERIOD_M12);
      case 16385: return(PERIOD_H1);
      case 16386: return(PERIOD_H2);
      case 16387: return(PERIOD_H3);
      case 16388: return(PERIOD_H4);
      case 16390: return(PERIOD_H6);
      case 16392: return(PERIOD_H8);
      case 16396: return(PERIOD_H12);
      case 16408: return(PERIOD_D1);
      case 32769: return(PERIOD_W1);
      case 49153: return(PERIOD_MN1);      
      default: return(PERIOD_CURRENT);
     }
  }
  


//---
#define EMPTY -1

//+------------------------------------------------------------------+
//| Calculate optimal lot size                                       |
//+------------------------------------------------------------------+
double TradeSizeOptimized(void)
  {
   double price=0.0;
   double margin=0.0;
//--- select lot size
   if(!SymbolInfoDouble(_Symbol,SYMBOL_ASK,price))
      return(0.0);
   if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin))
      return(0.0);
   if(margin<=0.0)
      return(0.0);

   double lot=NormalizeDouble(AccountInfoDouble(ACCOUNT_MARGIN_FREE)*MaximumRisk/margin,2);
//--- calculate number of losses orders without a break
   if(DecreaseFactor>0)
     {
      //--- select history for access
      HistorySelect(0,TimeCurrent());
      //---
      int    orders=HistoryDealsTotal();  // total history deals
      int    losses=0;                    // number of losses orders without a break

      for(int i=orders-1;i>=0;i--)
        {
         ulong ticket=HistoryDealGetTicket(i);
         if(ticket==0)
           {
            Print("HistoryDealGetTicket failed, no trade history");
            break;
           }
         //--- check symbol
         if(HistoryDealGetString(ticket,DEAL_SYMBOL)!=_Symbol)
            continue;
         //--- check Expert Magic number
         if(HistoryDealGetInteger(ticket,DEAL_MAGIC)!=MagicNumber)
            continue;
         //--- check profit
         double profit=HistoryDealGetDouble(ticket,DEAL_PROFIT);
         if(profit>0.0)
            break;
         if(profit<0.0)
            losses++;
        }
      //---
      if(losses>1)
         lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);
     }
//--- normalize and check limits
   double stepvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
   lot=stepvol*NormalizeDouble(lot/stepvol,0);

   double minvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   if(lot<minvol)
      lot=minvol;

   double maxvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
   if(lot>maxvol)
      lot=maxvol;
//--- return trading volume
   return(lot);
  }


void OnTick()
{
// Check for New Bar
static datetime dtBarCurrent   = WRONG_VALUE;
       datetime dtBarPrevious  = dtBarCurrent;
                dtBarCurrent   = (datetime) SeriesInfoInteger( _Symbol, _Period, SERIES_LASTBAR_DATE );

       bool     boolNewBarFlag = ( dtBarCurrent != dtBarPrevious );

if( boolNewBarFlag ) { 

CTrade trade;
trade.SetExpertMagicNumber(MagicNumber);
double Ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
double Bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);

  double MyPoint=_Point;
  if(_Digits==3 || _Digits==5) MyPoint=_Point*10;
  double TheStopLoss=0;
  double TheTakeProfit=0;
  if( TotalOrdersCount()==0 ) 
  {
     
     if((iRSIMQL4(NULL,0,Prd,PRICE_CLOSE,00)>Buyy)) // Here is your open buy rule
     {
     
        if(StopLoss>0) TheStopLoss=SymbolInfoDouble(_Symbol,SYMBOL_ASK)-StopLoss*MyPoint;
        if(TakeProfit>0) TheTakeProfit=SymbolInfoDouble(_Symbol,SYMBOL_ASK)+TakeProfit*MyPoint;
        trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,TradeSizeOptimized(),SymbolInfoDouble(_Symbol,SYMBOL_ASK),TheStopLoss,TheTakeProfit);
        return;
     }
     
     if((iRSIMQL4(NULL,0,Prd,PRICE_CLOSE,00)<Sell)) // Here is your open Sell rule
     {
        if(StopLoss>0) TheStopLoss=SymbolInfoDouble(_Symbol,SYMBOL_ASK)+StopLoss*MyPoint;
        if(TakeProfit>0) TheTakeProfit=SymbolInfoDouble(_Symbol,SYMBOL_ASK)-TakeProfit*MyPoint;
        trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,TradeSizeOptimized(),SymbolInfoDouble(_Symbol,SYMBOL_BID),TheStopLoss,TheTakeProfit);
        return;
     }
     
  }
  
   int posTotal=PositionsTotal();
   for(int posIndex=posTotal-1;posIndex>=0;posIndex--)
     {
      ulong ticket=PositionGetTicket(posIndex);
      if(PositionSelectByTicket(ticket) && PositionGetInteger(POSITION_MAGIC)==MagicNumber) 
      {
     if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
        {
              if((iRSIMQL4(NULL,0,Prd,PRICE_CLOSE,00)<Buyystop)) //here is your close buy rule
         {
         trade.PositionClose(ticket);
         break;
         }
       
         if(TrailingStop>0)  
              {                 
               if(SymbolInfoDouble(_Symbol,SYMBOL_BID)-PositionGetDouble(POSITION_PRICE_OPEN)>MyPoint*TrailingStop)
                 {
                  if(PositionGetDouble(POSITION_SL)<SymbolInfoDouble(_Symbol,SYMBOL_BID)-MyPoint*TrailingStop)
                    {
                    trade.PositionModify(ticket,SymbolInfoDouble(_Symbol,SYMBOL_BID)-MyPoint*TrailingStop,PositionGetDouble(POSITION_TP));
                     return;
                    }
                 }
              }
        }
      
       if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
        {
                if((iRSIMQL4(NULL,0,Prd,PRICE_CLOSE,00)>Sellstop)) // here is your close sell rule
         {
         trade.PositionClose(ticket);
         break;
         }
          if(TrailingStop>0)  
              {                 
               if(PositionGetDouble(POSITION_PRICE_OPEN)-SymbolInfoDouble(_Symbol,SYMBOL_ASK)>MyPoint*TrailingStop)
                 {
                  if(PositionGetDouble(POSITION_SL)>SymbolInfoDouble(_Symbol,SYMBOL_ASK)+MyPoint*TrailingStop)
                    {
                    trade.PositionModify(ticket,SymbolInfoDouble(_Symbol,SYMBOL_ASK)+MyPoint*TrailingStop,PositionGetDouble(POSITION_TP));
                     return;
                    }
                 }
              }
        }
      }
     }  
    return;
}
}

int TotalOrdersCount()
{
  int result=0;
  int posTotal=PositionsTotal();
   for(int posIndex=posTotal-1;posIndex>=0;posIndex--)
     {
      ulong ticket=PositionGetTicket(posIndex);
      if(PositionSelectByTicket(ticket) && PositionGetInteger(POSITION_MAGIC)==MagicNumber) result++;
     }  
  return (result);
}


int Hour()
{
   MqlDateTime tm;
   TimeCurrent(tm);
   return(tm.hour);
}
int Minute()
{
   MqlDateTime tm;
   TimeCurrent(tm);
   return(tm.min);
}

double CopyBufferMQL4(int handle,int index,int shift)
  {
   double buf[];
   switch(index)
     {
      case 0: if(CopyBuffer(handle,0,shift,1,buf)>0)
         return(buf[0]); break;
      case 1: if(CopyBuffer(handle,1,shift,1,buf)>0)
         return(buf[0]); break;
      case 2: if(CopyBuffer(handle,2,shift,1,buf)>0)
         return(buf[0]); break;
      case 3: if(CopyBuffer(handle,3,shift,1,buf)>0)
         return(buf[0]); break;
      case 4: if(CopyBuffer(handle,4,shift,1,buf)>0)
         return(buf[0]); break;
      default: break;
     }
   return(EMPTY_VALUE);
  }
  
  

  double iRSIMQL4(string symbol,
                int tf,
                int period,
                int price,
                int shift)
  {
   ENUM_TIMEFRAMES timeframe=TFMigrate(tf);
   ENUM_APPLIED_PRICE applied_price=PriceMigrate(price);
   int handle=iRSI(symbol,timeframe,period,applied_price);
   if(handle<0)
     {
      return(-1);
     }
   else
      return(CopyBufferMQL4(handle,0,shift));
  }
1 Like

Hi, your rule is “If RSI for previous bar is > 30 then BUY”
To capture only cross you need to have TWO conditions:

  • RSI for bar -1 > 30
  • RSI for bar -2 < 30

So basically for Daily timeframe, on Monday it needs to be below 30, on Tuesday above 30 to have a cross. Similarily you need to identify the cross for upper part of RSI.

(btw your code looks not bad, but it’s very long for such simple strategy. Think about closing reusable functions in MQH files, such as opening trades, setting break even, trailing stops, calculating position size to risk etc.)

2 Likes

RSI is not regarded as being an effective indicator, according to No Nonsense Forex testing analysis. He said what it is useful for is to just have a 50 line to confirm trend. Above 50 for bullish, and below for bearish.

The trouble with the standard settings is that trades can stay for days, even weeks being overbought or oversold.

2 Likes

The question here is not if RSI is effective or not. It was a coding issue to be resolved.

What does it mean, that RSI is not effective? Buying on 30 cross down is not effective? or buying on 30 cross up? Or maybe even selling on 30 cross down? Is it not effective for any potential risk/reward ratio and regardless of target TP/SL size?

Beginners are reading this forum and such general opinion may close some doors for them. I would encourage anyone to test and experiment with RSI and decide on their own. Instead of “RSI is not effective indicator” I would say “buying when RSI on default settings go into oversold without any other factors may not be profitable strategy in strong downtrend”.

2 Likes

Maybe you should read my post again. It stated what the No Nonsense FX guy said on Youtube when he tested out this indicator, as he does with dozens of others.He is a reliable source of information, and his take was as I stated.

I use RSI 50 as a trend signal, but it’s not an indicator I’d use for changing gear, as price action is by far the best probability movement.

As for the coding issue, there are better indicators to spend your time with.

1 Like

Did you code this yourself? I’m no expert but these bits of code seem to contradict your description.

 if((iRSIMQL4(NULL,0,Prd,PRICE_CLOSE,00)<Sell)) // Here is your open Sell rule
 {
    if(StopLoss>0) TheStopLoss=SymbolInfoDouble(_Symbol,SYMBOL_ASK)+StopLoss*MyPoint;
    if(TakeProfit>0) TheTakeProfit=SymbolInfoDouble(_Symbol,SYMBOL_ASK)-TakeProfit*MyPoint;
    trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,TradeSizeOptimized(),SymbolInfoDouble(_Symbol,SYMBOL_BID),TheStopLoss,TheTakeProfit);
    return;
 }

and

   if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
    {
            if((iRSIMQL4(NULL,0,Prd,PRICE_CLOSE,00)>Sellstop)) // here is your close sell rule
     {
     trade.PositionClose(ticket);
     break;

Plus the weird bit that stands out is that it looks like an attempted conversion of an MQL4 to 5 code? The syntax is in the form of MQL4 and not MQL5. Also not sure how declaring the MAs, Stoch and Timeframes are supposed to help either.

I’m not an expert but the codes looks very messy and doesn’t appear to fulfill the described function. I’d code one from scratch if I were you and get rid of redundant lines of code and avoid conversion errors (try compiling the code). Probably the best place to try is the MQL5 forum.

No Nonsense Forex guy as in Victor Patrick? He’s got a very poor testing methodology. He bashes indicators and the RSI in particular when he’s using it standalone. No textbook recommends using oscillators standalone so not sure what he’s trying to prove.

If I remember the RSI video he cites (from about 2 years ago) he makes two alarming claims:

  1. There’s no overselling/overbuying in forex: Don’t see how this is relevant if he understands the RSI formula
  2. It’s outdated since it came out in 1978: The ATR he uses in his system was developed in the same year by the same guy. Don’t know why he chooses to point how supposedly outdated this is in this instance only.

Hopefully I’m not misremembering things, but I completely unsubbed from him and anything he has to say after I saw him butchering the use of the Ichomoku Kinko Hyo. Garbage explanation on his part.

Yeah, I guess we’re not all perfect. The argument against these indicators, apart from lagging is that overbought and sold positions can last days, if not weeks. That’s not much use, is it?

It is quite factual that overbought and oversold indicators are losing strategies long term. Unless, of course they’re confirmation to an otherwise probable trade based on price action movement.

As for Ichimoku, which I use, more to prevent me for making an unsuitable trade. It has stood the test of time, and used as intended - in a trending market - is a better than 50% indicator. As an aside to that, IMO, in today’s covid environment the only true probability is price action and timing.

Come on guys, wake up to yourselves… You sound like a New Mothers Club…

The only way to get these standard Indicators to be profitable is by applying outside the box thinking…

GBPJPY 4 Hour Chart (Current) Not cherry-picked!!

Simple 4 Hour Chart with RSI 4 Period applied… High of 75 Low… of 25 to apply some smoothing.

Cross below the 25 is a Sell… Cross above the 75 is a Buy… A cross in the opposite direction reverses the trade… And Bingo… You have a viable RSI Strategy on the 4 Hour timeframe that has gained 1076 pips over the last 30 days… It won’t win every trade, but it will lose small and win large…

Even a new trader using 1:100 margin account and 0.05 lot positions should have added 660 whatevers to his/hers account…

Don’t want to use the GBPJPY… No problem, just layout the template and toggle through your favorite pairs until you find one that gives clean trading opportunities… Tweak the settings if it is required…

I have laid it all out so even Stevie Wonder won’t trip over it…

|

A few more examples…

EURUSD 4 Hour - 204 pips / 138 Buttons in 30 days of trading…

AUDUSD 4 Hour - 529 pips / 358 Buttons in 30 days of trading…

2 Likes

I think it works in your examples due to the fact that the market is ranging at present (medium term). Do you agree?

@meza, Bitcoin is one of the most volatile instruments to trade in the markets today… (See Below)

Bitcoin 4 Hour (Current) Chart with the same strategy applied… Manually back testing each Instrument across the previous 30/60/90 day period will display the slight tweaks required I explained in the original post…

Period is now 3, High is now 80… Low is now 20 which sharpens the Indicator for use on this volatile crypto… Gains 132,000 pips - Loses 4,000 pips = 128,000 across a 30 day period…

A strategy like this should require 15-30 mins per day…

It can be applied to the 15 min (Current) Chart only change erquired was to extend the Period to 4…

Using exactly the same entry and exit criteria as displayed in the original post a disciplined trader should have gained 43,800 pips and lost 1,800 pips = 42,000 pip gain across a 3 day period…

No Take Profits or Stop Losses (OMG!) have been used in any of these displayed strategies, Price Action and the Indicator alone allows you to implement such a simple strategy… Trial on a DEMO!!

1 Like

So, I take it you close your position when it crosses in the opposite direction. That means you need to be in front of your screen virtually all day.
Unless you can set it up as an EA.
Have you tried to modify it so it could work as an EOD strategy?

@meza, You might want to sit there all day… OR you could just download a FREE RSI Alert Indicator for MT4 or MT5 (See Below) from MQL5 Website and apply the strategy to your chosen pair…

Set it up to send you an email or Notification to your mobile… You have a few hours to enter and exit each trade on the 4 hour time frame…

It’s pretty simple to test if you put some real thought into it…

Are you trading this yourself?

@meza I used to trade a very similar strategy a few years back… If you search through my posts back in 2017 - 2019 you will see it’s not the first time I have posted this trading strategy… You will find trades posted live over a couple of weeks…

Only stopped at the time because a few of the “self appointed BP experts” got their panties all in a bunch… Would make for some interesting reading if you can be bothered to dig for it…

I have a couple of sharper strategies which I trade these days… That won’t see the light of day in BP…

Edit: You were here in 2008!.. nearly 10 years before me… You might have seen it in your travels…

2 Likes

I like the simplicity and will demo it.
Thanks for sharing.

1 Like

interesting range of opinions, here, on how to use the RSI

1 Like

This strategy of mine was working with RSI filtered with ADX.
->https://www.darwinex.com/darwin/KVL
It worked pretty well for 2 years.
99% of strategies fail
99% of srategies with RSI or other oscillators fail
99% of strategies with movng averages fail
99% of strategies with candlestick patterns AKA “price action” fail.

I’m no expert but apparently folks use other levels as well after studying and understanding the nuances of the RSI. Here’s an excerpt from this book that gives some insight:

RSI_part 1

The RSI portion concludes with this para:

RSI_part 2

@darthdimsky, good article that shows that what I have posted is not rocket science. Many traders before me have used similar concepts in their attempt to make the RSI profitable….

To offset the RSI values concurrent with the longer term trend is a characteristic that I had noticed when back testing, but never applied. So many thanks @darthdimsky for highlighting that text. It is something that I and other readers of your post can add to back testing this strategy.

There is many other Oscillators that can be applied in the same way? It’s really just converting the RSI to give it stochastic behaviour.

CCI, DPO, Trix, Williams%R etc. Virtually any bound indicator that displays the extremes (not strengths) of price action.

2 Likes