Features of the mql5 language, subtleties and tricks - page 335

 
amrali #:
You cannot open a trade on Friday, 3 April 2026, as the market is closed (Good Friday, the day before Easter Sunday).

Sometimes I can open or close a trade.


I believe that 5 out of 6 of the results below are correct.

void OnStart()
{
  const datetime OpenTime1 = D'2026.04.02 11:00';
  const datetime CloseTime1 = D'2026.04.03 02:00';    

  Print(HOLIDAY::GetDealLength(OpenTime1, CloseTime1)); // 54,000
  Print(HOLIDAY::GetDealLength_Cached(OpenTime1, CloseTime1)); // 54,000

  const datetime OpenTime2 = D'2026.04.02 11:00';
  const datetime CloseTime2 = D'2026.04.06 02:00';    

  Print(HOLIDAY::GetDealLength(OpenTime2, CloseTime2)); // 54,000
  Print(HOLIDAY::GetDealLength_Cached(OpenTime2, CloseTime2)); // 54,000

  const datetime OpenTime3 = D'2026.04.03 11:00';
  const datetime CloseTime3 = D'2026.04.06 02:00';    

  Print(HOLIDAY::GetDealLength(OpenTime3, CloseTime3)); // 54,000
  Print(HOLIDAY::GetDealLength_Cached(OpenTime3, CloseTime3)); // -32,400
}
 
fxsaber #:

I believe that 5 out of 6 of the results below are correct.


Correction:

  static int GetDealLength_Cached(
    datetime openTime,
    datetime closeTime)
  {
    int totalSeconds =
      (int)(closeTime - openTime);

    int a = DayIndex(openTime + DAY - 1 - Epoch);
    int b = DayIndex(closeTime - Epoch);

    int holidays = Prefix[b] - Prefix[a];

    return totalSeconds - holidays * DAY;
  }

Result:

void OnStart()
{
  const datetime OpenTime3 = D'2026.04.03 11:00';
  const datetime CloseTime3 = D'2026.04.06 02:00';    

  Print(HOLIDAY::GetDealLength(OpenTime3, CloseTime3)); // 54,000
  Print(HOLIDAY::GetDealLength_Cached(OpenTime3, CloseTime3)); // 54,000
}
Files:
Holiday4.mq5  16 kb
 
amrali #:

Correction:

Yes, it matches now.


I took a real-world problem where, at the end of a backtest, you need to calculate the duration of all positions. I stored the Open/Close times of the positions in an array and ran the following script on it.

void OnStart()
{
  int Times[];
  const int Size = (int)FileLoad("Times.bin", Times); // https://c.mql5.com/3/490/Times.zip
  
  Print(Size >> 1); // 324,865 positions.

  // Loop 1: Benchmark (non-cached)
  ulong sum1 = 0;
  ulong t1 = GetMicrosecondCount();
  
  for (int i = 0; i < Size; i++)
  {
    const datetime OpenTime = Times[i++];
    const datetime CloseTime = Times[i];
    
    sum1 += HOLIDAY::GetDealLength(OpenTime, CloseTime);
  }

  // GetDealLength: 582 microsec (sum = 187295981)
  PrintFormat("GetDealLength: %llu microsec (sum = %llu)", GetMicrosecondCount() - t1, sum1);

  // Loop 2: Cached benchmark
  ulong sum2 = 0;
  ulong t2 = GetMicrosecondCount();
  for (int i = 0; i < Size; i++)
  {
    const datetime OpenTime = Times[i++];
    const datetime CloseTime = Times[i];
    
    sum2 += HOLIDAY::GetDealLength_Cached(OpenTime, CloseTime);
  }

  // GetDealLength_Cached: 1046 microsec (sum = 187295981)
  PrintFormat("GetDealLength_Cached: %llu microsec (sum = %llu)", GetMicrosecondCount() - t2, sum2);

  Print("CORRECT: ", sum1 == sum2); // true
}

In tasks like this, you only need a single pass through all the positions, so I couldn’t gain any performance benefit from caching. I suppose the only thing that might help here is table data hard-coded into the source before compilation. But it’s probably not worth fighting over half a millisecond. Thanks for the research!

Files:
Times.zip  888 kb