How to backtest a manual trading system?

 

Hi guys,

I´m trying to backtest a manual trading system on 2013 year. As I have the date/hour/minute of every open and close trade, after lots of hour of work, I´ve succeeded in backtesting it on Excel in terms of profit only.

As you know, I system can not be evaluated just buy its profit. I need to know things like how big was the drawdown, how much margin does the system requires, what is the profit factor etc.

The only way I know to make a good backtest is buy Mt4 Strategy Tester. Ok, so I just need to make up a simple EA that open and close trades at a specific sort of dates/hours/minutes.

And here comes the problem: if on one hand I´m sure that this is one of simplest EA´s ever, I´m on the first steps of mql4 programming and I´m not succeeding in making this EA work.

Can you help me? It can be by helping me finding what is wrong with the EA I´ve designed or even telling me about another way to get a good backtest on my manual system.

Thank you in advance.

datetime BuyEURUSDStart1;
datetime BuyEURUSDFinish1;

datetime SellEURUSDStart1;
datetime SellEURUSDFinish1;

extern double Lots = 0.1;
extern int Slippage = 3;


int init() {
   return(0);
}

int deinit() {
   return(0);
}

int start() {

int TicketBuyEURUSD = 0;
int TicketSellEURUSD = 0;

BuyEURUSDStart1 = StrToTime("2013.9.12 13:00");
BuyEURUSDFinish1 = StrToTime("2013.16.12 13:00");

SellEURUSDStart1 = StrToTime("2013.16.12 13:01");
SellEURUSDFinish1 = StrToTime("2013.18.12 13:01");

if(TicketBuyEURUSD == 0 && TimeCurrent()>BuyEURUSDStart1 && TimeCurrent()<BuyEURUSDFinish1)
   TicketBuyEURUSD =   OrderSend("EURUSD",OP_BUY,Lots,Ask,Slippage,0,0); 
             
if(TicketBuyEURUSD > 0 && TimeCurrent()>=SellEURUSDStart1 && TimeCurrent()<SellEURUSDFinish1)
   {
   OrderClose(TicketBuyEURUSD, Lots, Bid, Slippage, Red);
   TicketBuyEURUSD = 0;
   }
   
if(TicketSellEURUSD == 0 && TimeCurrent()>SellEURUSDStart1 && TimeCurrent()<SellEURUSDFinish1)
   TicketSellEURUSD =   OrderSend("EURUSD",OP_SELL,Lots,Bid,Slippage,0,0);
   
if(TicketSellEURUSD > 0 && TimeCurrent()>=BuyEURUSDStart1 && TimeCurrent()<BuyEURUSDFinish1)
   {
   OrderClose(TicketSellEURUSD, Lots, Ask, Slippage, Navy);
   TicketSellEURUSD = 0;
   }
  
   return(0);
}
 
Reis: here comes the problem: I´m not succeeding in making this EA work. Can you help me?
  1. Your problem is not stating a problem. You can't even state what it is doing and what it should be.
  2. Add Print statements before and inside your conditionals, dumping your variable values and find out what it is doing and why.
  3. What are Function return values ? How do I use them ? - MQL4 forum
 

Thank you WHRoeder for the fast answer.

At this moment I´m studying how to put the Print Statements to find what is happening.

Thank you once more.

 

Ok guys,

I´ve done what WHReder told me to and I did not have to search to much to find issues.

I´ve made some changes on the EA and this is the new one:

datetime BuyEURUSDStart1;
datetime BuyEURUSDFinish1;

datetime SellEURUSDStart1;
datetime SellEURUSDFinish1;

extern double Lots = 0.1;
extern int Slippage = 3;

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init() {
   

   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit() {
   return(0);
}
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start() {

int TicketBuyEURUSD = 0;
int TicketSellEURUSD = 0;

BuyEURUSDStart1 = StrToTime("2013.9.12 13:00");
BuyEURUSDFinish1 = StrToTime("2013.16.12 13:00");

SellEURUSDStart1 = StrToTime("2013.16.12 13:01");
SellEURUSDFinish1 = StrToTime("2013.18.12 13:01");

Print("Current time is ", TimeToStr(TimeCurrent()));

//Print("Current time is ", TimeToStr(TimeCurrent()), "BuyEURUSDStart1 is", TimeToStr(BuyEURUSDStart1), "BuyEURUSDFinish1 is", TimeToStr(BuyEURUSDFinish1));
//Print("SellEURUSDStart1 is", TimeToStr(SellEURUSDStart1), "SellEURUSDFinish1 is", TimeToStr(SellEURUSDFinish1));

if(TimeCurrent() > BuyEURUSDStart1 && TimeCurrent() < BuyEURUSDFinish1)
   {
   if(TicketSellEURUSD > 1) 
      {
      OrderClose(TicketSellEURUSD, Lots, Ask, Slippage, DarkOrange);
      TicketSellEURUSD = 0;
      }
   if(TicketBuyEURUSD < 1) TicketBuyEURUSD =  OrderSend("EURUSD",OP_BUY,Lots,Ask,Slippage,0,0); 
   }   
   
           
if(TimeCurrent() > SellEURUSDStart1 && TimeCurrent() < SellEURUSDFinish1)
   {
   if(TicketBuyEURUSD > 1)
      {
      OrderClose(TicketBuyEURUSD, Lots, Bid, Slippage, DarkOrange);
      TicketBuyEURUSD = 0;
      }
   if(TicketSellEURUSD < 1)  TicketSellEURUSD = OrderSend("EURUSD",OP_SELL,Lots,Bid,Slippage,0,0);
   }

   return(0);
}

I´ve made the backtest for December 2013 and as you can see in this part of my journal, it seems I have a problem with the TimeCurrent() command. Although I´ve tested the entire month, TimeCurrent() always give me the last minutes of 24th day of December.

2013.12.28 19:32:35 2013.12.24 23:58 Teste de operações 1.12 EURUSD,M1: Current time is 2013.12.24 23:58

2013.12.28 19:32:35 2013.12.24 23:57 Teste de operações 1.12 EURUSD,M1: Current time is 2013.12.24 23:57

2013.12.28 19:32:35 2013.12.24 23:56 Teste de operações 1.12 EURUSD,M1: Current time is 2013.12.24 23:56

2013.12.28 19:32:35 2013.12.24 23:56 Teste de operações 1.12 EURUSD,M1: Current time is 2013.12.24 23:56

2013.12.28 19:32:35 2013.12.24 23:56 Teste de operações 1.12 EURUSD,M1: Current time is 2013.12.24 23:56

2013.12.28 19:32:35 2013.12.24 23:56 Teste de operações 1.12 EURUSD,M1: Current time is 2013.12.24 23:56

Is this the right command for this situation or Am I using it int the wrong way?

Can you keep on helping me?

Thank you again.


 

You appear to have run the test for the entire month. So the last print statements will be for the end of your history. What do you expect?

Try visual mode, when it gets to the point it is doing something you think is wrong, pause the test, look at your values, figure it out.

WHRoeder:
  1. Your problem is not stating a problem. You can't even state what it is doing and what it should be.
  2. Add Print statements before and inside your conditionals, dumping your variable values and find out what it is doing and why.
  3. What are Function return values ? How do I use them ? - MQL4 forum
Reis: I´ve done what WHReder told me to
You haven't done ANY of those (no problem, no variable, no path trace statements, no function checks.) All you are doing is printing the time for the current tick (if you really cared perhaps you should print the seconds also).
 
WHRoeder:

You haven't done ANY of those (no problem, no variable, no path trace statements, no function checks.) All you are doing is printing the time for the current tick (if you really cared perhaps you should print the seconds also).

WHRoeder,

I´ve done what I understood. I´m studying and trying to learn. That´s why I don´t know and I don´t understand lots of things about mql4 and mql4 terms. That´s why I haven´t done all the things you expected me to do. But believe me or not, I´m trying hard, ok?

But from the impolite way you write it seems that you are not very happy in helping me. As you are not obligated to help me or anyone here, I don´t understand why you are acting this way. It seems you are the kind of person who believes that are better then the others just because know something more.

But this is not my problem. In what concerns me I just want to tell you that I´m not interested in this kind of person in touch with me. So, I did not ask specifically you to came here to help me, but now I´m asking specifically you to go away and stop bothering me, ok?

Don´t worry, I´ll solve my problem in another way.

Have a nice evening.

 
Reis:

Ok guys,

I´ve done what WHReder told me to and I did not have to search to much to find issues.

I´ve made some changes on the EA and this is the new one:

I´ve made the backtest for December 2013 and as you can see in this part of my journal, it seems I have a problem with the TimeCurrent() command. Although I´ve tested the entire month, TimeCurrent() always give me the last minutes of 24th day of December.

2013.12.28 19:32:35 2013.12.24 23:58 Teste de operações 1.12 EURUSD,M1: Current time is 2013.12.24 23:58

2013.12.28 19:32:35 2013.12.24 23:57 Teste de operações 1.12 EURUSD,M1: Current time is 2013.12.24 23:57

2013.12.28 19:32:35 2013.12.24 23:56 Teste de operações 1.12 EURUSD,M1: Current time is 2013.12.24 23:56

2013.12.28 19:32:35 2013.12.24 23:56 Teste de operações 1.12 EURUSD,M1: Current time is 2013.12.24 23:56

2013.12.28 19:32:35 2013.12.24 23:56 Teste de operações 1.12 EURUSD,M1: Current time is 2013.12.24 23:56

2013.12.28 19:32:35 2013.12.24 23:56 Teste de operações 1.12 EURUSD,M1: Current time is 2013.12.24 23:56

Is this the right command for this situation or Am I using it int the wrong way?

Can you keep on helping me?

Thank you again.



Hello Reis,

I noticed a bug that if resolved should help you get closer to your solution. You are using the "StrToTime" function incorrectly. The format that you should be using is "yyyy.mm.dd hh:mi", but in your code you seem to be switching the month and day and using single digit instead of double digit for the day.

In other words you are using for example "2013.9.12 13:00" instead of the correct format of "2013.12.09 13:00".

There might be other bugs but this one stood out to me the most.

Best Regards,

PS! If you are having difficulty with the English Language, send me a PM in Portuguese and I will try to help you out. However, the best would be to continue in English here on the topic so that others may help too.

 

Thank you very much for your attention, FMIC.

I´ve changed what you´ve told me. it was really wrong. Unfortunately the EA is not working yet.

But I´m grateful for your help.

Grateful too for offering me help with english language. As you noticed, english is not my mother tongue and if I need any help I won´t be ashamed to ask you.

Have a nice day.

 
Reis:

Thank you very much for your attention, FMIC.

I´ve changed what you´ve told me. it was really wrong. Unfortunately the EA is not working yet.

But I´m grateful for your help.

Grateful too for offering me help with english language. As you noticed, english is not my mother tongue and if I need any help I won´t be ashamed to ask you.

Have a nice day.



Hello again,

Here are a few more pointers:

  1. EDIT - DISREGARD this - it is incorrect: Slippage is in not in PIP units, but as a price difference. So use 0.0003 in order to represent 3 pips, in the case of EURUSD (see example below).
    extern int Slippage = 0.0003;
  2. To make things easier to read and to make sure the variable coincides with the result of the OrderSend() function, use EMPTY to initialise the Ticket variables as well as to check the validity.
    int TicketBuyEURUSD = EMPTY, TicketSellEURUSD = EMPTY;
  3. Don't use the a string constant "EURUSD" for the symbol name because it might be slightly different on the broker. Use NULL and simply make sure you select the "EURUSD" symbol in the Strategy tester or the chart to which you attach the EA.
    if( TicketBuyEURUSD == EMPTY )
            TicketBuyEURUSD = OrderSend( NULL, OP_BUY, Lots, Ask, Slippage, 0, 0 );
  4. When closing an order, it might be safer to first select the order and then query the number of lots and current close price and the use that to close it. This way you can make sure you close the entire order and not have an error or only a partial close. You should also check if the order actually closed or not, before clearing the Ticket with EMPTY.
    if( TicketSellEURUSD != EMPTY ) 
    {
            if( OrderSelect( TicketSellEURUSD, SELECT_BY_TICKET, MODE_TRADES ) )
            {
                    if( OrderClose( TicketSellEURUSD, OrderLots(), OrderClosePrice(), Slippage, DarkOrange ) )
                            TicketSellEURUSD = EMPTY;
            }
            else
            {
                    // Oops! Order not accessible. It may have been closed on stop out or other factor. Have to do something about it!
            }
    }
  5. After you have made the changes, if it still does not work, post your full code here as a file attachment, and I will have a look at it for you and will list any bugs I find.

Regards,
FMIC


 
FMIC:



Hello again,

Here are a few more pointers:

  1. Slippage is in not in PIP units, but as a price difference. So use 0.0003 in order to represent 3 pips, in the case of EURUSD (see example below)

No, Slippage is an int and is a number of points. The original code is correct if slippage is meant to be 3 points.

FMIC:

To make things easier to read and to make sure the variable coincides with the result of the OrderSend() function, use EMPTY to initialise the Ticket variables as well as to check the validity.
There is no need and it may confuse . . . OrderSend() returns -1 in the event of an error or returns the ticket number in the event of success. So if the ticket == EMPTY there was also a failed OrderSend()

What about error reporting ? What are Function return values ? How do I use them ?

 
WHRoeder:

You appear to have run the test for the entire month. So the last print statements will be for the end of your history. What do you expect?

Try visual mode, when it gets to the point it is doing something you think is wrong, pause the test, look at your values, figure it out.

You haven't done ANY of those (no problem, no variable, no path trace statements, no function checks.) All you are doing is printing the time for the current tick (if you really cared perhaps you should print the seconds also).


It is not always necessary to elaborate a context excessively to understand it. In Portuguese we have a saying: "Para bom entendedor, meia palavra basta!", meaning literally, "For a good ‘understander’, a half word is enough".

The posted text, even if it was not perfect English, had sufficient information in order to understand what was requested. Telling him to go read a post, which obviously is above his understanding of MQL4, is not exactly helping. It would be like telling him to go read the "manual". If everyone was able to fully understand everything by reading the manual, there would be no need to have forums like this one.

Sometimes, one needs a guiding hand and meeting him halfway would have been a better approach. Scolding him for not understanding you is not exactly “friendly”, especially since English (and “mql4”) is not his mother tongue.

Come on, we are all here to learn (and teach). No need for the snide attitude!

Let’s all be friendly! ‘Tis the season to be happy!!!

Reason: