Особенности языка mql5, тонкости и приёмы работы - страница 334

 
amrali #:
Вы не можете открыть сделку в пятницу, 03.04.2026, так как рынок закрыт (Страстная пятница перед Пасхальным воскресеньем).

Иногда могу открыть/закрыть.


Считаю, что 5/6 результатов ниже правильные.

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)); // 54000
  Print(HOLIDAY::GetDealLength_Cached(OpenTime1, CloseTime1)); // 54000

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

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

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

  Print(HOLIDAY::GetDealLength(OpenTime3, CloseTime3)); // 54000
  Print(HOLIDAY::GetDealLength_Cached(OpenTime3, CloseTime3)); // -32400
}
 
fxsaber #:

Я считаю, что 5 из 6 приведенных ниже результатов верны.


Исправление:

  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;
  }

Результат:

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
}
Файлы:
Holiday4.mq5  16 kb
 
amrali #:

Исправление:

Да, теперь совпадает.


Я взял реальную задачу, когда в конце бэктеста нужно посчитать длительность всех позиций. Сохранил Open/Close-время позиций в массив. И прогнал на нем следующий скрипт.

void OnStart()
{
  int Times[];
  const int Size = (int)FileLoad("Times.bin", Times); // https://c.mql5.com/3/490/Times.zip
  
  Print(Size >> 1); // 324865 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: Benchmark cached
  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
}

В подобных задачах нужен только однократный проход по всем позициям, поэтому не удалось получить преимущество через кеширование. Наверное, тут могут помочь только вшитые в код до компиляции табличные данные. Но бороться за половину миллисекунды, наверное, не стоит. Спасибо за исследование!


ЗЫ Благодаря Вам обнаружил у себя ошибку.

#include <fxsaber\BestInterval\Holiday.mqh>

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

  Print(HOLIDAY::GetDealLength(OpenTime1, CloseTime1)); // 3600

  const datetime OpenTime2 = D'2026.04.03 03:00';
  const datetime CloseTime2 = D'2026.04.06 02:00';    

  Print(HOLIDAY::GetDealLength(OpenTime2, CloseTime2)); // 82800
}
Еще раз спасибо.
Файлы:
Times.zip  888 kb