Issue with Loading Previous Data using CopyTime() in MQL5

 

Hi,
I'm developing a custom indicator in MQL5 that uses CopyTime() to get timestamps of previous candles in the daily timeframe (D1). The problem is that after restarting MetaTrader, it seems that previous data is not loaded, and CopyTime() returns -1 .

I have tried the following solutions, but none of them worked :


Checking SeriesInfoInteger(Symbol(), PERIOD_D1, SERIES_SYNCHRONIZED) before calling CopyTime() 

Increasing Max bars in chart from MetaTrader settings

Using ChartRedraw() 

Clearing the cache and reloading historical data.


Has anyone experienced a similar issue? How can I ensure that previous data is loaded when restarting MetaTrader?

Thanks for your help!

 
Behzad Hajipoor:

Hi,
I'm developing a custom indicator in MQL5 that uses CopyTime() to get timestamps of previous candles in the daily timeframe (D1). The problem is that after restarting MetaTrader, it seems that previous data is not loaded, and CopyTime() returns -1 .

I have tried the following solutions, but none of them worked :


Checking SeriesInfoInteger(Symbol(), PERIOD_D1, SERIES_SYNCHRONIZED) before calling CopyTime() 

Increasing Max bars in chart from MetaTrader settings

Using ChartRedraw() 

Clearing the cache and reloading historical data.


Has anyone experienced a similar issue? How can I ensure that previous data is loaded when restarting MetaTrader?

Thanks for your help!

Hello , are you requesting D1 for the same symbol ?

 
Lorentzos Roussos #:

Hello , are you requesting D1 for the same symbol ?

Thank you, Lorentzos , for your response

Yes, the time frame is D1, and it’s the same symbol. I have noticed that the CopyTime function fails when executed on the first tick but works correctly on the second tick. As a result, it cannot be used when the market is closed, especially in OnInit() .

Ideally, I want CopyTime to run only once and not be called again. Since it cannot be used in OnInit , I designed my program so that it executes CopyTime once in OnCalculate and ensures it does not run on subsequent ticks.

I'll provide the related codes for the written function below, with the explanation that this function runs in OnCalculate , returns false on the first tick, and executes correctly on the second tick. Therefore, when the market is closed, this function will always return false . 

bool copytimeFunction(void)
  {
   int loctemp ;
   bool LocFlag = false ;


   for(int i = 0; i < 10; i++)
     {
      ResetLastError();
      // loctemp = CopyTime(_Symbol, PERIOD_D1, 0, BarsDay, AllDays);
      loctemp = CopyTime(_Symbol, PERIOD_D1, StartDate, BarsDay, AllDays);

      if(loctemp < 0)
        {
         Print("❌ CopyTime failed. No data available!");
         Print(__FUNCTION__,
               "-Error on CopyTime AllDays Array is = ", GetLastError());
               ChartRedraw(0);
        }
      else
        {
         LocFlag = true ;
         break ;
        }
     }

   if(loctemp < 0)
     {
      Print("Error on CopyTime ");

     }
   else
     {

      if(Drawing(0) != true)
        {
         Print("Error on Drawing ");
        }
     }

   return LocFlag ;
  }
 
Behzad Hajipoor #:
StartDate, BarsDay, AllDays

Using a loop to call CopyTime repeatedly seems odd and probably wrong - why are you doing this? 

The reason is probably that the COPYtime function does not copy data as fast. If you need to copy a completely fixed amount of history on the first call without going further before the data is loaded to the buffer then you can use the loop and iTime function instead of CopyTime. iSeries functions act like wrappers of CopySeries functions. This method is a slower than directly using the CopySeries functions but you can check the result return using an iterator where the iterator represents the amount of data need to be loaded. If running value of iterator reaches desired amount of data then return true. Using both, CopyTime or iTime functions ,when starting the program, load the required history. During the checks, don't reload the whole history but load the missing part of the history. start_time or start_pos == loaded history. 

 
Behzad Hajipoor #:

Thank you, Lorentzos , for your response

Yes, the time frame is D1, and it’s the same symbol. I have noticed that the CopyTime function fails when executed on the first tick but works correctly on the second tick. As a result, it cannot be used when the market is closed, especially in OnInit() .

Ideally, I want CopyTime to run only once and not be called again. Since it cannot be used in OnInit , I designed my program so that it executes CopyTime once in OnCalculate and ensures it does not run on subsequent ticks.

I'll provide the related codes for the written function below, with the explanation that this function runs in OnCalculate , returns false on the first tick, and executes correctly on the second tick. Therefore, when the market is closed, this function will always return false . 

This is old and known issue, you can search the forum about it.

It's expected behaviour following the platform design, you need to find a way to deal with it, and using a loop is not a good one. I recommend using a timer.

 
Behzad Hajipoor #:

Thank you, Lorentzos , for your response

Yes, the time frame is D1, and it’s the same symbol. I have noticed that the CopyTime function fails when executed on the first tick but works correctly on the second tick. As a result, it cannot be used when the market is closed, especially in OnInit() .

Ideally, I want CopyTime to run only once and not be called again. Since it cannot be used in OnInit , I designed my program so that it executes CopyTime once in OnCalculate and ensures it does not run on subsequent ticks.

I'll provide the related codes for the written function below, with the explanation that this function runs in OnCalculate , returns false on the first tick, and executes correctly on the second tick. Therefore, when the market is closed, this function will always return false . 

Just think about it from the servers perspective , it has to find the data you requested and send it to you.

So on the second -third check you might get the data you need.

 
Behzad Hajipoor #:

Thank you, Lorentzos , for your response

Yes, the time frame is D1, and it’s the same symbol. I have noticed that the CopyTime function fails when executed on the first tick but works correctly on the second tick. As a result, it cannot be used when the market is closed, especially in OnInit() .

Ideally, I want CopyTime to run only once and not be called again. Since it cannot be used in OnInit , I designed my program so that it executes CopyTime once in OnCalculate and ensures it does not run on subsequent ticks.

I'll provide the related codes for the written function below, with the explanation that this function runs in OnCalculate , returns false on the first tick, and executes correctly on the second tick. Therefore, when the market is closed, this function will always return false . 

anyhow , maybe try this approach 

#property indicator_chart_window
bool PINGER=false;
bool READY=false;
input int MinimumDaysRequired=10;//minimum days required
datetime PINGER_from=0,PINGER_to=0;
datetime DAYS[];
int OnInit()
  {
  READY=false;
  PINGER=false;
  PINGER_from=0;
  PINGER_to=0;
  ArrayFree(DAYS);
  return(INIT_SUCCEEDED);
  }

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
  if(prev_calculated==0&&!READY){
    PINGER=true;
    EventSetMillisecondTimer(55);
    }
  return(rates_total);
  }

void OnTimer()
  {
  if(SymbolIsSynchronized(_Symbol)){
    if(CopyTime(_Symbol,_Period,0,1,DAYS)==1){
      PINGER_to=DAYS[0];
      ResetLastError();
      int total=iBars(_Symbol,_Period);
      if(total>1&&GetLastError()==0){       
        for(int i=0;i<total;i++){
        ResetLastError();
        datetime gt=iTime(_Symbol,_Period,i);
        if(GetLastError()==0){
          PINGER_from=gt;
          }
          }
        if(PINGER_from<PINGER_to){
          if(CopyTime(_Symbol,PERIOD_D1,PINGER_from,PINGER_to,DAYS)>MinimumDaysRequired){
            READY=true;
            PINGER=false;
            EventKillTimer();
            Print("Collected "+IntegerToString(ArraySize(DAYS))+" days");
            Print("Frist date "+TimeToString(DAYS[0],TIME_DATE|TIME_MINUTES|TIME_SECONDS));
            Print("Lsat date "+TimeToString(DAYS[ArraySize(DAYS)-1],TIME_DATE|TIME_MINUTES|TIME_SECONDS));
            }
          }
        }
      }
    }
  }

void OnDeinit(const int reason){
if(PINGER){
EventKillTimer();
}}
 
no argument at all, timer set according to the amount of data is probably the best choice in this situation where speed is priority. Commendation for this previous code and thanks to the author ! 

But , if accurate data volume needed and execution speed is not a priority we can do it more easily too...

(I use this solution myself for optimization , which then runs max once per a week)
ArrayResize(time, datasize);
for (int i = datasize - 1; i >= 0; i--) { time[i] = iTime (NULL, timeframe, datasize - i); }

The execution time difference is of course insane compared to directly using CopyTime but the loop does not allow the following functions to run until all data is loaded. a cheap and foolproof solution if you need to spend 15000 microseconds instead of 500 microseconds :)  Moreover, an incorrectly set timer can make data collection even much slower. No matter how the data is harvested , if the volume of data is very large, the key is not to reload all the data each time, but to load only the last missing data. 

cheers...