MetaTrader you had one job - inconsistencies when backtesting (visual vs. non visual)

 

MetaTrader 5 produces different backtest results when you use exactly the same settings for the Visual Backtester and Non-Visual Backtester.

When I use the Visual mode everything is normal and goes as expected, when I uncheck the visual mode hoping to get the same results but faster, this is what I get (look at the attached images and the highlighted areas)

the non-visual mode opens and closes trades based on some unknown factors. the execution latency is set to 0 so there's no delay. also I am using the same data from my broker and the modeling is set to every-tick.

Almost a year ago I had a similar problem which I then somehow mnaged to work around (https://www.mql5.com/en/forum/466338) please anyone any suggestions?

Inconsistent backtest results
Inconsistent backtest results
  • 2024.04.28
  • hematinik
  • www.mql5.com
Yet another quirk of MT5, with exactly the same conditions the visual tester does the job right while the non-visual tester opens a position when i...
Files:
 

Is your code logic in anyway dependant on graphical objects?

If yes, then that is the most probable reason, given the different way they are handled between visual and non-visual way.

If not, then based on your previous topic, also have a look at the following program property ...


tester_everytick_calculate

string

In the Strategy Tester, indicators are only calculated when their data are accessed, i.e. when the values of indicator buffers are requested. This provides a significantly faster testing and optimization speed, if you do not need to obtain indicator values on each tick.

By specifying the tester_everytick_calculate property, you can enable the forced calculation of the indicator on every tick.

Indicators in the Strategy Tester are also forcibly calculated on every tick in the following cases:

This feature only applies in the Strategy Tester, while in the terminal indicators are always calculated on each received tick.

Documentation on MQL5: Language Basics / Preprocessor / Program Properties (#property)
Documentation on MQL5: Language Basics / Preprocessor / Program Properties (#property)
  • www.mql5.com
Every mql5-program allows to specify additional specific parameters named #property that help client terminal in proper servicing for programs...
 
Fernando Carreiro #:

Is your code logic in anyway dependant on graphical objects?

I really appreciate your response,

No graphical objects, this is a basic EA that trades a simple trailing stop indicator. I tried the suggested #property and the same problem presists. I also tried adding OnTimer() with a Print() just to make sure that backtester calculates everytick.

I tried to use only one core of my CPU just in case multi-threading was problematic with no avail. something is different under the hood between the two backtesters.

 
hematinik #: No graphical objects, this is a basic EA that trades a simple trailing stop indicator. I tried the suggested #property and the same problem presists. I also tried adding OnTimer() with a Print() just to make sure that backtester calculates everytick.

Without access to the full source code, we can offer very little advice. You will have to do a deep analysis and/or thorough debugging, to uncover the reason for the discrepancy.

In my own use of MetaTrader 5 (and previously MetaTrader 4), I have not had a similar issue, so I can only attribute your issue to a code logic problem, and not a platform deficiency.

EDIT: Also debug your custom indicators. The problem may be in the indicators and not necessarily in the EA.

hematinik #: I tried to use only one core of my CPU just in case multi-threading was problematic with no avail. something is different under the hood between the two backtesters.

For a single back-test, enabling or disabling multi-threading will have no effect. Only optimisations will make use of multi-threading for each pass.

 
hematinik #:

I really appreciate your response,

No graphical objects, this is a basic EA that trades a simple trailing stop indicator. I tried the suggested #property and the same problem presists. I also tried adding OnTimer() with a Print() just to make sure that backtester calculates everytick.

I tried to use only one core of my CPU just in case multi-threading was problematic with no avail. something is different under the hood between the two backtesters.

In the past, this has often happend to me; the 1 reason always being; including using custom indicators that did not retrieve the price data correctly, OR, my ea did not retrieve the price data correctly. Sometimes the non visual test was proven correct; other times, it was the visual tester that was proven correct; but in all cases, once I fixed the code, then, both tester "flavours", matched after the code was fixed.

 
Michael Charles Schefe #:

In the past, this has often happend to me; the 1 reason always being; including using custom indicators that did not retrieve the price data correctly, OR, my ea did not retrieve the price data correctly. Sometimes the non visual test was proven correct; other times, it was the visual tester that was proven correct; but in all cases, once I fixed the code, then, both tester "flavours", matched after the code was fixed.

While you could always do that, the basic question is that why this happens and no body seems to know that for a long time. you expect the non-visual backtester produce the same results as in the visual and the live chart, otherwise how can you trust any backtest optimization to be correct?

 
hematinik #: While you could always do that, the basic question is that why this happens and no body seems to know that for a long time. you expect the non-visual backtester produce the same results as in the visual and the live chart, otherwise how can you trust any backtest optimization to be correct?

It seems you did not understand the answers, so please read them again.

There is no "long time"! It is not a fault with the Strategy Tester.

The problem is with your own code. You need to fix it.

 

This topic comes up from time to time..

Forum on trading, automated trading systems and testing trading strategies

how come a line of my backtest has a profit x and a dd y....and when i run the single test the profit and dd is way different from the backtest line result?

Manuel Alejandro Cercos Perez, 2023.06.18 09:36

https://www.mql5.com/en/code/21700

https://www.mql5.com/en/code/21247


If an indicator checks for updates in only all or 1 rates, it gives errors: when in non visual mode, an indicator would only call OnCalculate when called in a CopyBuffer so if it is not accessed during some candle you could get an OnCalculate where rates_total==prev_calculated+3, for example. Also in non visual the backtest does only the open price tick for each candle, in visual it does open-high-low-close (only open for code, the other 3 for indicators), and indicators get updated in all ticks. In the example there are also other CopyBuffers that would miss data if they don't update 1 by 1 (and would have data from open only, instead of close, so that also changes even when going 1 by 1). In visual or live charts they usually work perfectly though.


You can test them with a simple EA like this one:

input string indicatorName = "NAME";
input int mainBuffer = 0;
input int displace = 1;
input int daysToPrint = 2;
input int jump = 0;
input bool only_hash = false;


int handle;


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

union LongDouble 
{ 
  long long_value; 
  double double_value; 
};

//int file=0;

long hash;

int OnInit()
{
        hash = 0;
        
        //if (!MQLInfoInteger(MQL_VISUAL_MODE))
        //      file=FileOpen("_NONVISUALTEST.txt", FILE_COMMON|FILE_WRITE|FILE_TXT|FILE_ANSI);

   handle = iCustom(Symbol(), PERIOD_CURRENT, indicatorName);



   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
        //if (!MQLInfoInteger(MQL_VISUAL_MODE))
        //{
        //      FileWrite(file, "\nHash: ", hash);
        //      FileClose(file);
        //}
        //else
                Print("\nHash: ", hash);
                
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+

datetime TimeStamp;
int jumpCount=0;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
{
   if(TimeStamp!=iTime(_Symbol,PERIOD_CURRENT,0))
   {
      TimeStamp=iTime(_Symbol,PERIOD_CURRENT,0);
      if (jumpCount<jump)
      {
         jumpCount++;
         return;
      }
      else
      {
         jumpCount=0;
      }

      double val[];
      CopyBuffer(handle, mainBuffer, displace, daysToPrint, val);

      string to_print = "";

      for (int j = 0; j < daysToPrint; j++)
      {
        LongDouble lb;
        lb.double_value = val[j];
      
        hash = hash ^ lb.long_value;
        
        if (!only_hash)
                to_print += DoubleToString(val[j]) + " ";
      }
                if (!only_hash)
                {
                        //if (!MQLInfoInteger(MQL_VISUAL_MODE))
                        //      FileWrite(file, to_print);
                        //else
                Print(to_print);
                }
                        
      
   }
}
//+------------------------------------------------------------------+

There are multiple indicators that have errors of this kind, but to be fair there is no way (that I know) to test an indicator in non visual mode by itself!


At least, there are ways to identify which indicator is the source of your issues (you can test them), IF an indicator is the cause (which most often is). If you find it, put the tester_everytick_calculate property above its code as said previously and if you can't access the code, replace it with another similar that works well or contact the author.

The codebase is filled with indicators with such errors...

 
hematinik #:

While you could always do that, the basic question is that why this happens and no body seems to know that for a long time. you expect the non-visual backtester produce the same results as in the visual and the live chart, otherwise how can you trust any backtest optimization to be correct?

totally agree. however, the fact remains that your code needs to be fixed for it to work in strategy tester.

 
Manuel Alejandro Cercos Perez #:

This topic comes up from time to time..


At least, there are ways to identify which indicator is the source of your issues (you can test them), IF an indicator is the cause (which most often is). If you find it, put the tester_everytick_calculate property above its code as said previously and if you can't access the code, replace it with another similar that works well or contact the author.

The codebase is filled with indicators with such errors...


Dear Manuel I can not thank you enough. I was trying to figure out a way to understand what's going on under the hood to avoid the problem in the future, knowing that nothing is wrong with my code as other folks assume:


Fernando Carreiro #:
It seems you did not understand the answers

The problem is with your own code. You need to fix it.


How could I possibly edit a compiled indicator? So I put "tester_everytick_calculate" property inside the EA among dozens of other efforts and none of them helped. this is clearly a flaw in the MT design which I've been stuggling with for a long time. I perfectly did understand the answers that none of them was a solution.

 
hematinik #: this is clearly a flaw in the MT design which I've been stuggling with for a long time.

How are you trying to shift the blame onto the Strategy Tester when it is the indicator that is improperly coded?

hematinik #: How could I possibly edit a compiled indicator?

If you don't have the code for the indicator, then contact the author to have it fixed.

And if that is not possible, then rewrite a new indicator to match the functionality of the "closed source" indicator.