Arrows in MT5 custom indicator not appearing with M1 candles — need help

 

I coded a custom indicator that plots arrows on M1 candles when all higher timeframes (M5, M15, M30, H1, H4, D1) agree with the candle direction.
The arrows  appear shifted or misplaced or don't appear at all. I think the problem is with the loop. I am adding the for loop in OnCalculate function below

   

   int start = MathMax(1, rates_total - InpBarsToCheck); // avoid bar 0 (not closed)

   for(int i = rates_total-2; i >= start; i--) // exclude current forming bar

   {  

      BuyArrowBuffer[i]  = EMPTY_VALUE;

      SellArrowBuffer[i] = EMPTY_VALUE;

      int shift = iBarShift(_Symbol, PERIOD_M1, time[i], false);

      if(shift < 0) continue;

      

      if(BullishAgreement(shift)){

         BuyArrowBuffer[i] = high[i] + (_Point * InpArrowShift);

         Print(time[i]," ",high[i]," ",BuyArrowBuffer[i]);

       }

      if(BearishAgreement(shift)){

         SellArrowBuffer[i] = low[i] - (_Point * InpArrowShift);

         Print(time[i]," ",low[i]," ",SellArrowBuffer[i]);

      }

   }

   return(rates_total);

}

Can someone explain the best way to correctly map M1 candles to higher timeframes so my arrows plot exactly on the right bar?
Открой новые возможности в MetaTrader 5 с сообществом и сервисами MQL5
Открой новые возможности в MetaTrader 5 с сообществом и сервисами MQL5
  • 2025.09.04
  • www.mql5.com
MQL5: язык торговых стратегий для MetaTrader 5, позволяет писать собственные торговые роботы, технические индикаторы, скрипты и библиотеки функций
 

Hi vaishali2304,

When you plot on M1 but read data from higher TFs, the usual cause of “shifted/misplaced” arrows is bar-index mapping and the processing loop.

Key points

  1. Map the M1 bar time to each higher-TF bar
    Use the M1 bar time time[i] and find the containing bar on each HTF with iBarShift(..., /*exact=*/false) . Then read OHLC from those HTFs at the returned index, but always write to your M1 buffer at i .

  2. Process forward, avoid bar 0
    In MQL5 indicators you should iterate forward from start to rates_total-1 . Skip i = rates_total-1 (the forming bar).

  3. Copy HTF series once, set as_series
    Copy OHLC arrays for each HTF up front and set them as series so indexing matches.

Template you can drop in

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[])
{
   // --- prepare HTF data
   MqlRates m5[], m15[], m30[], h1[], h4[], d1[];
   int need = rates_total + 100; // a little extra headroom

   CopyRates(_Symbol, PERIOD_M5,  0, need, m5);
   CopyRates(_Symbol, PERIOD_M15, 0, need, m15);
   CopyRates(_Symbol, PERIOD_M30, 0, need, m30);
   CopyRates(_Symbol, PERIOD_H1,  0, need, h1);
   CopyRates(_Symbol, PERIOD_H4,  0, need, h4);
   CopyRates(_Symbol, PERIOD_D1,  0, need, d1);

   ArraySetAsSeries(m5,  true);  ArraySetAsSeries(m15, true);
   ArraySetAsSeries(m30, true);  ArraySetAsSeries(h1,  true);
   ArraySetAsSeries(h4,  true);  ArraySetAsSeries(d1,  true);

   // --- calc window
   int start = (prev_calculated > 0 ? prev_calculated-1 : 1); // skip bar 0
   for(int i = start; i < rates_total-1; i++)                  // process forward, avoid forming bar
   {
      BuyArrowBuffer[i]  = EMPTY_VALUE;
      SellArrowBuffer[i] = EMPTY_VALUE;

      datetime t = time[i];

      // map M1 bar 'i' to bar indexes on each HTF
      int i5  = iBarShift(_Symbol, PERIOD_M5,  t, false);
      int i15 = iBarShift(_Symbol, PERIOD_M15, t, false);
      int i30 = iBarShift(_Symbol, PERIOD_M30, t, false);
      int iH1 = iBarShift(_Symbol, PERIOD_H1,  t, false);
      int iH4 = iBarShift(_Symbol, PERIOD_H4,  t, false);
      int iD1 = iBarShift(_Symbol, PERIOD_D1,  t, false);
      if(i5<0 || i15<0 || i30<0 || iH1<0 || iH4<0 || iD1<0) continue;

      bool bull =
         (m5[i5].close  > m5[i5].open)   &&
         (m15[i15].close> m15[i15].open) &&
         (m30[i30].close> m30[i30].open) &&
         (h1[iH1].close > h1[iH1].open)  &&
         (h4[iH4].close > h4[iH4].open)  &&
         (d1[iD1].close > d1[iD1].open);

      bool bear =
         (m5[i5].close  < m5[i5].open)   &&
         (m15[i15].close< m15[i15].open) &&
         (m30[i30].close< m30[i30].open) &&
         (h1[iH1].close < h1[iH1].open)  &&
         (h4[iH4].close < h4[iH4].open)  &&
         (d1[iD1].close < d1[iD1].open);

      // IMPORTANT: write to M1 buffer at index 'i'
      if(bull) BuyArrowBuffer[i]  = low[i]  - _Point * InpArrowShift;
      if(bear) SellArrowBuffer[i] = high[i] + _Point * InpArrowShift;
   }

   return(rates_total);
}

Common pitfalls to avoid

  • Using iBarShift(..., true) (exact match) — M1 times rarely equal an HTF bar open; use false .

  • Writing to BuyArrowBuffer[shift] instead of [i] .

  • Iterating backward with as-series confusion while mixing copied arrays that aren’t ArraySetAsSeries(true) .

  • Using bar 0 (still forming) for decisions/plotting.

If you adopt the mapping above (M1 time[i] → HTF index via iBarShift(..., false) ), your arrows will land exactly on the intended M1 bars. Hope this helps!

[Deleted]  
Your topic has been moved to the section: Technical Indicators
Please consider which section is most appropriate — https://www.mql5.com/en/forum/172166/page6#comment_49114893
 
Thank you for the help but while storing the candles, only 2400 candles can be stored, after 2400 candles code gives error. Is this limit or some other problem?
Matei-Alexandru Mihai #:

Hi vaishali2304,

When you plot on M1 but read data from higher TFs, the usual cause of “shifted/misplaced” arrows is bar-index mapping and the processing loop.

Key points

  1. Map the M1 bar time to each higher-TF bar
    Use the M1 bar time time[i] and find the containing bar on each HTF with iBarShift(..., /*exact=*/false) . Then read OHLC from those HTFs at the returned index, but always write to your M1 buffer at i .

  2. Process forward, avoid bar 0
    In MQL5 indicators you should iterate forward from start to rates_total-1 . Skip i = rates_total-1 (the forming bar).

  3. Copy HTF series once, set as_series
    Copy OHLC arrays for each HTF up front and set them as series so indexing matches.

Template you can drop in

Common pitfalls to avoid

  • Using iBarShift(..., true) (exact match) — M1 times rarely equal an HTF bar open; use false .

  • Writing to BuyArrowBuffer[shift] instead of [i] .

  • Iterating backward with as-series confusion while mixing copied arrays that aren’t ArraySetAsSeries(true) .

  • Using bar 0 (still forming) for decisions/plotting.

If you adopt the mapping above (M1 time[i] → HTF index via iBarShift(..., false) ), your arrows will land exactly on the intended M1 bars. Hope this helps!