How to handle the MQL5 Indicators in Multi-Currency and Multi-Timeframe EA?

[Deleted]  

Hello,

I have built an multiTimeframe and MultiSymbol EA. For example, i am using Moving Average, it create handle for all the selected symbols and timeframe. 

1. Sometime Due to Moving Average full EA get stuck
2. Sometime CopyBuffer get failed and return 0 (for all indicators)
3. When i deinit and init again by changing Timeframe my EA getting stuck (Until i close and reopen metatrader again).


My Code :

input string TradingSymbols = "EURUSD,GBPUSD,USDJPY,USDCHF,USDCAD,AUDUSD,NZDUSD,GBPCAD,EURGBP,AUDNZD,XAGUSD,XAUUSD,XAUGBP,XAUAUD,XAUEUR,XAUCAD,XAUJPY,XAUCHF,BTCUSD";
input string __TimeFrame__ = "***TimeFrame Settings***";
// ===== Minute Timeframes =====
input bool PeriodM1   = true;   // PERIOD_M1
input bool PeriodM2   = true;   // PERIOD_M2
input bool PeriodM3   = true;   // PERIOD_M3
input bool PeriodM4   = true;   // PERIOD_M4
input bool PeriodM5   = true;   // PERIOD_M5
input bool PeriodM6   = true;   // PERIOD_M6
input bool PeriodM10  = true;   // PERIOD_M10
input bool PeriodM12  = true;   // PERIOD_M12
input bool PeriodM15  = true;   // PERIOD_M15
input bool PeriodM20  = true;   // PERIOD_M20
input bool PeriodM30  = true;   // PERIOD_M30

// ===== Hour Timeframes =====
input bool PeriodH1   = true;   // PERIOD_H1
input bool PeriodH2   = true;   // PERIOD_H2
input bool PeriodH3   = true;   // PERIOD_H3
input bool PeriodH4   = true;   // PERIOD_H4
input bool PeriodH6   = true;   // PERIOD_H6
input bool PeriodH8   = true;   // PERIOD_H8
input bool PeriodH12  = true;   // PERIOD_H12

// ===== Higher Timeframes =====
input bool PeriodD1   = true;   // PERIOD_D1
input bool PeriodW1   = true;   // PERIOD_W1
input bool PeriodMN1  = true;   // PERIOD_MN1

input string __MovingAverage_Indicator__ = "***Moving Average Indicator Settings***";
input ENUM_APPLIED_PRICE MovingAverage_AppliedPrice = PRICE_CLOSE;
input ENUM_MA_METHOD MovingAverage_Method = MODE_EMA;
input int MovingAverage_Period = 200;
input int MovingAverage_MAShift = 0;

int gSymbolIndex = 0;
string validSymbols[];
ENUM_TIMEFRAMES TimeFrameArray[];

//+------------------------------------------------------------------+
//|   OnInit                                                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   InitMultiSymbols();
   TimeFrameEnabled();

//Indicator Handle
   int MaxPeriod = MovingAverage_Period * 3;

   for(int s=0; s<ArraySize(validSymbols); s++)
     {
      string sym = validSymbols[s];
      SymbolSelect(sym, true);
      for(int t=0; t<ArraySize(TimeFrameArray); t++)
        {
         ENUM_TIMEFRAMES tf = TimeFrameArray[t];
         MqlRates rates[];
         if(CopyRates(sym, tf, 0, MaxPeriod, rates) <= 0)
           {
            Print("Failed to load history for ", sym, " ", EnumToString(tf));
           }
         GetMAHandle(sym, tf, MovingAverage_Period, MovingAverage_MAShift, MovingAverage_Method, MovingAverage_AppliedPrice);
        }
     }

   TesterHideIndicators(true);

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| On Deinit                                                        |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   for(int i=0;i<ArraySize(MAHandles);i++)
     {
      if(MAHandles[i].handle != INVALID_HANDLE)
        {
         if(!IndicatorRelease(MAHandles[i].handle))
            Print("Failed to release MA handle: ", MAHandles[i].handle);
         MAHandles[i].handle = INVALID_HANDLE;
        }
     }
   ArrayResize(MAHandles,0);
  }

