CopyTicksRange() in tester

 

Testing an EA that has the following function called in OnTrade() event. The goal of the function is to find the highest Ask price for the current bar. Later I want to extend the function so I could get the Ask Price for any bar back in history and use it in an indicator

private:
   double            GetBarMaxPrice(int bar, double defaultPrice)
     {

      datetime start = iTime(GetSymb(), PERIOD_CURRENT, bar);

      MqlTick mqlTick[];
      int copiedTicks=CopyTicksRange(GetSymb(),mqlTick,COPY_TICKS_INFO,(ulong) start * 1000);
      if(copiedTicks < 0)
        {
         CErrorHandler::CheckLastError(false,GetProgramShortName()+"COrderStatus():GetMaxSpread()");
         return defaultPrice;
        }
      else
        {
         double maxAsk;
         for(int a = 0;a<copiedTicks;a++)
           {
            if(maxAsk<mqlTick[a].ask)
              {
               maxAsk=mqlTick[a].ask;
              }
           }
         Print("bar = "+(int)bar+" maxAsk = "+DoubleToString(maxAsk,5)+ " start = "+start+ " copiedTicks = "+copiedTicks);
         return maxAsk;
        }
      return defaultPrice;
     }

Having a Sell order for which stop loss is triggered. Here are the logs:

2026.01.01 20:01:08.708 2025.09.30 09:23:20   bar = 0 maxAsk = 1.17397 start = 2025.09.30 09:00:00 copiedTicks = 1365
2026.01.01 20:01:08.708 2025.09.30 09:23:20   bar = 0 maxAsk = 1.17397 Order.StopLoss = 1.174055080213903
2026.01.01 20:01:08.712 2025.09.30 09:23:20   stop loss triggered #2 sell 0.3 EURUSD 1.17206 sl: 1.17406 [#4 buy 0.3 EURUSD at 1.17406]
2026.01.01 20:01:08.713 2025.09.30 09:23:20   deal #4 buy 0.3 EURUSD at 1.17406 done (based on order #4)
2026.01.01 20:01:08.713 2025.09.30 09:23:20   deal performed [#4 buy 0.3 EURUSD at 1.17406]
2026.01.01 20:01:08.713 2025.09.30 09:23:20   order performed buy 0.3 at 1.17406 [#4 buy 0.3 EURUSD at 1.17406]
2026.01.01 20:01:08.714 2025.09.30 09:23:20   bar = 0 maxAsk = 1.17398 start = 2025.09.30 09:00:00 copiedTicks = 1366

Question: Why is the stoploss triggered at price 1.17406, yet the maxAsks for the current bar is still 1.17398? AFAIK, for sell order, the Ask price shoud be equal or higher the stop loss to trigger it?

Tested both with Modelling : Every tick based on real ticks and Every tick, same results

 
Dimitr Trifonov:
[F]or sell order, the Ask price shoud be equal or higher the stop loss to trigger it?

Yes. A stop order converts to a market order when triggered. Remember, the idea of a stop is to get out urgently. Slippage and delay can be manipulated in the Tester, of course.

In contrast, a limit order does exactly that--limit execution to at or better than... assuming that your limit order can get filled.

As Every tick based on real ticks and Every tick [generated] can't be exactly the same all of the time, I would be interested to see what happens when you demo test your code.
 

I found an Article dedicated to accurate backtesting:

"The pursuit of reliable back-test results in algorithmic trading hinges not only on robust strategy logic but also on the efficiency and precision of the underlying code. Raw code optimization and tweaking are critical to ensuring that Expert Advisors (EAs) perform as intended, minimizing computational overhead while maximizing execution accuracy. Poorly optimized code can distort back-test outcomes through delayed order execution, incorrect signal detection, or resource exhaustion—issues that mask a strategy’s true potential."

"Two MqlTick structures—`CTick` and `PTick`—are employed to track real-time price data, ensuring precision in execution timing and market condition analysis."

Articles

Raw Code Optimization and Tweaking for Improving Back-Test Results

Hlomohang John Borotho, 2025.05.09 11:55

Enhance your MQL5 code by optimizing logic, refining calculations, and reducing execution time to improve back-test accuracy. Fine-tune parameters, optimize loops, and eliminate inefficiencies for better performance.

 
Dimitr Trifonov:
int copiedTicks=CopyTicksRange(GetSymb(),mqlTick,COPY_TICKS_INFO,(ulong) start * 1000);

Did you check that you got the correct ticks for the considered bar ?

Are you sure this log you posted is using Every ticks (real or generated) ?

 

Thank you for your responses.

I call my function this way

GetBarMaxPrice(
0 , 
0 )

So I expect this line

int copiedTicks=CopyTicksRange(GetSymb(),mqlTick,COPY_TICKS_INFO,(ulong) start * 1000);
to return all ticks for the current/last/most-recent bar.

My guess is that the ticks in the tester may not be the same as the ticks used by CopyTicks(), even when the ticks modelling in the tester is "Every tick based on real ticks"

Keep in mind the following features when testing on real ticks:

When launching a test, the minute data on a symbol is synchronized along with the tick one.
Ticks are stored in the symbol cache of the strategy tester. The cache size does not exceed 128 000 ticks. 
When new ticks arrive, the oldest data is removed from the cache. 
However, the CopyTicks function allows receiving ticks outside the cache (only when testing on real ticks). 
In that case, the data is requested from the tester tick database 
that is completely similar to the corresponding client terminal database. 
No minute bar corrections are implemented to this base. 
Therefore, the ticks there may differ from the ones stored in the cache.

https://www.mql5.com/en/docs/runtime/testing

My initial goal is to simulate open and close positions for one of my indicators which is on the Market. It works fine, however there minor discrepancies between running the indicator in the tester and just adding the indicator on the chart.

1.Did anyone used CopyTicksRange() in the tester and face any problems like this?

2.Also maybe anyone can suggest a way to simulate precisely opening and closing of a position in indicator, that would fully replicate the opening and closing of a position in the tester?

Documentation on MQL5: Testing Trading Strategies / MQL5 programs
Documentation on MQL5: Testing Trading Strategies / MQL5 programs
  • www.mql5.com
The idea of automated trading is appealing by the fact that the trading robot can work non-stop for 24 hours a day, seven days a week. The robot...
 
Dimitr Trifonov #:

Also maybe anyone can suggest a way to simulate precisely opening and closing of a position in indicator, that would fully replicate the opening and closing of a position in the tester?

Thank you for posting that info and a link to it. I did some additional reading there...

"Tick data may not coincide with minute bars for various reasons, for example because of connection losses or other failures when transmitting data from a source to the client terminal. The minute data is considered more reliable during tests" (emphasis added).

To me, that sounds like an outright warning about testing based on ticks in the MT5 Tester. The log that you posted in your OP confirms it.

 
Dimitr Trifonov #:

Thank you for your responses.

I call my function this way

So I expect this line

to return all ticks for the current/last/most-recent bar.

My guess is that the ticks in the tester may not be the same as the ticks used by CopyTicks(), even when the ticks modelling in the tester is "Every tick based on real ticks"

https://www.mql5.com/en/docs/runtime/testing

My initial goal is to simulate open and close positions for one of my indicators which is on the Market. It works fine, however there minor discrepancies between running the indicator in the tester and just adding the indicator on the chart.

1.Did anyone used CopyTicksRange() in the tester and face any problems like this?

2.Also maybe anyone can suggest a way to simulate precisely opening and closing of a position in indicator, that would fully replicate the opening and closing of a position in the tester?

Expecting and guessing is not how programming is working. You need to check.

Please post the log file of your backtest.

 

The log is in my first post:

2026.01.01 20:01:08.708 2025.09.30 09:23:20   bar = 0 maxAsk = 1.17397 start = 2025.09.30 09:00:00 copiedTicks = 1365

So this line of code

int copiedTicks=CopyTicksRange(GetSymb(),mqlTick,COPY_TICKS_INFO,(ulong) start * 1000);

returns 1365 ticks, highest has value 1.17397. The tester is logging the event at 2025.09.30 09:23:20, start of CopyTicksRange is 2025.09.30 09:00:00 testing on H1 timeframe. So all ticks are from the current/last bar.

However next the stop loss is triggered at Ask price (1.17406) that is not in the list returned by CopyTicksRange

order performed buy 0.3 at 1.17406 [#4 buy 0.3 EURUSD at 1.17406]

Next, the function logs maxAsk 1.17398 which is lower than 1.17406

2026.01.01 20:01:08.714 2025.09.30 09:23:20   bar = 0 maxAsk = 1.17398 start = 2025.09.30 09:00:00 copiedTicks = 1366

Log posted here is the same for 

'Every tick based on real ticks' and

'Every tick, same results'

 
Dimitr Trifonov #:

The log is in my first post:

So this line of code

returns 1365 ticks, highest has value 1.17397. The tester is logging the event at 2025.09.30 09:23:20, start of CopyTicksRange is 2025.09.30 09:00:00 testing on H1 timeframe. So all ticks are from the current/last bar.

However next the stop loss is triggered at Ask price (1.17406) that is not in the list returned by CopyTicksRange

Next, the function logs maxAsk 1.17398 which is lower than 1.17406

Log posted here is the same for 

'Every tick based on real ticks' and

'Every tick, same results'

A last try, I asked you the log FILE, not an excerpt of it.

Forum on trading, automated trading systems and testing trading strategies

CopyTicksRange() in tester

Alain Verleyen, 2026.01.02 19:53

Expecting and guessing is not how programming is working. You need to check.

Please post the log file of your backtest.


 
Alain Verleyen #:

A last try, I asked you the log FILE, not an excerpt of it.


.
Files:
20260101.log  179 kb
 
Dimitr Trifonov #:
.
Thanks, checking...