Strategy tester

 

Hi,

 

I have an ea which performs extremely well in strategy tester when 'open prices only' is selected, but when I test on 'every tick' mode the results are not so good. So my question is..

Is it possible to adjust my ea so that it works on the same open bar principle as the strategy tester? I tried changing the 'eachtick' variable to 'false' but that didn't do it. Anyone know if there is anything I can do?

The ea is very simple and only uses 2 indicators 

#define SIGNAL_NONE 0
#define SIGNAL_BUY   1
#define SIGNAL_SELL  2
#define SIGNAL_CLOSEBUY 3
#define SIGNAL_CLOSESELL 4

#property copyright "Expert Advisor Builder"
#property link      "http://sufx.core.t3-ism.net/ExpertAdvisorBuilder/"

extern int MagicNumber = 1001;
extern bool EachTickMode = True;
extern double Lots = 1.0;
extern int Slippage = 3;
extern bool UseStopLoss = True;
extern int StopLoss = 400;
extern bool UseTakeProfit = True;
extern int TakeProfit = 500;
extern bool UseTrailingStop = True;
extern int TrailingStop = 250;

int BarCount;
int Current;
bool TickCheck = False;
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init() {
   BarCount = Bars;

   if (EachTickMode) Current = 0; else Current = 1;

   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit() {
   return(0);
}
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start() {
   int Order = SIGNAL_NONE;
   int Total, Ticket;
   double StopLossLevel, TakeProfitLevel;



   if (EachTickMode && Bars != BarCount) TickCheck = False;
   Total = OrdersTotal();
   Order = SIGNAL_NONE;

   //+------------------------------------------------------------------+
   //| Variable Begin                                                   |
   //+------------------------------------------------------------------+


double Buy1_1 = iADX(NULL, PERIOD_M30, 18, PRICE_CLOSE, MODE_MAIN, Current + 0);
double Buy1_2 = 28;
double Buy2_1 = iMACD(NULL, PERIOD_M15, 12, 26, 9, PRICE_CLOSE, MODE_SIGNAL, Current + 0);
double Buy2_2 = iMACD(NULL, PERIOD_M15, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, Current + 0);

double Sell1_1 = iADX(NULL, PERIOD_M30, 18, PRICE_CLOSE, MODE_MAIN, Current + 0);
double Sell1_2 = 28;
double Sell2_1 = iMACD(NULL, PERIOD_M15, 12, 26, 9, PRICE_CLOSE, MODE_SIGNAL, Current + 0);
double Sell2_2 = iMACD(NULL, PERIOD_M15, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, Current + 0);



   
   //+------------------------------------------------------------------+
   //| Variable End                                                     |
   //+------------------------------------------------------------------+

   //Check position
   bool IsTrade = False;

   for (int i = 0; i < Total; i ++) {
      OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
      if(OrderType() <= OP_SELL &&  OrderSymbol() == Symbol()) {
         IsTrade = True;
         if(OrderType() == OP_BUY) {
            //Close

            //+------------------------------------------------------------------+
            //| Signal Begin(Exit Buy)                                           |
            //+------------------------------------------------------------------+

            

            //+------------------------------------------------------------------+
            //| Signal End(Exit Buy)                                             |
            //+------------------------------------------------------------------+

            if (Order == SIGNAL_CLOSEBUY && ((EachTickMode && !TickCheck) || (!EachTickMode && (Bars != BarCount)))) {
               OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, MediumSeaGreen);
                SendMail("[Signal Alert]", "[" + Symbol() + "] " + DoubleToStr(Bid, Digits) + " Close Buy");
               if (!EachTickMode) BarCount = Bars;
               IsTrade = False;
               continue;
            }
            //Trailing stop
            if(UseTrailingStop && TrailingStop > 0) {                 
               if(Bid - OrderOpenPrice() > Point * TrailingStop) {
                  if(OrderStopLoss() < Bid - Point * TrailingStop) {
                     OrderModify(OrderTicket(), OrderOpenPrice(), Bid - Point * TrailingStop, OrderTakeProfit(), 0, MediumSeaGreen);
                     if (!EachTickMode) BarCount = Bars;
                     continue;
                  }
               }
            }
         } else {
            //Close

            //+------------------------------------------------------------------+
            //| Signal Begin(Exit Sell)                                          |
            //+------------------------------------------------------------------+

            

            //+------------------------------------------------------------------+
            //| Signal End(Exit Sell)                                            |
            //+------------------------------------------------------------------+

            if (Order == SIGNAL_CLOSESELL && ((EachTickMode && !TickCheck) || (!EachTickMode && (Bars != BarCount)))) {
               OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, DarkOrange);
                SendMail("[Signal Alert]", "[" + Symbol() + "] " + DoubleToStr(Ask, Digits) + " Close Sell");
               if (!EachTickMode) BarCount = Bars;
               IsTrade = False;
               continue;
            }
            //Trailing stop
            if(UseTrailingStop && TrailingStop > 0) {                 
               if((OrderOpenPrice() - Ask) > (Point * TrailingStop)) {
                  if((OrderStopLoss() > (Ask + Point * TrailingStop)) || (OrderStopLoss() == 0)) {
                     OrderModify(OrderTicket(), OrderOpenPrice(), Ask + Point * TrailingStop, OrderTakeProfit(), 0, DarkOrange);
                     if (!EachTickMode) BarCount = Bars;
                     continue;
                  }
               }
            }
         }
      }
   }

   //+------------------------------------------------------------------+
   //| Signal Begin(Entry)                                              |
   //+------------------------------------------------------------------+

   if (Buy1_1 > Buy1_2 && Buy2_1 < Buy2_2) Order = SIGNAL_BUY;

   if (Sell1_1 > Sell1_2 && Sell2_1 > Sell2_2) Order = SIGNAL_SELL;


   //+------------------------------------------------------------------+
   //| Signal End                                                       |
   //+------------------------------------------------------------------+

   //Buy
   if (Order == SIGNAL_BUY && ((EachTickMode && !TickCheck) || (!EachTickMode && (Bars != BarCount)))) {
      if(!IsTrade) {
         //Check free margin
         if (AccountFreeMargin() < (1000 * Lots)) {
            Print("We have no money. Free Margin = ", AccountFreeMargin());
            return(0);
         }

         if (UseStopLoss) StopLossLevel = Ask - StopLoss * Point; else StopLossLevel = 0.0;
         if (UseTakeProfit) TakeProfitLevel = Ask + TakeProfit * Point; else TakeProfitLevel = 0.0;

         Ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, Slippage, StopLossLevel, TakeProfitLevel, "Buy(#" + MagicNumber + ")", MagicNumber, 0, DodgerBlue);
         if(Ticket > 0) {
            if (OrderSelect(Ticket, SELECT_BY_TICKET, MODE_TRADES)) {
                                Print("BUY order opened : ", OrderOpenPrice());
                 SendMail("[Signal Alert]", "[" + Symbol() + "] " + DoubleToStr(Ask, Digits) + " Open Buy");
                        } else {
                                Print("Error opening BUY order : ", GetLastError());
                        }
         }
         if (EachTickMode) TickCheck = True;
         if (!EachTickMode) BarCount = Bars;
         return(0);
      }
   }

   //Sell
   if (Order == SIGNAL_SELL && ((EachTickMode && !TickCheck) || (!EachTickMode && (Bars != BarCount)))) {
      if(!IsTrade) {
         //Check free margin
         if (AccountFreeMargin() < (1000 * Lots)) {
            Print("We have no money. Free Margin = ", AccountFreeMargin());
            return(0);
         }

         if (UseStopLoss) StopLossLevel = Bid + StopLoss * Point; else StopLossLevel = 0.0;
         if (UseTakeProfit) TakeProfitLevel = Bid - TakeProfit * Point; else TakeProfitLevel = 0.0;

         Ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, Slippage, StopLossLevel, TakeProfitLevel, "Sell(#" + MagicNumber + ")", MagicNumber, 0, DeepPink);
         if(Ticket > 0) {
            if (OrderSelect(Ticket, SELECT_BY_TICKET, MODE_TRADES)) {
                                Print("SELL order opened : ", OrderOpenPrice());
                 SendMail("[Signal Alert]", "[" + Symbol() + "] " + DoubleToStr(Bid, Digits) + " Open Sell");
                        } else {
                                Print("Error opening SELL order : ", GetLastError());
                        }
         }
         if (EachTickMode) TickCheck = True;
         if (!EachTickMode) BarCount = Bars;
         return(0);
      }
   }

   if (!EachTickMode) BarCount = Bars;

   return(0);
}
//+------------------------------------------------------------------+
 

You can add something like this to check if new candle is opened:

   static datetime currentBarTime = 0; // or Time[0] if you want to skip first candle; 
   
   
   if ( currentBarTime == Time[0] )
   {
      return(0);
   }
   currentBarTime = Time[0];

This code should be added at the beginning of the start function. It will ensure that rest of the code is executed only when new candle is opened. 

 

Using "BarCount" as you have in your code has problem because it keeps length of "Bars" buffer. This buffer has some maximum value and from that point on it returns the same number.

 
Ok thank you! I will add that code in today and play around with it. Not sure what you mean exactly by the BarCount (I'm very new to this) The majority of that code was created by an ea generator. Is there something that I would need to take out then (the BarCount) or would I just need to leave the EachTickMode on False
 

Near the beginning of the start() function there is this line:

 if (EachTickMode && Bars != BarCount) TickCheck = False;

 

I didn't do detailed analysis, but it looks to me that this is used to limit order opening only to the start of the candle. 

After a bit detailed look into your code,  thing that I wrote should be modified a bit. If you copy that as I wrote, it will limit code for closing orders only to the opening of the new candle.

Something like this should work:

 

static datetime currentBarTime = 0; // or Time[0] if you want to skip first candle; 

if (EachTickMode && currentBarTime == Time[0]) TickCheck = False;   
   
currentBarTime = Time[0];

 I did not test this code, so you should carefully test if this suits your trading algorithm.

 
Ok great :) So should I remove this line as well as adding the new code?
if (EachTickMode && Bars != BarCount) TickCheck = False;
 
Bluntside:

Hi,

 

I have an ea which performs extremely well in strategy tester when 'open prices only' is selected, but when I test on 'every tick' mode the results are not so good. So my question is..

Is it possible to adjust my ea so that it works on the same open bar principle as the strategy tester? I tried changing the 'eachtick' variable to 'false' but that didn't do it. Anyone know if there is anything I can do?

The ea is very simple and only uses 2 indicators 

Read https://www.mql5.com/en/articles/75
The Algorithm of Ticks' Generation within the Strategy Tester of the MetaTrader 5 Terminal
The Algorithm of Ticks' Generation within the Strategy Tester of the MetaTrader 5 Terminal
  • 2010.06.02
  • MetaQuotes Software Corp.
  • www.mql5.com
MetaTrader 5 allows us to simulate automatic trading, within an embedded strategy tester, by using Expert Advisors and the MQL5 language. This type of simulation is called testing of Expert Advisors, and can be implemented using multithreaded optimization, as well as simultaneously on a number of instruments. In order to provide a thorough testing, a generation of ticks based on the available minute history, needs to be performed. This article provides a detailed description of the algorithm, by which the ticks are generated for the historical testing in the MetaTrader 5 client terminal.
 
Ok I'll have a read now :)
Reason: