MQ5 Indicator - Array out of range error - page 2

 
ITM7 #:

Why I have the "total+1":

Step 1, we drop the indicator on the chart, at this point "prev_calculated" is zero and total is most likely greater than 100 (assuming rates total returned so). So the indicator starts checking the candles from candle 1 (i = 1), and continues to do so until i is greater than "total + 1". At this stage, "total + 1" does not cause any harm of running out of range because total is set to "rates_total - 8". 

Step 2, a new candle has just been opened (candle zero), and "prev_calculated" is not zero, i.e. it is 1 candle less than rates_total, therefore, total = 1.

The for loop starts again from i=1, but it can only proceed / go through if i < total, but since total is == 1, I added "total+1" so that the for loop can go through. I added the "total+1" after considering it has no effects to step 1 as described above.  

I just realised a mistake from my side (refer to intention of the indicator / code in the introduction). I intended the for loop to count (or look back) from candle 1 all the way to the back (rates_total -8), i.e. 1,2,3,4...,(n-8). At this point stopping at ((n-8)+1) is not a concern (total+1). If i is the reference point and i starts at 1, then i+1 = 2, but i-1 = 0, and candle zero is incomplete. The if conditions in the for loop are currently looking backwards with reference to i, i.e. i-1, i-2. I would expect an array out of range at this stage but I didn't get any. Thanks for the clue, I will debug and update progress if any. Otherwise if my explanation above is somewhat wrong, your correction(s) are welcome.

Indicators: Need help understanding lookback set-up
Indicators: Need help understanding lookback set-up
  • 2021.08.26
  • www.mql5.com
General: Indicators: Need help understanding lookback set-up
 

Thank you, I will do so.

 

I finally managed to get the look back logic correct, I had a fundamental misunderstanding of indexing arrays set to series and those that are not. 

Below, a link I found very useful in explaining rates_total and prev_caluclated. 

https://www.mql5.com/en/forum/6301#comment_163327


And below is the code in case someone might find it useful in the future, not the accuracy of the arrows but the logic. If not, admin or moderator can close / delete this thread. Thank you all for your assistance.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021"
#property version   "1.0"
#property strict
#property indicator_chart_window

#property indicator_buffers 2
#property indicator_plots   2

#property indicator_color1  Green
#property indicator_type1   DRAW_ARROW
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

#property indicator_color2  Red
#property indicator_type2   DRAW_ARROW
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- Indicator buffers
double bullishArrowBuffer[];
double bearishArrowBuffer[];

//--- Input parameters
input bool   ShowAlerts = true;            // Display Alerts
input bool   EnablePushNotifications = false;  // Enable Push Notifications

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Creating buffers for arrows
   SetIndexBuffer(0, bullishArrowBuffer, INDICATOR_DATA); 
   PlotIndexSetInteger(0,PLOT_ARROW,233); // Wingdings char code for upward arrow

   SetIndexBuffer(1, bearishArrowBuffer, INDICATOR_DATA);  
   PlotIndexSetInteger(1,PLOT_ARROW,234); // Wingdings char code for downward arrow

   //--- Name of the indicator
   //IndicatorShortName("Engulfing Pattern Indicator");
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
  
//   ArraySetAsSeries(time,true);
//   ArraySetAsSeries(high,true);
//   ArraySetAsSeries(low,true);
//   ArraySetAsSeries(close,true);
//   ArraySetAsSeries(open,true);
  
   //--- Return value of prev_calculated for next call
   int total, limit;
  
      if (prev_calculated == 0) // i.e The indicator is running for the first time
     {
       total = rates_total - 1; // leave at least 1 candle to the right to avoid array out of range
       limit = 20; // This is the limit of candles / bars to count backwards, i.e. the lookback and zero is
                   // the last candle / bar on the left of the chart.
     }
     
      else if (rates_total - prev_calculated <= 0) // i.e The indicator is not running for the first time but is on same candle
                                                   // total is zero and the for loop will not run
     {
       total = rates_total - prev_calculated; // total is/has zero
       limit = 0; 
     }     

      else  // i.e There is a new candle on the chart and we just want to count / loop 
            // once, so we create the condition to force the for loop to run only once.
            // rates_total - prev_calculated == 1
     {
        total = rates_total-2;
        limit = prev_calculated-2;
        
        // why minus 2: rates total returns the magnitude of the rates array, and numbering starts from zero. Assuming the 
        // rates total array has 100 rates, the numbering index will be from 0 to 99. If we use rates_total - 1, we get 
        // 100 - 1 = 99. But 99 is the last candle (current active candle) and we want to see if the candle that closed 
        // immediately formed some pattern that we are interested in, so the index of that candle is 98, and therefore we 
        // have to subtarct 2 from rates_total. We also subtract 2 from previously calculated OR subtract 3 from rates_total 
        // to use 97 as a control for existing the loop, because we just want to run 1 calculation for the new candle since 
        // other candles in history have already been calculated. 
     }  

   for(int i = total; i > limit; i--)
     
     {// Checking for bullish engulfing pattern
      if(close[i] > open[i] && open[i-1] > close[i-1] && // Current candle is bullish and previous is bearish
         close[i] > open[i-1] && open[i] < close[i-1])   // Current candle engulfs the previous candle
        {
         // Check if one of the two candles before the bearish candle is also bearish
         if (open[i-2] > close[i-2] || open[i-3] > close[i-3])
           {
            bullishArrowBuffer[i] = low[i] - (5 * Point()); // Position the arrow below the low of the bullish candle

            // Alert and Notification
            if(ShowAlerts)
              Alert("Bullish Engulfing Pattern at ", Symbol(), " ", TimeToString(time[i], TIME_DATE|TIME_MINUTES));
            if(EnablePushNotifications)
              SendNotification("Bullish Engulfing Pattern at " + Symbol());
           }
        }

      // Checking for bearish engulfing pattern
      if(close[i] < open[i] && open[i-1] < close[i-1] && // Current candle is bearish and previous is bullish
         close[i] < open[i-1] && open[i] > close[i-1])   // Current candle engulfs the previous candle
        {
         // Check if one of the two candles before the bullish candle is also bullish
         if (open[i-2] < close[i-2] || open[i-3] < close[i-3])
           {
            bearishArrowBuffer[i] = high[i] + (5 * Point()); // Position the arrow above the high of the bearish candle

            // Alert and Notification
            if(ShowAlerts)
              Alert("Bearish Engulfing Pattern at ", Symbol(), " ", TimeToString(time[i], TIME_DATE|TIME_MINUTES));
            if(EnablePushNotifications)
              SendNotification("Bearish Engulfing Pattern at " + Symbol());
           }
        }
     }
   //--- Return value for the next call
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   //--- Clearing the buffers
   ArrayFree(bullishArrowBuffer);
   ArrayFree(bearishArrowBuffer);
  }
//+------------------------------------------------------------------+
Tough time understanding the loop structure and price array's.
Tough time understanding the loop structure and price array's.
  • 2012.03.01
  • www.mql5.com
I'm trying to learn the language and I understand that an important part of an indicator is being able to cycle through price data but I'm having a...