//+------------------------------------------------------------------+
//|    OnTick                                                        |
//+------------------------------------------------------------------+
void OnTick()
  {
   for(int s=0; s<ArraySize(validSymbols); s++)
     {
      string sym = validSymbols[s];
      for(int t=0; t<ArraySize(TimeFrameArray); t++)
        {
         ENUM_TIMEFRAMES tf = TimeFrameArray[t];

         double MovingAverageValue = fMA(sym, tf, MovingAverage_Period, 0, MovingAverage_Method, MovingAverage_AppliedPrice, 1);

        }
     }
  }

//+------------------------------------------------------------------+
//|     Symbol Array                                                 |
//+------------------------------------------------------------------+
void InitMultiSymbols()
  {
   ArrayResize(validSymbols, 0);
   gSymbolIndex = 0;

   string inputPairs[];
   int pairCount = StringSplit(TradingSymbols, ',', inputPairs);
   if(pairCount <= 0)
     {
      Print("InitMultiSymbols: No TradingSymbols");
      return;
     }

   bool isTester = MQLInfoInteger(MQL_TESTER);
   int totalMW   = SymbolsTotal(true);

   for(int i = 0; i < pairCount; i++)
     {
      if(isTester)
        {
         // Tester: accept input directly
         ArrayResize(validSymbols, ArraySize(validSymbols) + 1);
         validSymbols[ArraySize(validSymbols) - 1] = inputPairs[i];
        }
      else
        {
         // Live/Demo: only if in Market Watch
         for(int m = 0; m < totalMW; m++)
           {
            if(SymbolName(m, true) == inputPairs[i])
              {
               ArrayResize(validSymbols, ArraySize(validSymbols) + 1);
               validSymbols[ArraySize(validSymbols) - 1] = inputPairs[i];
               break;
              }
           }
        }
     }
  }

//+------------------------------------------------------------------+
//|   Timeframe                                                      |
//+------------------------------------------------------------------+
void TimeFrameEnabled()
  {
   int tfCount = 0;
   ArrayResize(TimeFrameArray, 21);   // max possible TFs

   if(PeriodM1)
      TimeFrameArray[tfCount++] = PERIOD_M1;
   if(PeriodM2)
      TimeFrameArray[tfCount++] = PERIOD_M2;
   if(PeriodM3)
      TimeFrameArray[tfCount++] = PERIOD_M3;
   if(PeriodM4)
      TimeFrameArray[tfCount++] = PERIOD_M4;
   if(PeriodM5)
      TimeFrameArray[tfCount++] = PERIOD_M5;
   if(PeriodM6)
      TimeFrameArray[tfCount++] = PERIOD_M6;
   if(PeriodM10)
      TimeFrameArray[tfCount++] = PERIOD_M10;
   if(PeriodM12)
      TimeFrameArray[tfCount++] = PERIOD_M12;
   if(PeriodM15)
      TimeFrameArray[tfCount++] = PERIOD_M15;
   if(PeriodM20)
      TimeFrameArray[tfCount++] = PERIOD_M20;
   if(PeriodM30)
      TimeFrameArray[tfCount++] = PERIOD_M30;

   if(PeriodH1)
      TimeFrameArray[tfCount++] = PERIOD_H1;
   if(PeriodH2)
      TimeFrameArray[tfCount++] = PERIOD_H2;
   if(PeriodH3)
      TimeFrameArray[tfCount++] = PERIOD_H3;
   if(PeriodH4)
      TimeFrameArray[tfCount++] = PERIOD_H4;
   if(PeriodH6)
      TimeFrameArray[tfCount++] = PERIOD_H6;
   if(PeriodH8)
      TimeFrameArray[tfCount++] = PERIOD_H8;
   if(PeriodH12)
      TimeFrameArray[tfCount++] = PERIOD_H12;

   if(PeriodD1)
      TimeFrameArray[tfCount++] = PERIOD_D1;
   if(PeriodW1)
      TimeFrameArray[tfCount++] = PERIOD_W1;
   if(PeriodMN1)
      TimeFrameArray[tfCount++] = PERIOD_MN1;

   ArrayResize(TimeFrameArray, tfCount);   // shrink to real size
  }


//+------------------------------------------------------------------+
//|   Series Checl                                                   |
//+------------------------------------------------------------------+
bool IsSeriesReady(string sy, ENUM_TIMEFRAMES tf)
  {
   long sync = 0;
   if(!SeriesInfoInteger(sy, tf, SERIES_SYNCHRONIZED, sync))
      return false;

   return (sync == 1);
  }

//+------------------------------------------------------------------+
//|  Force Rates                                                     |
//+------------------------------------------------------------------+
bool ForceRates(string sy, ENUM_TIMEFRAMES tf)
  {
   int MaxPeriod = MovingAverage_Period * 3;
   
   MqlRates rates[];
   ArraySetAsSeries(rates, true);

   int copied = CopyRates(sy, tf, 0, MaxPeriod, rates);
   return (copied > 0);
  }

//+------------------------------------------------------------------+
//|      Moving Average                                              |
//+------------------------------------------------------------------+
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;
        }
     }

//Symbol Safety
   if(!SymbolSelect(sy, true))
     {
      Print(__FUNCTION__, "SymbolSelect Returned Error for symbol: ", sy, " timeframe: ", EnumToString(tf));
      return -919;
     }

//Symbol Sync Check
   if(!SymbolIsSynchronized(sy))
     {
      Print(__FUNCTION__, "Symbol Synchreonized Returned Error for symbol: ", sy, " timeframe: ", EnumToString(tf));
      return -919;
     }

//Check Bars
   if(Bars(sy, tf) < period)
     {
      Print(__FUNCTION__, "Bars (No Enough Bars) Returned Error for symbol: ", sy, " timeframe: ", EnumToString(tf));
      return -919;
     }

//force price data
   if(!ForceRates(sy, tf))
     {
      Print(__FUNCTION__, "Rate Returned Error for symbol: ", sy, " timeframe: ", EnumToString(tf));
      return -919;
     }

// Ensure series is synchronized
   if(!IsSeriesReady(sy, tf))
     {
      Print(__FUNCTION__, " Series Returned Error for symbol: ", sy, " timeframe: ", EnumToString(tf));
      return -919;
     }

   int h = iMA(sy, tf, period, ma_shift, method, price);
   if(h == INVALID_HANDLE)
     {
      Print(__FUNCTION__, " Failed to create MA for symbol: ", sy, " timeframe: ", EnumToString(tf));
      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)
  {

   int h = GetMAHandle(sy, tf, period, ma_shift, method, price);
   if(h == INVALID_HANDLE || h == -919)
     {
      Print(__FUNCTION__, "Invalid Handle Returned 0 for symbol: ", sy, " timeframe: ", EnumToString(tf));
      return 0;
     }

// Ensure indicator is calculated
   if(BarsCalculated(h) <= shift + period)
     {
      Print(__FUNCTION__, "BarsCalculated (Shift) Returned 0 for symbol: ", sy, " timeframe: ", EnumToString(tf));
      return 0;
     }

   double buf[];
   ArraySetAsSeries(buf, true);
   if(CopyBuffer(h, 0, shift, 1, buf) <= 0)
     {
      Print(__FUNCTION__, " CopyBuffer Returned 0 for symbol: ", sy, " timeframe: ", EnumToString(tf));
      return 0;
     }

   return buf[0];
  }


I have attached full handle EA for multiple indicator (In-case if you needed for reference), Kindly check the attachment.


Please Help me optimism and fix the code. 

Files:
 
Shanmugi:

Hello,

I have built an multiTimeframe and MultiSymbol EA. For example, i am using Moving Average, it create handle for all the selected symbols and timeframe. 

1. Sometime Due to Moving Average full EA get stuck
2. Sometime CopyBuffer get failed and return 0 (for all indicators)
3. When i deinit and init again by changing Timeframe my EA getting stuck (Until i close and reopen metatrader again).


My Code :


I have attached full handle EA for multiple indicator (In-case if you needed for reference), Kindly check the attachment.


Please Help me optimism and fix the code. 

Traders and coders are working for free:

  • if it is interesting for them personally, or
  • if it is interesting for many members on this forum.

Freelance section of the forum should be used in most of the cases.

Trading applications for MetaTrader 5 to order
Trading applications for MetaTrader 5 to order
  • 2026.02.14
  • www.mql5.com
The largest freelance service with MQL5 application developers
[Deleted]  
Oleksandr Medviediev #:

Traders and coders are working for free:

  • if it is interesting for them personally, or
  • if it is interesting for many members on this forum.

Thanks for remaindering me again. I know and i am not asking as Job but as request and i can wait for someone to answer. :) 


Oleksandr Medviediev #:
Freelance section of the forum should be used in most of the cases.

Yes i know and i use it a lot too. I converted my 5 EA MQL4 to MQL5 through paid freelancer only. this small work does not requires freelancer as per my requirement as i want to do it myself so i can learn more about MQL5. 

 

Hello,

Nothing is wrong with MA itself. The problem is how MT5 loads history synchronizes series and calculates indicators when you request hundreds of handles at once.

Count your EA creates

Symbols
timeframes

MAs handless

mt5 indicator engine is single thread/sym series. So, u create a queue of hundreds of calculation that's why your ma freezes whole EA

 

Try 


// Global or better — member of class
struct MAKey {
   string          symbol;
   ENUM_TIMEFRAMES tf;
   int             period;
   int             ma_shift;
   ENUM_MA_METHOD  method;
   ENUM_APPLIED_PRICE price;
};

MAKey       keys[];
int         handles[];     // parallel array

// Fast lookup helper (linear search is OK for <500 items)
int FindHandleIndex(const string sy, ENUM_TIMEFRAMES tf, int per, int mshift, ENUM_MA_METHOD meth, ENUM_APPLIED_PRICE pr) {
   for(int i = 0; i < ArraySize(keys); i++) {
      if(keys[i].symbol == sy && keys[i].tf == tf &&
         keys[i].period == per && keys[i].ma_shift == mshift &&
         keys[i].method == meth && keys[i].price == pr)
         return i;
   }
   return -1;
}

// ────────────────────────────────────────────────
int GetOrCreateMAHandle(string sy, ENUM_TIMEFRAMES tf, int period, int ma_shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE price) {

   int idx = FindHandleIndex(sy, tf, period, ma_shift, method, price);
   if(idx >= 0) return handles[idx];

   // Safety minimal checks
   if(!SymbolSelect(sy, true)) {
      Print("SymbolSelect failed: ", sy);
      return INVALID_HANDLE;
   }

   if(Bars(sy, tf) < period + 10) {
      Print("Not enough bars: ", sy, " ", EnumToString(tf));
      return INVALID_HANDLE;
   }

   int h = iMA(sy, tf, period, ma_shift, method, price);
   if(h == INVALID_HANDLE) {
      Print("iMA failed: ", sy, " ", EnumToString(tf));
      return INVALID_HANDLE;
   }

   // Store
   int n = ArraySize(keys);
   ArrayResize(keys,   n+1);
   ArrayResize(handles,n+1);

   keys[n].symbol   = sy;
   keys[n].tf       = tf;
   keys[n].period   = period;
   keys[n].ma_shift = ma_shift;
   keys[n].method   = method;
   keys[n].price    = price;
   handles[n]       = h;

   return h;
}

// ────────────────────────────────────────────────
// Recommended fMA version (shift=0 means current bar, shift=1 previous completed bar)
double fMA(string sy, ENUM_TIMEFRAMES tf, int period, int ma_shift,
           ENUM_MA_METHOD method, ENUM_APPLIED_PRICE price, int buffer_shift = 1) {

   int h = GetOrCreateMAHandle(sy, tf, period, ma_shift, method, price);
   if(h == INVALID_HANDLE) return 0;

   int calculated = BarsCalculated(h);
   if(calculated <= buffer_shift) {
      // Not ready yet (common on first ticks after history load)
      return 0;
   }

   double buf[1];
   if(CopyBuffer(h, 0, buffer_shift, 1, buf) != 1) {
      //Print("CopyBuffer failed ", GetLastError());
      return 0;
   }

   return buf[0];
}