Array out of range error while backtesting a candle pattern

 
Hi everyone,

I am pretty new to the MQL5 platform. I built a custom indicator to identify Hammer and shooting star patterns on the chart. The indicator buffer at a particular index is filled with 1.0 after a hammer appears and -1.0 after shooting star appears. Everything seemed to be working fine when I dropped the indicator on the chart. The next step was to create an EA which loads this indicator and places buy or sell order based on the value in the indicator buffer, i.e 1.0 for buy order and -1.0 for sell order. I'm facing an issue while backtesting that EA. 


This is the error I face:

2019.09.06 09:25:01.918 Core 1 2019.06.01 00:00:00   array out of range in 'Hammer.mq5' (92,42)


Also any feedback on the code would be appreciated since I'm new to this and want to learn how to code things in an efficient way. 


The following is the code for the Hammer pattern:

//+------------------------------------------------------------------+
//|                                                     Hammer.mq5 |
//|                                                     BullsEye
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "BullsEye"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots 1
#property indicator_type1 DRAW_HISTOGRAM
#property indicator_color1 clrSilver
#property indicator_width1 2
//---Buffers
double PatternBuffer[];
int patternUpcounter;
int patternDowncounter;

double openBuffer[];
double closeBuffer[];
double lowBuffer[];
double highBuffer[];

input double hammer_upShadow = 0.1;
input double hammer_downShadow = 2;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   ArraySetAsSeries(PatternBuffer,true);
   SetIndexBuffer(0,PatternBuffer,INDICATOR_DATA);

   ArraySetAsSeries(openBuffer,true);
   ArraySetAsSeries(highBuffer,true);
   ArraySetAsSeries(lowBuffer,true);
   ArraySetAsSeries(closeBuffer,true);
   
   
   patternUpcounter = patternDowncounter =0;
   
   
//---
   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[])
  {
//---
   static datetime lastfound;
   ArraySetAsSeries(open,true);
   ArraySetAsSeries(high,true);
   ArraySetAsSeries(low,true);
   ArraySetAsSeries(close,true);
   ArraySetAsSeries(time,true);
   
   int limit;
   if(prev_calculated ==0)
      limit = rates_total;
   else
      limit = rates_total - prev_calculated;
   
   for(int i=1 ; i < limit; i++)
   {
      {
         ArrayResize(highBuffer,3);
         ArrayResize(lowBuffer,3);
         ArrayResize(closeBuffer,3);
         ArrayResize(openBuffer,3);
         
         CopyHigh(_Symbol,_Period,i,3,highBuffer);
         CopyLow(_Symbol,_Period,i,3,lowBuffer);
         CopyOpen(_Symbol,_Period,i,3,openBuffer);
         CopyClose(_Symbol,_Period,i,3,closeBuffer);
         
         
         double body = MathAbs(closeBuffer[1]-openBuffer[1]);
         
         bool up_condition1 = (openBuffer[2]>closeBuffer[2]) && (openBuffer[1]<closeBuffer[1]) && (openBuffer[0]<closeBuffer[0]);
         bool up_condition2 = (openBuffer[1]<closeBuffer[2]);
         double up_shadow_hammer = MathAbs(highBuffer[1]-closeBuffer[1]);
         double low_shadow_hammer = MathAbs(openBuffer[1]-lowBuffer[1]);
         int min_l_idx = ArrayMinimum(lowBuffer,0,WHOLE_ARRAY);
         bool body_condition_hammer = (low_shadow_hammer>= hammer_downShadow*body) && (up_shadow_hammer <= hammer_upShadow*body);

         
         bool down_condition1 = (openBuffer[2]<closeBuffer[2]) && (openBuffer[1]>closeBuffer[1]) && (openBuffer[0]>closeBuffer[0]);
         bool down_condition2 = (openBuffer[1]>closeBuffer[2]);
         double up_shadow_hangingman = MathAbs(highBuffer[1]-openBuffer[1]);
         double low_shadow_hangingman= MathAbs(closeBuffer[1]-lowBuffer[1]);
         int max_h_idx = ArrayMaximum(highBuffer,0,WHOLE_ARRAY);
         bool body_condition_hman = (low_shadow_hangingman >= hammer_downShadow*body) && (up_shadow_hangingman <= hammer_upShadow*body);
         
         if(up_condition1 && up_condition2 && body_condition_hammer && min_l_idx==1) 
         {
            PatternBuffer[i-1] = 1.0;
            patternUpcounter++;
            if(lastfound < time[i-1])
               lastfound = time[i-1];
         }
         else if(down_condition1 && down_condition2 && body_condition_hman && max_h_idx==1 )
         {
            PatternBuffer[i-1] = -1.0;
            patternDowncounter++;
            if(lastfound < time[i-1])
               lastfound = time[i-1];
         }
         else
         {
            PatternBuffer[i-1] = 0.0;
         }
         ArrayFree(highBuffer);
         ArrayFree(lowBuffer);
         ArrayFree(openBuffer);
         ArrayFree(closeBuffer);
      }
      Comment("Up: "+IntegerToString(patternUpcounter)+" Down: "+IntegerToString(patternDowncounter)+"\n"+"Last found: "+TimeToString(lastfound));
   }
//--- return value of prev_calculated for next call
   return(rates_total-1);
  }
//+------------------------------------------------------------------+

The following is the code for EA which loads this indicator:

//+------------------------------------------------------------------+
//|                                                  patterntest.mq5 |
//|                                                        BullsEye |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "BullsEye"
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <Trade\SymbolInfo.mqh>
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\OrderInfo.mqh>
#include <Trade\TerminalInfo.mqh>
#include <StdLibErr.mqh>
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
//Objects init
CSymbolInfo symbol_info;
CTrade trade;
CPositionInfo position;
COrderInfo order_info;
CTerminalInfo terminal;

int patternhandle =0;
double patternbuffer[1];
int OnInit()
  {
//---
   patternhandle = iCustom(_Symbol,_Period,"Hammer");
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

   symbol_info.RefreshRates();
   CopyBuffer(patternhandle,0,0,1,patternbuffer);
   
   if(patternbuffer[0]==1.0)
      Print("Buy");
      
   else if(patternbuffer[0] == -1.0)
      Print("Sell");
   
  }
//+------------------------------------------------------------------+
 
  1.          CopyHigh(_Symbol,_Period,i,3,highBuffer);
             CopyLow(_Symbol,_Period,i,3,lowBuffer);
             CopyOpen(_Symbol,_Period,i,3,openBuffer);
             CopyClose(_Symbol,_Period,i,3,closeBuffer);
    You ask for three items.

  2. bool up_condition1 = (openBuffer[2]>closeBuffer[2]) && …
    You read three items.

  3.    if(prev_calculated ==0)
          limit = rates_total;
       else
          limit = rates_total - prev_calculated;
       
       for(int i=1 ; i < limit; i++)
    But, the first run prev_calculated is zero, so limit is Bars, and when i=Bars-1, there aren't three items to read. Your lookback is two.
              How to do your lookbacks correctly.
 
William Roeder:
  1. You ask for three items.

  2. You read three items.

  3. But, the first run prev_calculated is zero, so limit is Bars, and when i=Bars-1, there aren't three items to read. Your lookback is two.
              How to do your lookbacks correctly.
Thanks William, I resolved the error. Added a int lookback and made the following changes to the code 
if(prev_calculated ==0)
      limit = rates_total-lookback+1;
   else
      limit = rates_total - prev_calculated;
   
   for(int i=1 ; i < limit; i++)
It is working fine now.
 
Any other suggestions on how to make this code more efficient?
 
Good day MQL5 team I believe has the CCanndlePattern Class some where in the code base