MT4 bug: TimeCurrent() is not in sync with ArrayCopyRates() (might be present in MT5 too)

 

This one caused me a lot of trouble, as it happens randomly... I had missed quite some trades because of this bug, but thanks to some logs I have found it in the end.

The time in yellow is the time of the computer, while the time in red is the time of the last candle. There is also a third time accessible to EAs through the TimeCurrent() function: the current time of the broker -- closely related to the computer time (apart from the timezone difference). If an EA is using this time information to check if the market has stepped into a new period, it can fail from time-to-time, as this information is not in sync with the candle information provided by the terminal (the time values in red).

In the example below, the difference between the yellow times is >1 hour... still the system is presenting for the EA the same candle as the last at both times:
01:59:02 test EURCAD,H1: [03.01 09:00] close=1.34561
02:59:59 test EURCAD,H1: [03.01 09:00] close=1.34561
The following sample code might help reproducing the bug (the original code is way too large to present it here):
void test() {
    static datetime lastTime=0;
    datetime currentTime = getBarTime(TimeCurrent(), Period());
    if(lastTime != currentTime) {
        lastTime = currentTime;
        double rates[][6];
        ArrayCopyRates(rates, NULL, PERIOD_H1);
        Print("last bar: [", TimeToStr(rates[0][0]), "] close=", rates[0][4]);        
    }
}

datetime getBarTime(datetime time, int timeFrame) {
    int seconds = timeFrame * 60;
    //int seconds = timeFrame; // MT5
    return(time - (time % seconds)); // floor(time / seconds) * seconds;
}

 This is clearly a MT4 bug, as a workaround one can use iTime() instead of the above getBarTime() -- however iTime() is bar count dependent: for smaller periods backtest can fail

datetime currentTime = iTime(NULL, timeFrame, 0);

 

 
Try calling ACR once in init
   //{https://www.mql5.com/en/forum/129734/page2 says ArrayCopyRates is a nonreentrant,
   // non-thread-safe call. Therefor you must put a mutex around the call in
   // case of multiple EAs on multiple charts. Alteratively, since init() is
   // single threaded across all charts, put all ACRs there.
   //}
   ArrayCopyRates(acr.arr, market.pair, period.market);     // I'm in an OnInit.
Reason: