MQ5 Indicator - Array out of range error

 

Good day, 

I am trying to make an indicator that shows up and down arrows when an engulfing pattern is formed. The bearish engulfing pattern is confirmed if either of the 2 candles before the engulfed candle are bullish and similar for the bullish engulfing pattern is confirmed if the either of the 2 candles before the engulfed candle are bearish, so the indicator requires to look back at least to the 5th candle left of the recently closed candle. 

I have tried multiple attempts but with no success, I am failing to get the logic that makes the indicator find all patterns in history and continue to show new arrows when conditions for new patterns are met.

1. First problem is that when I get the indicator to show arrows for past patterns in history, the indicator does not show new arrows and gives an "array out of range" error. Here is the full code below: 

//+------------------------------------------------------------------+
//| 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[])
  {
   //--- Return value of prev_calculated for next call
   int begin;
   
      if(prev_calculated == 0) // i.e The indicator is running for the first time
     {
       begin = rates_total - 8; // leave at least 8 candles to the left to avoid array out of range
     }
     
    else
      {
        begin = rates_total - prev_calculated;
      }   

   for(int i = begin; i < rates_total - 1; 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);
  }
//+------------------------------------------------------------------+


2. When I try to make the indicator show past patterns, it successfully shows the past patterns but fails to show new ones, this time with no error. Here is the complete code below:

//+------------------------------------------------------------------+
//| 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[])
  {
   //--- Return value of prev_calculated for next call
   int total;
   
      if(prev_calculated == 0) // i.e The indicator is running for the first time
     {
       total = rates_total - 8; // leave at least 8 candles to the left to avoid array out of range
     }
     
    else
      {
        total = rates_total - prev_calculated;
      }   

   for(int i = 1; i < total+1; 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);
  }
//+------------------------------------------------------------------+


Your assistance to get the indicator to show past patterns and new ones is highly appreciated.

 
Then please identify in your code which line or lines are having the array out of range errors.
 

why do coders and engineers love attempting to redesign the wheel?

Just do a 1 minute search of codebase. There are several indicators already made and shown to work.

 
Fernando Carreiro #:
Then please identify in your code which line or lines are having the array out of range errors.

Thank you for your interest to assist. The array out of range error is at line 77 Array out of range erropr from backtester


The code at line 77 is where the inside of the for loop begins: 

      // 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());
           }
        }

Code line 77

 
Revo Trades #:

why do coders and engineers love attempting to redesign the wheel?

Just do a 1 minute search of codebase. There are several indicators already made and shown to work.

That is usually the first step I do, to try and find something similar and modify it to match what I need it to do. But this time around I didn't find anything useful, and I got to where I am in the code after watching some good YouTube videos. 

For anyone interested (I am in no way affiliated to the owner of the video), see YouTube link below:

https://youtu.be/8gRtm5xH-gQ?si=0L0eZZl4H0uuMOyv

IndicatorCounted() and Prev_Calculated Explained
IndicatorCounted() and Prev_Calculated Explained
  • 2019.10.30
  • www.youtube.com
Learn Mql4 at https://learnmql4.comHeiken Ashi Indicator Coursehttps://learnmql4.teachable.com/p/code-the-heiken-ashi-trigger-indicatorTierOne Trading 14 day...
 
ITM7 #: Thank you for your interest to assist. The array out of range error is at line 77. The code at line 77 is where the inside of the for loop begins: 

Your screenshot shows code that is different to what you have shown in your first post.

So, here is a logic query ...

for( int i = begin; i < rates_total; i++)

What if the variable "begin" is zero (0)?

close[i-1]

What will the value of "i - 1" be?

It will be "-1". Is that a valid array index?

No, it is not. It will cause an "array out of range" error.

What if the variable "begin" is one (1)?

open[i-3]

What will the value of "i - 3" be?

It will be "-2". Is that a valid array index?

No, it is not. It will cause an "array out of range" error.

And so on ....

Do you understand the problem now?

 
Fernando Carreiro #:

Your screenshot shows code that is different to what you have shown in your first post.

So, here is a logic query ...

What if the variable "begin" is zero (0)?

What will the value of "i - 1" be?

It will be "-1". Is that a valid array index?

No, it is not. It will cause an "array out of range" error.

What if the variable "begin" is two (2)?

What will the value of "i - 3" be?

It will be "-1". Is that a valid array index?

No, it is not. It will cause an "array out of range" error.

And so on ....

Do you understand the problem now?

Yes, I understand the problem in the logic by how you explained it. But I don't understand why it runs successfully for the past candles up to some point and then only show array out of range.

Arrows before array out of range

I am sorry about the code I inserted, it is from my second alternative where the indicator does not show array out of range but instead only draws arrows once when dropped on the chart and does not draw new arrows as new price keeps coming in. 

For convenience, the complete code is below. The only difference is the logic that attempts to look for past patterns and continue to draw new ones.

//+------------------------------------------------------------------+
//| 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[])
  {
   //--- Return value of prev_calculated for next call
   int total;
   
      if(prev_calculated == 0) // i.e The indicator is running for the first time
     {
       total = rates_total - 8; // leave at least 8 candles to the left to avoid array out of range
     }
     
    else
      {
        total = rates_total - prev_calculated;
      }   

   for(int i = 1; i < total+1; 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);
  }
//+------------------------------------------------------------------+

 
ITM7 #:

That is usually the first step I do, to try and find something similar and modify it to match what I need it to do. But this time around I didn't find anything useful, and I got to where I am in the code after watching some good YouTube videos. 

For anyone interested (I am in no way affiliated to the owner of the video), see YouTube link below:


Rodger that.

 
ITM7 #:

Yes, I understand the problem in the logic by how you explained it. But I don't understand why it runs successfully for the past candles up to some point and then only show array out of range.

I am sorry about the code I inserted, it is from my second alternative where the indicator does not show array out of range but instead only draws arrows once when dropped on the chart and does not draw new arrows as new price keeps coming in. 

For convenience, the complete code is below. The only difference is the logic that attempts to look for past patterns and continue to draw new ones.


Your problem is here:

 for(int i = 1; i < total+1; i++)

Why total+1???
EDIT:
Search the forum for "how to do lookup correctly"
 
Dominik Egert #:
Your problem is here:


Why total+1???
EDIT:
Search the forum for "how to do lookup correctly"

For my level of coding, the results from the search will require quite a long time to understand

How to do a lookup correctly

 
Dominik Egert #:
Your problem is here:


Why total+1???
EDIT:
Search the forum for "how to do lookup correctly"


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.