Error in strategy tester

 

So I run this code in strategy tester

 

//+------------------------------------------------------------------+
//|                                        Bobs Magic Boxes v4.2.mq4 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
//--- input parameters
extern string  Box_Settings     ="Inputs";
extern int     Min_Range        =      50;
extern int     Max_Range        =     210;
extern int     Box_Minimum      =      70;
extern int     Box_Maximum      =     180;
extern string  Box_Type         ="0010.1011.0010";
extern string  Trade_Management ="Inputs";
extern bool    Trade_Long       =    true;
extern double  Risk             =     1.0;
extern int     Magic_No         =  100001;
extern int     Slippage         =       0;
extern string  Trading_Sessions =   "GMT";
extern int     Asian_Open       =       0;
extern int     Asian_Close      =      24;
extern int     Europe_Open      =       0;
extern int     Europe_Close     =       0;
extern int     London_Open1     =       0;
extern int     London_Close1    =       0;
extern int     London_Open2     =       0;
extern int     London_Close2    =       0;
extern int     London_Open3     =       0;
extern int     London_Close3    =       0;
extern int     NewYork_Open1    =       0;
extern int     NewYork_Close1   =       0;
extern int     NewYork_Open2    =       0;
extern int     NewYork_Close2   =       0;
extern string  Tradeing_Days    =   "   ";
extern bool    Sunday           =    true;
extern bool    Monday           =    true;
extern bool    Tuesday          =    true;
extern bool    Wednesday        =    true;
extern bool    Thursday         =    true;
extern bool    Friday           =    true;

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
datetime currentbar;

double   min_range,max_range,box_min,box_max;
datetime spd4,spd5,spd6,spd7,spd8,spd9,spd10,spd11,spd12,spd13,spd14,spd15,spd16,spd17,spd18,spd19,spd20,spd21;
string   binaryh1,binaryh2,binaryh3,binaryh4,binaryh5,binaryl1,binaryl2,binaryl3,binaryl4,binaryl5;
string   CurrentBoxPattern;
double   box1high,box1low,box2high,box2low,box3high,box3low,box1range,box2range,box3range;
double   AccBal,AccEqu,TickValue;

bool     NewTradeBoxFormed,continuescan;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   currentbar=0;

   min_range = Min_Range*Point;
   max_range = Max_Range*Point;
   box_min   = Box_Minimum*Point;
   box_max   = Box_Maximum*Point;

   spd4  = Time[10];
   spd5  = Time[12];
   spd6  = Time[14];
   spd7  = Time[16];
   spd8  = Time[18];
   spd9  = Time[20];
   spd10 = Time[22];
   spd11 = Time[24];
   spd12 = Time[26];
   spd13 = Time[28];
   spd14 = Time[30];
   spd15 = Time[32];
   spd16 = Time[34];
   spd17 = Time[36];
   spd18 = Time[38];
   spd19 = Time[40];
   spd20 = Time[42];
   spd21 = Time[44];

   box1high = 0.0;
   box1low  = 0.0;
   box2high = 0.0;
   box2low  = 0.0;
   box3high = 0.0;
   box3low  = 0.0;

   NewTradeBoxFormed = false;
   continuescan      = false;
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---Set variables
   datetime time_current = TimeGMT();
   datetime thisbar      = Time[0];
   int      time_hour    = TimeHour(time_current);

   AccBal    = AccountInfoDouble(ACCOUNT_BALANCE);
   AccEqu    = AccountInfoDouble(ACCOUNT_EQUITY);
   TickValue = MarketInfo(Symbol(),MODE_TICKVALUE);

//--- Activate trading hours
   bool tradetrue=((time_hour>=Asian_Open && time_hour<Asian_Close) || 
                   (time_hour>=Europe_Open && time_hour<Europe_Close)||
                   (time_hour>=London_Open1 && time_hour<London_Close1)||
                   (time_hour>=London_Open2 && time_hour<London_Close2)||
                   (time_hour>=London_Open3 && time_hour<London_Close3)||
                   (time_hour>=NewYork_Open1 && time_hour<NewYork_Close1)||
                   (time_hour>=NewYork_Open2 && time_hour<NewYork_Close2));

//--- Activate trading days
   bool tradeday=((TimeDayOfWeek(time_current)==0 && Sunday==true) || 
                  (TimeDayOfWeek(time_current)==1 && Monday==true)||
                  (TimeDayOfWeek(time_current)==2 && Tuesday==true)||
                  (TimeDayOfWeek(time_current)==3 && Wednesday==true)||
                  (TimeDayOfWeek(time_current)==4 && Thursday==true)||
                  (TimeDayOfWeek(time_current)==5 && Friday==true));
                  
//--- Check for active trades
   bool InTheMarket = OrdersTotal()>0;

//+------------------------------------------------------------------+
//|   Trade Logic                                                    |
//+------------------------------------------------------------------+
//---Function 
   if(currentbar!=thisbar)//--- New bar detector
     {
      currentbar=thisbar;
      continuescan=true;
      ScanForBoxPatterns();
     }

//---Function
   if(InTheMarket || !tradetrue || !tradeday) NewTradeBoxFormed=false;

//---Function
   if(tradeday && tradetrue && NewTradeBoxFormed) LookForActiveTradeBox();
  }

//+----------------------------------------+
//  Scan for Box Patterns                  |
//+----------------------------------------+
void ScanForBoxPatterns()
//+----------------------------------------+
  {
   while(continuescan)
     {
      RunRangeScan(iBarShift(NULL,0,spd4),9,5,4,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd5),11,6,5,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd6),13,7,6,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd7),15,8,7,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd8),17,9,8,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd9),19,10,9,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd10),21,11,10,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd11),23,12,11,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd12),25,13,12,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd13),27,14,13,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd14),29,15,14,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd15),31,16,15,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd16),33,17,16,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd17),35,18,17,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd18),37,19,18,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd19),39,20,19,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd20),41,21,20,min_range,max_range);
      if(!continuescan) break;
      RunRangeScan(iBarShift(NULL,0,spd21),43,22,21,min_range,max_range);

      continuescan=false;
     }
  }
//+----------------------------------------+
//  Run Range scan                         |
//+----------------------------------------+
void RunRangeScan(int index,int boxspread,int run_leg,int boxNo,double Min,double Max)
//+----------------------------------------+
  {
   if(index>boxspread)
     {
      for(int i=index;i>0;i--)
        {
         bool valid=true;
         int bc=0;

         int    BoxHS  = iHighest(NULL,0,MODE_HIGH,run_leg,i);
         int    BoxLS  = iLowest (NULL,0,MODE_LOW,run_leg,i);
         int    LeftT  = MathMax(BoxHS,BoxLS);
         int    RightT = MathMin(BoxHS,BoxLS);
         int    hs1    = BoxHS+1;
         int    hs2    = BoxHS+2;
         int    hs3    = BoxHS+3;
         int    ls1    = BoxLS+1;
         int    ls2    = BoxLS+2;
         int    ls3    = BoxLS+3;

         double BoxH   = High[BoxHS];
         double BoxH1  =   High[hs1];
         double BoxH2  =   High[hs2];
         double BoxH3  =   High[hs3];
         double BoxL   =  Low[BoxLS];
         double BoxL1  =    Low[ls1];
         double BoxL2  =    Low[ls2];
         double BoxL3  =    Low[ls3];
         double range  =   BoxH-BoxL;

         if((LeftT==RightT) || 
            (range<Min) || 
            (range>Max) || 
            (LeftT==BoxHS && BoxH1>=BoxH)||
            (LeftT==BoxHS && BoxH2>=BoxH)||
            (LeftT==BoxHS && BoxH3>=BoxH)||
            (LeftT==BoxLS && BoxL1<=BoxL)||
            (LeftT==BoxLS && BoxL2<=BoxL)||
            (LeftT==BoxLS && BoxL3<=BoxL))
           {
            switch(boxNo)
              {
               case 4:   spd4=Time[i];break;
               case 5:   spd5=Time[i];break;
               case 6:   spd6=Time[i];break;
               case 7:   spd7=Time[i];break;
               case 8:   spd8=Time[i];break;
               case 9:   spd9=Time[i];break;
               case 10: spd10=Time[i];break;
               case 11: spd11=Time[i];break;
               case 12: spd12=Time[i];break;
               case 13: spd13=Time[i];break;
               case 14: spd14=Time[i];break;
               case 15: spd15=Time[i];break;
               case 16: spd16=Time[i];break;
               case 17: spd17=Time[i];break;
               case 18: spd18=Time[i];break;
               case 19: spd19=Time[i];break;
               case 20: spd20=Time[i];break;
               case 21: spd21=Time[i];break;
              }
            continue;
           }

         for(int x=i-1;x>0;x--)
           {
            if((High[x]>BoxH) || (Low[x]<BoxL))
              {
               valid=false;
               break;
              }
            bc++;
           }

         if(valid && bc>=run_leg)
           {
            if(BoxH>=box1high || BoxL<=box1low)
              {
               if(box1high==BoxH || box1low==BoxL)
                 {
                  box1high = BoxH;
                  box1low  = BoxL;
                  box1range= range;
                 }
               else
                 {
                  box3high  =  box2high;
                  box3low   =   box2low;
                  box3range = box2range;
                  box2high  =  box1high;
                  box2low   =   box1low;
                  box2range = box1range;
                  box1high  =      BoxH;
                  box1low   =      BoxL;
                  box1range =     range;
                 }
              }
            RunBARscan();
            continuescan=false;
            break;
           }
        }
     }
  }
//+----------------------------------------+
//  Run BAR scan                           |
//+----------------------------------------+
void RunBARscan()
//+----------------------------------------+
  {
//Specification Engine Rule 1
   if(box1high>box2high) binaryh1="00";
   else if(box1high<=box2high && box1high>=box2low) binaryh1="10";
   else binaryh1="11";

   if(box1low>box2high) binaryl1="00";
   else if(box1low<=box2high && box1low>=box2low) binaryl1="10";
   else binaryl1="11";

//Specification Engine Rule 2
   if(box2high>box3high) binaryh2="00";
   else if(box2high<=box3high && box2high>=box3low) binaryh2="10";
   else binaryh2="11";

   if(box2low>box3high) binaryl2="00";
   else if(box2low<=box3high && box2low>=box3low) binaryl2="10";
   else binaryl2="11";

//Specification Engine Rule 3
   if(box1high>box3high) binaryh3="00";
   else if(box1high<=box3high && box1high>=box3low) binaryh3="10";
   else binaryh3="11";

   if(box1low>box3high) binaryl3="00";
   else if(box1low<=box3high && box1low>=box3low) binaryl3="10";
   else binaryl3="11";

   CurrentBoxPattern=+binaryh2+binaryl2+"."+binaryh1+binaryl1+"."+binaryh3+binaryl3;
   Print("Current box pattern - "+CurrentBoxPattern);

   if((CurrentBoxPattern==Box_Type) && 
      (box1range>box_min && box1range<box_max) && 
      (box2range>box_min && box3range<box_max) && 
      (box3range>box_min && box3range<box_max))
      NewTradeBoxFormed=true;
  }
//+----------------------------------------+
//  Look For Active Trade Box              |
//+----------------------------------------+
void LookForActiveTradeBox()
//+----------------------------------------+
  {
   double fakey = iClose(Symbol(),0,1);
   double price = Bid;

   if(Trade_Long)
     {
      if(price>box1high)
        {
         NewTradeBoxFormed=false;
         GoLongIntoMarket(box1high,box1low);
        }
      if(fakey<box1low) NewTradeBoxFormed=false;
     }

   else
     {
      if(fakey>box1high)NewTradeBoxFormed=false;
      if(price<box1low)
        {
         NewTradeBoxFormed=false;
         GoShortIntoMarket(box1high,box1low);
        }
     }
  }
//+------------------------------------------------------------------+
//|   Set first order to go long into market                         |
//+------------------------------------------------------------------+
void GoLongIntoMarket(double high,double low)
//+------------------------------------------------------------------+
  {
   double lot            = 0.01;
   double volatility     = high-low;
   double n_value        = (volatility/Point)*TickValue;
   double risk           = AccBal*(Risk / 100);
   double tradevolume    = risk /n_value;

   if(tradevolume>lot) lot=tradevolume;

   double price          = Ask;
   double StopLoss       = Ask-volatility;
   double TakeProfit     = Ask+volatility;

   int OpenLong=OrderSend(Symbol(),OP_BUY,lot,price,Slippage,StopLoss,TakeProfit,NULL,Magic_No,0,Blue);

   NewTradeBoxFormed=false;

  }
//+------------------------------------------------------------------+
//|   Set first order to go short into market                        |
//+------------------------------------------------------------------+
void GoShortIntoMarket(double high,double low)
//+------------------------------------------------------------------+
  {
   double lot            = 0.01;
   double volatility     = high-low;
   double n_value        = (volatility/Point)*TickValue;
   double risk           = AccBal*(Risk / 100);
   double tradevolume    = risk /n_value;

   if(tradevolume>lot) lot=tradevolume;

   double price          = Bid;
   double StopLoss       = Bid+volatility;
   double TakeProfit     = Bid-volatility;

   int OpenShort=OrderSend(Symbol(),OP_SELL,lot,price,Slippage,StopLoss,TakeProfit,NULL,Magic_No,0,Red);

   NewTradeBoxFormed=false;

  }

 

When I run a visual test in strategy tester works fine (to the best of my very limited programming ability). However when I do optimizing runs, more often than not, I receive the following errors after the first pass

 

2016.09.18 08:53:08.796 2021.11.30 11:38  Bobs BARBAB v5.1 Tester EURUSD,M1: array out of range in 'Bobs BARBAB v5.1 Tester.mq4' (232,32)
2016.09.18 08:53:08.796 2021.11.30 11:38  Testing pass stopped due to a critical error in the EA
2016.09.18 08:53:08.795 2021.11.30 11:38  Bobs BARBAB v5.1 Tester EURUSD,M1: array out of range in 'Bobs BARBAB v5.1 Tester.mq4' (232,32)
2016.09.18 08:53:08.795 Testing pass stopped due to a critical error in the EA
2016.09.18 08:53:08.795 Bobs BARBAB v5.1 Tester EURUSD,M1: array out of range in 'Bobs BARBAB v5.1 Tester.mq4' (232,32)
2016.09.18 08:51:37.301 Bobs BARBAB v5.1 Tester: optimization started
2016.09.18 08:51:34.061 TestGenerator: actual tick file "C:\Users\Robert Browne\AppData\Roaming\MetaQuotes\Terminal\24EE5CAC8CCD07170A66D63F6BC063B9\tester\history\EURUSD1_0.fxt" found
2016.09.18 08:51:34.061 TDS: Using current spread 20.

 

So its blaming this bit of code

 

//--- line code causing error
         double BoxH1  =   High[hs1];

//--- from this bit of code

//+----------------------------------------+
//  Run Range scan                         |
//+----------------------------------------+
void RunRangeScan(int index,int boxspread,int run_leg,int boxNo,double Min,double Max)
//+----------------------------------------+
  {
   if(index>boxspread)
     {
      for(int i=index;i>0;i--)
        {
         bool valid=true;
         int bc=0;

         int    BoxHS  = iHighest(NULL,0,MODE_HIGH,run_leg,i);
         int    BoxLS  = iLowest (NULL,0,MODE_LOW,run_leg,i);
         int    LeftT  = MathMax(BoxHS,BoxLS);
         int    RightT = MathMin(BoxHS,BoxLS);
         int    hs1    = BoxHS+1;
         int    hs2    = BoxHS+2;
         int    hs3    = BoxHS+3;
         int    ls1    = BoxLS+1;
         int    ls2    = BoxLS+2;
         int    ls3    = BoxLS+3;

         double BoxH   = High[BoxHS];
         double BoxH1  =   High[hs1];
         double BoxH2  =   High[hs2];
         double BoxH3  =   High[hs3];
         double BoxL   =  Low[BoxLS];
         double BoxL1  =    Low[ls1];
         double BoxL2  =    Low[ls2];
         double BoxL3  =    Low[ls3];
         double range  =   BoxH-BoxL;

 

This error occurs solely based on the start date for each run. Some start dates it works fine, most won't and it makes it annoying cause one can't do in sample and out of sample  back testing.  Can someone help with what's going wrong

 
Is this for stock exchanges/indices? I am not sure what you are trying to get data for. If its indices then it may be because (just a guess) all of them are opening and closing simultaniously at different times and there will be gaps, missing bars or static prices. Other than that I do not know, you could try downloading more data from the history centre.
 
alexlearnmql:
Is this for stock exchanges/indices? I am not sure what you are trying to get data for. If its indices then it may be because (just a guess) all of them are opening and closing simultaniously at different times and there will be gaps, missing bars or static prices. Other than that I do not know, you could try downloading more data from the history centre.

Run on currency pairs bro, used on a 1min chart. Its the bare bones code of my actual bot I use to test different price action patterns. Just taken the bling bling out for testing purposes.

My testing data is sourced from dukascopy, converted with tickstorylite and I test with Birts tickdata suite.

 
Yep way too complicated for me lol. Good luck finding a solution.
 
  1. int OnInit(){
       :
    
       spd4  = Time[10];
       spd5  = Time[12];
    
    You initialize these once when the EA is loaded instead of in start.
  2. You know the line, print the size of the array and the variables and track it down.
 
WHRoeder 2016.09.18 18:34 #
  1. int OnInit(){
       :
    
       spd4  = Time[10];
       spd5  = Time[12];
    
    You initialize these once when the EA is loaded instead of in start.
I'm afraid I don't understand this bit. Where else can I load these valves if not onInit(). 
  1. You know the line, print the size of the array and the variables and track it down.

So I loaded the code with print() functions. Again in visual mode no problems, all the valves are returned as required. Yet still, during optimizing, the first pass runs no problems but then the error occurs. As the print() function doesn't work during optimizing I can't see what is happening there. 

Any other suggestions???

The code is extracted from an indicator I have developed. I have attached it as it shows clearly what the code is identifying.  Might make things more clearer

 

Files:
bmb_v3.4.mq4  12 kb
 
forexbob1970: I'm afraid I don't understand this bit. Where else can I load these valves if not onInit().

Since the Bar History Data is continually updating, how do you expect it to work in OnInit() when it is only called once when the code is initialised. The only way to keep getting the latest data is to check it in the OnTick(). In order to be efficient however, you should detect when I new bar is created and only then update these values.

 
FMIC:

The only way to keep getting the latest data is to check it in the OnTick(). In order to be efficient however, you should detect when I new bar is created and only then update these values.

This is the part I am having trouble getting my head around. Because the value of the variable is set here (calculated on the new bar)

 switch(boxNo)
              {
               case 4:   spd4=Time[i];break;
               case 5:   spd5=Time[i];break;
               case 6:   spd6=Time[i];break;
               case 7:   spd7=Time[i];break;
               case 8:   spd8=Time[i];break;

 If I loaded the value OnTick() won't it just reset back to this value on each tick. Because of the price pattern this code detects once this "spd4..." value is set it needs to hold this valve as each new bar is formed until the price action is void.

 
forexbob1970:

This is the part I am having trouble getting my head around. Because the value of the variable is set here (calculated on the new bar)

 If I loaded the value OnTick() won't it just reset back to this value on each tick. Because of the price pattern this code detects once this "spd4..." value is set it needs to hold this valve as each new bar is formed until the price action is void.

The root of the problem, is that your whole approach seems incorrect and adhoc (in my opinion, as I still don't understand what it is you are trying to achieve). In my own opinion, you should rewrite your entire code from scratch and in a more structured way (as it is very "stringy"), but only once you understand the underlying principals of how the MQL environment  works.

  • OnInit() only gets called when the code is first initialised (eg. when the EA is attached to the chart).
  • OnTick() gets called on every new tick (in real trading however, some get skipped).
  • On every new tick (not necessarily on every OnTick() event), there will be updates to Volume[0], Close[0], and if applicable, to High[0] or Low[0]. There will be no change to Open[0], Time[0] and all the other [i] instances, as they remain the same (provided no new bar is formed, see next point).
  • When the new tick is for a new bar forming, then all the previous [0] data moves on over to the [1] position, and [1] to [2], and [2] to [3], etc. and a new bar is created at [0] with Open[0]=Close[0]=High[0]=Low[0]=Bid and Volume[0]=1 and Time[0]=CurrentTime.
  • Incidentally, that is how you detect a new bar, when Time[0] changes, as you have correctly coded.
  • With regards to all your "spd#" variables, use arrays and loops instead.
  • As it is, it looks a mess - it is long and "stringy" and is difficult to read or understand what it is you are trying to accomplish.

EDIT: PS! It may be easier and probably more correct and efficient, for you to first code an Indicator to detect and signal all the so called "boxes", and then to call that logic from "iCustom". That way you can visually test and make sure your Indicator logic is working correctly, before you start worrying about the order and trade management of an EA with the added bonus that you will be able to use the Indicator for manual trading and visualisation, independently of the EA.

 
forexbob1970:
WHRoeder 2016.09.18 18:34 #
  1. You initialize these once when the EA is loaded instead of in start.
I'm afraid I don't understand this bit. Where else can I load these valves if not onInit().
What part of "in start" was unclear? Old style start, new style onTick.

Perhaps you need to read the documentation. Event Handling Functions - Functions - Language Basics - MQL4 Reference
 
Thank you gentlemen for your responses. I appreciate my woeful coding skills and how difficult it must be to try and understand what I'm trying to achieve from it. Thank you for your patience. 
Reason: