Bar (Time) lag in CopyRates on symbol other then current chart in open prices only mode.

 

Take the following EA:

#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

input string inSymbolA = "EURUSD";
input string inSymbolB = "GBPUSD";

datetime MinLag = INT_MAX;

int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
  
void OnDeinit(const int reason)
  {
  Print ("********************");  
  Print ("* Minial Lag ", TimeToString(MinLag,TIME_MINUTES)," *");
  Print ("********************");  
  }

void OnTick()
  {
   if (!IsNewBar(inSymbolA,PERIOD_CURRENT))
      return;
      
   MqlRates RatesA[],RatesB[];
   
   CopyRates(inSymbolA,PERIOD_CURRENT,0,1,RatesA);  // Get last bar
   CopyRates(inSymbolB,PERIOD_CURRENT,0,1,RatesB);  // Get last bar

   datetime Difference =  RatesA[0].time - RatesB[0].time; // Calculate the time difference
   
   if (Difference<MinLag)
    MinLag = Difference;

   
  }

// Detects when a "new bar" occurs, which is the same as when the previous bar has completed.
bool IsNewBar(const string symbol, const ENUM_TIMEFRAMES period)
{
        bool isNewBar = false;
        static datetime priorBarOpenTime = NULL;

        // New Bar event handler -> per https://www.mql5.com/en/articles/159
        // SERIES_LASTBAR_DATE == Open time of the last bar of the symbol-period
        const datetime currentBarOpenTime = (datetime) SeriesInfoInteger(symbol,period,SERIES_LASTBAR_DATE);

        if( priorBarOpenTime != currentBarOpenTime )
        {
                // Don't want new bar just because EA started
                if ( priorBarOpenTime == NULL )
                {
                        isNewBar = false;
                }
                else
                {
                        isNewBar = true;
                }
                // isNewBar = ( priorBarOpenTime == NULL )?false:true;  // priorBarOpenTime is only NULL once

                // Regardless of new bar, update the held bar time
                priorBarOpenTime = currentBarOpenTime;
        }

        return isNewBar;
}

When run with these settings:

The result a lag of 30 minutes on M30 timeframe, 1 bar. This happens from M1 to M30, on H1 there is zero lag. Haven't tested the rest but i reckon this will be 0 as wel.

2022.12.08 18:05:44.025 2022.12.05 23:59:59   ********************
2022.12.08 18:05:44.025 2022.12.05 23:59:59   * Minial Lag 00:30 *
2022.12.08 18:05:44.025 2022.12.05 23:59:59   ********************

Same result with different builds.

In every tick based on real, lag is always zero as one would expect.

Am i missing something here? Flaw in my code logic perhaps?

 

You are not checking CopyRates for a return status nor any error checking if they fail.

Remember that you have to synchronise data for other symbols other than the chart symbol.

Documentation on MQL5: Timeseries and Indicators Access / Organizing Data Access
Documentation on MQL5: Timeseries and Indicators Access / Organizing Data Access
  • www.mql5.com
Organizing Data Access - Timeseries and Indicators Access - MQL5 Reference - Reference on algorithmic/automated trading language for MetaTrader 5
 
Fernando Carreiro #:

You are not checking CopyRates for a return status nor any error checking if they fail.

Remember that you have to synchronise data for other symbols other than the chart symbol.

Isn't the data in tester always sycnronized? 

 

Turn the MinLag to an int .

Run twice once as is and once with the symbols flipped.

If you get 30*60(secs) on one pass and -30*60 on the second its probably not an error .  

edit : Although you could get 0 on the second run because it executes on OnTick
 
Enrique Dangeroux #: Isn't the data in tester always sycnronized? 

Not necessarily. If the EA is multi-symbol, the first time you run it, it may need to download the extra data. Only on the second run may it be already synchronised if nothing has changed.

However, that is besides the point. You should check return status, check for errors and carry out synchronisation anyway for when it goes live.

 

The Ea limits calculaton on the new bar condition of symbol A.

Essentially datetime is an int. I havent encountered any negative "lag" with any of my tests.

I tried flipping the symbols, So instead of running on EURUSD M1 chart, flip symbol A and B and run on GBPUSD. The result is zero, so there is a difference compared to the default on EURUSD M1 chart (which shows a lag of 1 bar. 1 minute in this example).
 
Fernando Carreiro #:

Not necessarily. If the EA is multi-symbol, the first time you run it, it may need to download the extra data. Only on the second run may it be already synchronised if nothing has changed.

However, that is besides the point. You should check return status, check for errors and carry out synchronisation anyway for when it goes live.

I understand. However the issue i have and the example code is with the tester, not the terminal. 

 
Enrique Dangeroux #:The Ea limits calculaton on the new bar condition of symbol A. Essentially datetime is an int. I havent encountered any negative "lag" with any of my tests.I tried flipping the symbols, So instead of running on EURUSD M1 chart, flip symbol A and B and run on GBPUSD. The result is zero, so there is a difference compared to the default on EURUSD M1 chart (which shows a lag of 1 bar. 1 minute in this example).

Have you considered the possibility of missing bars due to no tick activity during that timespan?

 
Fernando Carreiro #:

Have you considered the possibility of missing bars due to no tick activity during that timespan?

that must be it , if he measures max delta b2in ticks of symbols (latest one of the lagging symbol) it will be way less than 30 mins

Enrique Dangeroux #:

The Ea limits calculaton on the new bar condition of symbol A.

Essentially datetime is an int. I havent encountered any negative "lag" with any of my tests.

I tried flipping the symbols, So instead of running on EURUSD M1 chart, flip symbol A and B and run on GBPUSD. The result is zero, so there is a difference compared to the default on EURUSD M1 chart (which shows a lag of 1 bar. 1 minute in this example).

When you say 0 you mean it prints zero or it prints nothing ? 

 
Fernando Carreiro #:

Have you considered the possibility of missing bars due to no tick activity during that timespan?

Yes. On M1 there can be missing bars so dalays up to 40 minutes on some symbols. But the test accomodates for that by taking the leeast amount of lag accross all bars within the specefied tester timespam. Equeal timestamps of the bars means, there is zero lag, the timestamps are equal the EA will print the least measuered lag.

When running on 1M, timespan of 24 hours of test data approx 1440 bars are taken into considration. On my end with the default setting on EURUSD M1 chart the least amount of lag measured is 1 minute == 1 bar. same goes for timeframes up to M30 = 30 minutes lag == 1 bar. 

When flipped the result is different. Zero lag, a timestamp of the two symbols at one point was equal.

Try running the EA with default parameters on EURUSD M1 open prices only mode, and post the result of the Deinit print. If the result is not reproduced, the issue is elsewhere. It could be the tick feed of which the open prices are constructed in the tester for example.

 

I get that too , on H1 as well 

#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

input string inSymbolA = "EURUSD";
input string inSymbolB = "GBPUSD";

datetime MinLag = INT_MAX;
int lagsum=0;
int bars_total=0,bars_with_difference=0;

int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
  
void OnDeinit(const int reason)
  {
  Print ("********************");  
  Print ("* Minial Lag ", TimeToString(MinLag,TIME_MINUTES)," *");
  Print("Bars with difference ",IntegerToString(bars_with_difference),"/",IntegerToString(bars_total));
  Print("Average lag ",DoubleToString(((double)lagsum/((double)bars_total)),2)+".secs");
  Print ("********************");  
  }

void OnTick()
  {

   if (!IsNewBar(inSymbolA,PERIOD_CURRENT))
      return;
      
   MqlRates RatesA[],RatesB[];
   
   CopyRates(inSymbolA,PERIOD_CURRENT,0,1,RatesA);  // Get last bar
   CopyRates(inSymbolB,PERIOD_CURRENT,0,1,RatesB);  // Get last bar

   int Difference =  (int)RatesA[0].time - (int)RatesB[0].time; // Calculate the time difference
   
   bars_total++;
   lagsum+=Difference;
   if(Difference>0){
   bars_with_difference++;
   }
   if (Difference<MinLag)
    MinLag = Difference;

   
  }

// Detects when a "new bar" occurs, which is the same as when the previous bar has completed.
bool IsNewBar(const string symbol, const ENUM_TIMEFRAMES period)
{
        bool isNewBar = false;
        static datetime priorBarOpenTime = NULL;

        // New Bar event handler -> per https://www.mql5.com/en/articles/159
        // SERIES_LASTBAR_DATE == Open time of the last bar of the symbol-period
        const datetime currentBarOpenTime = (datetime) SeriesInfoInteger(symbol,period,SERIES_LASTBAR_DATE);

        if( priorBarOpenTime != currentBarOpenTime )
        {
                // Don't want new bar just because EA started
                if ( priorBarOpenTime == NULL )
                {
                        isNewBar = false;
                }
                else
                {
                        isNewBar = true;
                }
                // isNewBar = ( priorBarOpenTime == NULL )?false:true;  // priorBarOpenTime is only NULL once

                // Regardless of new bar, update the held bar time
                priorBarOpenTime = currentBarOpenTime;
        }

        return isNewBar;
}
i'll do a programer's shot in the dark here . 
They have coded the ticks to come sequentially from each symbol and since open prices has one tick event it has no time to fire the rest of the symbols . 
Reason: