How to use Predefined Indicator for MultiPair EA?

shanmugapradeep

Master Trader
Dec 18, 2020
180
16
54
40
MQL5:
fRSI(SelectedSymbol, PERIOD_CURRENT, 14, PRICE_CLOSE, 0);
 
double fRSI(string sy,ENUM_TIMEFRAMES SelectedTimeFrame,int period,ENUM_APPLIED_PRICE applied_price,int shift)
{
double buf[1];
int handle=iRSI(sy,SelectedTimeFrame,period,applied_price);
if(handle<0)
{
OpenNewTrade = false;
return(0);
}
else
{
if(CopyBuffer(handle,0,shift,1,buf)<0)
{
OpenNewTrade = false;
IndicatorRelease(handle);
return(0);
}
}
IndicatorRelease(handle);
return(buf[0]);
}

List of Indicator : https://www.mql5.com/en/docs/indicators/irsi


For example, i made function for RSI. is this right way to use for multi-currency pair EA?
 
I don't think it's a good way to use indicator handles in MT5.
The general rule is to declare an indicator handle for the given symbol/period combination only once. And then use a function to only copy different sections of the indicator values to a buffer.
If you are building a multi-symbol multi-period EA, you need an array of handles, but it's better to declare all the handles you will need beforehand - inside OnInit().
 
How about this?

ATR

MQL5:
double fATR(string sy, ENUM_TIMEFRAMES SelectedTimeFrame,int ATRper,int shift)
  {
   double atrBuf[];
   ArrayResize(atrBuf,ATRper+shift+1);
   int i=ATRper+shift;
   while(i>=0)
     {
      double high=iHigh(sy,SelectedTimeFrame,i);
      double low =iLow(sy,SelectedTimeFrame,i);
      double prevclose=iClose(sy,SelectedTimeFrame,i+1);
      atrBuf[i]=fmax(high,prevclose)-fmin(low,prevclose);
      i--;
     }
   return(SMA(ATRper+shift+1,atrBuf,ATRper,shift));
  }
//+------------------------------------------------------------------+
double SMA(const int rates_total,const double &array_src[],const int period,const int shift)
  {
   if(period<1 || shift>rates_total-period-1)
      return array_src[shift];
   double sum=0;
   for(int i=0; i<period; i++)
      sum+=array_src[shift+i];
   return(sum/period);
  }

Moving Average

MQL5:
struct MA_HANDLE
  {
   string            symbol;
   ENUM_TIMEFRAMES   tf;
   int               period;
   int               shift;
   ENUM_MA_METHOD    method;
   ENUM_APPLIED_PRICE price;
   int               handle;
  };
 
MA_HANDLE MAHandles[];
//MA Handle
int GetMAHandle(string sy, ENUM_TIMEFRAMES tf,
                int period, int ma_shift,
                ENUM_MA_METHOD method,
                ENUM_APPLIED_PRICE price)
  {
   for(int i=0;i<ArraySize(MAHandles);i++)
     {
      if(MAHandles[i].symbol==sy &&
         MAHandles[i].tf==tf &&
         MAHandles[i].period==period &&
         MAHandles[i].shift==ma_shift &&
         MAHandles[i].method==method &&
         MAHandles[i].price==price)
        {
         return MAHandles[i].handle;
        }
     }
 
   int h = iMA(sy, tf, period, ma_shift, method, price);
   if(h == INVALID_HANDLE)
      return INVALID_HANDLE;
 
   int n = ArraySize(MAHandles);
   ArrayResize(MAHandles, n+1);
 
   MAHandles[n].symbol = sy;
   MAHandles[n].tf     = tf;
   MAHandles[n].period = period;
   MAHandles[n].shift  = ma_shift;
   MAHandles[n].method = method;
   MAHandles[n].price  = price;
   MAHandles[n].handle = h;
 
   return h;
  }
 
//MA Value
double pMA(string sy, ENUM_TIMEFRAMES tf,
           int period,int ma_shift,
           ENUM_MA_METHOD method,
           ENUM_APPLIED_PRICE price,
           int shift)
  {
   int h = GetMAHandle(sy, tf, period, ma_shift, method, price);
   if(h == INVALID_HANDLE)
      return 0;
 
   double buf[];
   if(CopyBuffer(h, 0, shift, 1, buf) <= 0)
      return 0;
 
   return buf[0];
  }

BollingerBands

MQL5:
struct BB_HANDLE
  {
   string            symbol;
   ENUM_TIMEFRAMES   tf;
   int               period;
   double            deviation;
   int               shift;
   ENUM_APPLIED_PRICE price;
   int               handle;
  };
 
BB_HANDLE BBHandles[];
//BB Handle
int GetBBHandle(string sy, ENUM_TIMEFRAMES tf,
                int period, double deviation,
                int bands_shift,
                ENUM_APPLIED_PRICE price)
  {
   for(int i=0; i<ArraySize(BBHandles); i++)
     {
      if(BBHandles[i].symbol == sy &&
         BBHandles[i].tf == tf &&
         BBHandles[i].period == period &&
         BBHandles[i].deviation == deviation &&
         BBHandles[i].shift == bands_shift &&
         BBHandles[i].price == price)
        {
         return BBHandles[i].handle; //  reuse
        }
     }
 
// ❗ create only once
   int h = iBands(sy, tf, period, bands_shift, deviation, price);
   if(h == INVALID_HANDLE)
      return INVALID_HANDLE;
 
   int n = ArraySize(BBHandles);
   ArrayResize(BBHandles, n + 1);
 
   BBHandles[n].symbol    = sy;
   BBHandles[n].tf        = tf;
   BBHandles[n].period    = period;
   BBHandles[n].deviation = deviation;
   BBHandles[n].shift     = bands_shift;
   BBHandles[n].price     = price;
   BBHandles[n].handle    = h;
 
   return h;
  }
//BB Value
double pBands(string sy,
              ENUM_TIMEFRAMES tf,
              int period,
              double deviation,
              int bands_shift,
              ENUM_APPLIED_PRICE price,
              int mode,   // 0=Upper, 1=Middle, 2=Lower
              int shift)
  {
   int h = GetBBHandle(sy, tf, period, deviation, bands_shift, price);
   if(h == INVALID_HANDLE)
      return 0;
 
   double buf[];
   if(CopyBuffer(h, mode, shift, 1, buf) <= 0)
      return 0;
 
   return buf[0];
  }

RSI

MQL5:
struct RSI_HANDLE
  {
   string            symbol;
   ENUM_TIMEFRAMES   tf;
   int               period;
   ENUM_APPLIED_PRICE price;
   int               handle;
  };
 
RSI_HANDLE RSIHandles[];
//RSI Handle
int GetRSIHandle(string sy,
                 ENUM_TIMEFRAMES tf,
                 int period,
                 ENUM_APPLIED_PRICE price)
  {
   for(int i=0; i<ArraySize(RSIHandles); i++)
     {
      if(RSIHandles[i].symbol == sy &&
         RSIHandles[i].tf == tf &&
         RSIHandles[i].period == period &&
         RSIHandles[i].price == price)
        {
         return RSIHandles[i].handle; //  reuse
        }
     }
 
// ❗ create once
   int h = iRSI(sy, tf, period, price);
   if(h == INVALID_HANDLE)
      return INVALID_HANDLE;
 
   int n = ArraySize(RSIHandles);
   ArrayResize(RSIHandles, n + 1);
 
   RSIHandles[n].symbol = sy;
   RSIHandles[n].tf     = tf;
   RSIHandles[n].period = period;
   RSIHandles[n].price  = price;
   RSIHandles[n].handle = h;
 
   return h;
  }
//Get RSI Value
double pRSI(string sy,
            ENUM_TIMEFRAMES tf,
            int period,
            ENUM_APPLIED_PRICE price,
            int shift)
  {
   int h = GetRSIHandle(sy, tf, period, price);
   if(h == INVALID_HANDLE)
      return 0;
 
   double buf[];
   if(CopyBuffer(h, 0, shift, 1, buf) <= 0)
      return 0;
 
   return buf[0];
  }

ADX

MQL5:
struct ADX_HANDLE
  {
   string            symbol;
   ENUM_TIMEFRAMES   tf;
   int               period;
   int               handle;
  };
 
ADX_HANDLE ADXHandles[];
 
//Get ADX Handle
int GetADXHandle(string sy,
                 ENUM_TIMEFRAMES tf,
                 int period)
  {
   for(int i = 0; i < ArraySize(ADXHandles); i++)
     {
      if(ADXHandles[i].symbol == sy &&
         ADXHandles[i].tf == tf &&
         ADXHandles[i].period == period)
        {
         return ADXHandles[i].handle; //  reuse
        }
     }
 
// ❗ create once
   int h = iADX(sy, tf, period);
   if(h == INVALID_HANDLE)
      return INVALID_HANDLE;
 
   int n = ArraySize(ADXHandles);
   ArrayResize(ADXHandles, n + 1);
 
   ADXHandles[n].symbol = sy;
   ADXHandles[n].tf     = tf;
   ADXHandles[n].period = period;
   ADXHandles[n].handle = h;
 
   return h;
  }
 
//ADX Value
double pADX(string sy,
            ENUM_TIMEFRAMES tf,
            int period,
            int mode,   // 0=ADX, 1=+DI, 2=-DI
            int shift)
  {
   int h = GetADXHandle(sy, tf, period);
   if(h == INVALID_HANDLE)
      return 0;
 
   double buf[];
   if(CopyBuffer(h, mode, shift, 1, buf) <= 0)
      return 0;
 
   return buf[0];
  }


Is this correct?
 
It looks good except for one thing. You create the handle just before trying to read from it. This won't work well in some cases. The reason the handles are created in OnInit is that it takes time for the platform to prepare the data for the handle.
 
It looks good except for one thing. You create the handle just before trying to read from it. This won't work well in some cases. The reason the handles are created in OnInit is that it takes time for the platform to prepare the data for the handle.

I added this in OnInit()

MQL5:
if(SymbolMode == CurrentSymbol)
     {
      for(int t=0; t<ArraySize(TimeFrameArray); t++)
        {
         GetMAHandle(Symbol(), TimeFrameArray[t], MovingAverage_Period, MovingAverage_MAShift, MovingAverage_Method, MovingAverage_AppliedPrice);
         GetRSIHandle(Symbol(), TimeFrameArray[t], RSI_Period, RSI_AppliedPrice);
         GetBBHandle(Symbol(), TimeFrameArray[t], BollingerBands_Period, BollingerBands_deviation, BollingerBands_BandShift, BollingerBands_AppliedPrice);
         GetADXHandle(Symbol(), TimeFrameArray[t], ADX_Period);
        }
     }
   else
     {
      for(int s=0; s<ArraySize(validSymbols); s++)
        {
         for(int t=0; t<ArraySize(TimeFrameArray); t++)
           {
            GetMAHandle(validSymbols[s], TimeFrameArray[t], MovingAverage_Period, MovingAverage_MAShift, MovingAverage_Method, MovingAverage_AppliedPrice);
            GetRSIHandle(validSymbols[s], TimeFrameArray[t], RSI_Period, RSI_AppliedPrice);
            GetBBHandle(validSymbols[s], TimeFrameArray[t], BollingerBands_Period, BollingerBands_deviation, BollingerBands_BandShift, BollingerBands_AppliedPrice);
            GetADXHandle(validSymbols[s], TimeFrameArray[t], ADX_Period);
           }
        }
     }

Is this correct now?
 
MovingAverage making problem.

for some currency pairs like CHFJPY, AUDCAD, etc for higher TF H6 or Above it getting freeze after that OnTick is not processing and as well as changing MT5 timeframe also do not trigger OnDenit. but price and candle running fine in MT5.

Then i have to close MT5 and open again to process OnTick (EA) again.


Updates :

I made some changes like adding more checks before MA process. Now working fine but still not sure if this is best approach.

MQL5:
struct MA_HANDLE
  {
   string            symbol;
   ENUM_TIMEFRAMES   tf;
   int               period;
   int               shift;
   ENUM_MA_METHOD    method;
   ENUM_APPLIED_PRICE price;
   int               handle;
  };
 
MA_HANDLE MAHandles[];
//MA Handle
int GetMAHandle(string sy, ENUM_TIMEFRAMES tf,
                int period, int ma_shift,
                ENUM_MA_METHOD method,
                ENUM_APPLIED_PRICE price)
  {
   for(int i=0;i<ArraySize(MAHandles);i++)
     {
      if(MAHandles[i].symbol==sy &&
         MAHandles[i].tf==tf &&
         MAHandles[i].period==period &&
         MAHandles[i].shift==ma_shift &&
         MAHandles[i].method==method &&
         MAHandles[i].price==price)
        {
         return MAHandles[i].handle;
        }
     }
 
   int h = iMA(sy, tf, period, ma_shift, method, price);
   if(h == INVALID_HANDLE)
      return INVALID_HANDLE;
 
   int n = ArraySize(MAHandles);
   ArrayResize(MAHandles, n+1);
 
   MAHandles[n].symbol = sy;
   MAHandles[n].tf     = tf;
   MAHandles[n].period = period;
   MAHandles[n].shift  = ma_shift;
   MAHandles[n].method = method;
   MAHandles[n].price  = price;
   MAHandles[n].handle = h;
 
   return h;
  }
 
//MA Value
double fMA(string sy, ENUM_TIMEFRAMES tf,
           int period, int ma_shift,
           ENUM_MA_METHOD method,
           ENUM_APPLIED_PRICE price,
           int shift)
  {
// Step 1: force price data
   if(!ForceRates(sy, tf))
      return 0;
 
// Step 2: ensure series is synchronized
   if(!IsSeriesReady(sy, tf))
      return 0;
 
   int h = GetMAHandle(sy, tf, period, ma_shift, method, price);
   if(h == INVALID_HANDLE)
      return 0;
 
// Step 3: ensure indicator is calculated
   if(BarsCalculated(h) <= shift)
      return 0;
 
   double buf[];
   ArraySetAsSeries(buf, true);
 
// Step 4: Copy safely
   int copied = CopyBuffer(h, 0, shift, 1, buf);
   if(copied != 1)
      return 0;
 
   return buf[0];
  }
 
//Series check
bool IsSeriesReady(string sy, ENUM_TIMEFRAMES tf)
  {
   long sync = 0;
   if(!SeriesInfoInteger(sy, tf, SERIES_SYNCHRONIZED, sync))
      return false;
 
   return (sync == 1);
  }
 
//force rate
bool ForceRates(string sy, ENUM_TIMEFRAMES tf)
  {
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
 
   int copied = CopyRates(sy, tf, 0, 10, rates);
   return (copied > 0);
  }
 
Last edited: