Question about unsynced bars read by CopyOpen/CopyRates/...

Hello,

I’ve encountered issues with the bar data retrieval functions—CopyRates, CopyOpen, Copy..., etc. I am running tests on 6–7 years of historical data using the "Strategy Tester." To get straight to the point: I’ve run into situations where the `OnTimer` event triggers and a bar is added—one that hasn't actually started generating yet—appearing at index 0 with identical Open and Close values. In other instances, that same bar is missing entirely, forcing me to rely on earlier bars that have already been processed. You might suggest implementing validation or time checks; I’ve already tried those approaches, which is why I’m posting here now. Is there a way to avoid this issue? Is there a function that forces bar synchronization? The last few times I debugged my bot using visual mode, I observed discrepancies: a bar would appear on the chart but be missing from the buffer, or conversely, a bar wouldn't have started drawing yet but would already exist in the buffer.

The bot runs alongside a ZigZag indicator, and shifting the data by 2–3 bars causes significant lag. I am testing on a one-hour timeframe.

Thanks in advance!

hi @Alexibg1000

Actually I’ve seen this behavior in MT5, especially when using ZigZag with the Strategy Tester.
CopyRates() may already return the new H1 bar at index 0, while ZigZag hasn’t finished updating its buffer yet. Because of that, shifting the data 2–3 bars isn’t a good solution—it can add unnecessary lag.


I’d check both the price series and indicator state before processing:


if(!SeriesInfoInteger(_Symbol, PERIOD_H1, SERIES_SYNCHRONIZED))

   return;

if(BarsCalculated(zigzag_handle) <= 0)

   return;


Also use iTime() to detect a new bar instead of comparing Open/Close values.
There isn’t a single function that forces everything to synchronize at exactly the same moment. It’s better to handle it as:
new bar → series ready → indicator calculated → CopyBuffer() → process
I use this kind of separation in MT5 EA development because it avoids unnecessary bar delays and makes tester behavior more predictable.

Alexibg1000 - Trader's profile
Alexibg1000 - Trader's profile
  • 2026.10.07
  • www.mql5.com
Trader's profile
Alexibg1000:

Hello,

I’ve encountered issues with the bar data retrieval functions—CopyRates, CopyOpen, Copy..., etc. I am running tests on 6–7 years of historical data using the "Strategy Tester." To get straight to the point: I’ve run into situations where the `OnTimer` event triggers and a bar is added—one that hasn't actually started generating yet—appearing at index 0 with identical Open and Close values. In other instances, that same bar is missing entirely, forcing me to rely on earlier bars that have already been processed. You might suggest implementing validation or time checks; I’ve already tried those approaches, which is why I’m posting here now. Is there a way to avoid this issue? Is there a function that forces bar synchronization? The last few times I debugged my bot using visual mode, I observed discrepancies: a bar would appear on the chart but be missing from the buffer, or conversely, a bar wouldn't have started drawing yet but would already exist in the buffer.

The bot runs alongside a ZigZag indicator, and shifting the data by 2–3 bars causes significant lag. I am testing on a one-hour timeframe.

Thanks in advance!

Insufficient information to get a useful answer.

You need to provide code, logs, settings, etc...

Vignesh Mani #:

hi @Alexibg1000

Actually I’ve seen this behavior in MT5, especially when using ZigZag with the Strategy Tester.
CopyRates() may already return the new H1 bar at index 0, while ZigZag hasn’t finished updating its buffer yet. Because of that, shifting the data 2–3 bars isn’t a good solution—it can add unnecessary lag.


I’d check both the price series and indicator state before processing:


if(!SeriesInfoInteger(_Symbol, PERIOD_H1, SERIES_SYNCHRONIZED))

   return;

if(BarsCalculated(zigzag_handle) <= 0)

   return;


Also use iTime() to detect a new bar instead of comparing Open/Close values.
There isn’t a single function that forces everything to synchronize at exactly the same moment. It’s better to handle it as:
new bar → series ready → indicator calculated → CopyBuffer() → process
I use this kind of separation in MT5 EA development because it avoids unnecessary bar delays and makes tester behavior more predictable.

Thanks for help! I don't think that there is a problem with a ZigZag. I tested it before adding bar data collection, and it worked perfect. After i started reading bar data, missmaches started appearing, and they are from bars. I will check the function SeriesInfoInteger :-) , i hope it will help me

Alexibg1000:
I’ve run into situations where the `OnTimer` event triggers and a bar is added—one that hasn't actually started generating yet—appearing at index 0 with identical Open and Close values. In other instances, that same bar is missing entirely,

What increment of time is your timer set at? 

Note that the relevant documentation states that:

In general, when the timer period is reduced, the testing time is increased, as the handler of timer events is called more often (https://www.mql5.com/en/docs/event_handlers/ontimer).

I experienced issues in the Tester while running a millisecond timer, so I conditionally switched back to OnTick() using MQLInfoInteger(MQL_TESTER).

As Alain Verleyen alluded, we're left to guess without details.

Alexibg1000 #:

Thanks for help! I don't think that there is a problem with a ZigZag. I tested it before adding bar data collection, and it worked perfect. After i started reading bar data, missmaches started appearing, and they are from bars. I will check the function SeriesInfoInteger :-) , i hope it will help me

SeriesInfoInteger is irrelevant for the Strategy Tester.
Ryan L Johnson #:

What increment of time is your timer set at? 

Note that the relevant documentation states that:

In general, when the timer period is reduced, the testing time is increased, as the handler of timer events is called more often (https://www.mql5.com/en/docs/event_handlers/ontimer).

I experienced issues in the Tester while running a millisecond timer, so I conditionally switched back to OnTick() using MQLInfoInteger(MQL_TESTER).

As Alain Verleyen alluded, we're left to guess without details.

Hi, I am using:
 In Init function: 

current_timeframe = PERIOD_H1;
EventSetTimer(PeriodSeconds(current_timeframe));

Then in OnTimer event, first thing i am doing is - getting bars info via CopyOpen/CopyClose and etc..., then processing that data. I tried both to sleep before getting bars like 2 minutes and to get difference between TimeCurrent() and rounded up time, but that also doesn't work as I expected. I thought if i wait to come next bar, it will be always on index 0, but it is not. 😃


Alexibg1000 #:
Hi, I am using:
 In Init function: 

current_timeframe = PERIOD_H1;
EventSetTimer(PeriodSeconds(current_timeframe));

Then in OnTimer event, first thing i am doing is - getting bars info via CopyOpen/CopyClose and etc..., then processing that data. I tried both to sleep before getting bars like 2 minutes and to get difference between TimeCurrent() and rounded up time, but that also doesn't work as I expected. I thought if i wait to come next bar, it will be always on index 0, but it is not. 😃

Sleep() merely adds to simulated trade execution latency in the Tester.

Alexibg1000:
The bot runs alongside a ZigZag indicator, and shifting the data by 2–3 bars causes significant lag.

The standard MT5 ZigZag indicator stores EMPTY_VALUE between confirmed historical pivots. Make sure that your EA code is filtering out those EMPTY_VALUE's prior to the EA saving a ZigZag indicator value.

Alexibg1000 #:

current_timeframe = PERIOD_H1;
EventSetTimer(PeriodSeconds(current_timeframe));

Then in OnTimer event, first thing i am doing is - getting bars info via CopyOpen/CopyClose and etc..., then processing that data. I tried both to sleep before getting bars like 2 minutes and to get difference between TimeCurrent() and rounded up time, but that also doesn't work as I expected. I thought if i wait to come next bar, it will be always on index 0, but it is not. 😃


Please, specify what you need (expect) exactly. The timer is not synced with bar formation in any way (because it's not 100% exact by its start-up time and periodic events due to OS and hardware implementation). Also you can't expect that every bar will start formation at specific moment inside the timeframe - bars are formed from ticks which can come at any second/minute/whatever unit or be missing for a while.
Stanislav Korotky #:
Please, specify what you need (expect) exactly. The timer is not synced with bar formation in any way (because it's not 100% exact by its start-up time and periodic events due to OS and hardware implementation). Also you can't expect that every bar will start formation at specific moment inside the timeframe - bars are formed from ticks which can come at any second/minute/whatever unit or be missing for a while.
My expectation was that after that Sleep, the next bar will be added on index 0. And i will know that everytime i have to start processing from index 1. 🙂 Without shifted/unshifted or "broken" bars.
Alexibg1000 #:
My expectation was that after that Sleep, the next bar will be added on index 0. And i will know that everytime i have to start processing from index 1. 🙂 Without shifted/unshifted or "broken" bars.

This is unclear. Every new bar is added at index 0, but this happens at arbitrary moment, not at the timer event.

What is your requirement?

PS&NB: the tester handles ticks/bars differently depending from the mode - you did not specify which you use.