В MT4-тестере одиночный прогон в ~10 раз медленнее, чем в режиме оптимизации

 

ТС в режиме оптимизации в ~10 (на глаз) раз быстрее вычисляется, чем в одиночном прогоне.

В логи ничего не принтую. Пробовал сделать read-only SSD-папку tester/logs/ - не помогает.

Под конец прогона OrdersHistoryTotal() ~1200, количество модификаций ~500К.

Как сделать, чтобы одиночный прогон не тормозил?

 

Для МТ4. Если одиночный прогон без визуализации , то по идее время на тестирование и один проход оптимизации не должны сильно отличаться. Наблюдал  разность времен вычислений тестера и тестера в режиме оптимизации у ТС использующих генератор случайных чисел.

Для МТ5 не знаю. Знаю что там оптимизация распределяется параллельно по ядрам.

 

Набросал советник для тестирования производительности тестера:

#property strict

input int AmountSystems = 10;
input int Step = 100;
input double Lots = 0.1;

ulong MicrosecondCount;
int handle = 0;

void OnInit( void )
{
//  if (!IsOptimization())
  {
    handle = FileOpen(WindowExpertName() + ".txt", FILE_WRITE | FILE_IS_TEXT);

    MicrosecondCount = GetMicrosecondCount();
  }

  return;
}

void OnDeinit( const int Reason )
{
  if (handle > 0)
    FileClose(handle);

  return;
}

bool GetOrder( const int MagicNumber )
{
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS))
      if (OrderMagicNumber() == MagicNumber)
        return(TRUE);

  return(FALSE);
}

void System( int &AmountBars )
{
  for (int i = 0; i < AmountSystems; i++)
    if (AmountBars % AmountSystems == i)
    {
      if (GetOrder(i))
        OrderClose(OrderTicket(), OrderLots(), Bid, 0);

      OrderSend(Symbol(), OP_BUY, Lots, Ask, 0, 0, 0, NULL, i);
    }
    else if (GetOrder(i))
      OrderModify(OrderTicket(), OrderOpenPrice(), OrderStopLoss(), OrderOpenPrice() * 2 * (i %2 ), 0);

  AmountBars++;

  return;
}

#define MILLION 1000000.0

void Bench( const int AmountBars )
{
  static int PrevHistoryTotal = 0;
  static int PrevAmountBars = 0;

  if (handle <= 0)
    return;

  const int HistoryTotal = OrdersHistoryTotal();

  if (HistoryTotal > PrevHistoryTotal + Step)
  {
    const ulong NewMicrosecondCount = GetMicrosecondCount();

    const double Velocity = MILLION * (AmountBars - PrevAmountBars) / (NewMicrosecondCount - MicrosecondCount);

    FileWrite(handle, (string)HistoryTotal + " " + (string)Velocity);

    MicrosecondCount = NewMicrosecondCount;

    PrevHistoryTotal = HistoryTotal;
    PrevAmountBars = AmountBars;
  }

  return;
}

void OnTick( void )
{
  static datetime PrevTime = 0;
  static int AmountBars = 0;

  if (PrevTime == Time[0])
    return;

  PrevTime = Time[0];

  System(AmountBars);
  Bench(AmountBars);

  return;
}

Результат "по ценам открытия":

На графике зависимость производительности тестера (баров в секундуд) от количества ордеров в истории. Хорошо видно, что при оптимизации производительность в разы выше, чем при одиночном прогоне. Также у тестера проваливается на ~30% производительно аккурат, как переваливает 10К ордеров в истории, и аж в ~5 еще раз, когда число ордеров в истории переваливает точненько 100К штук. В режиме включенной оптимизации ничего подобного не происходит -производительность на зависит от числа ордеров в историию.

Воспроизводится эта картина каждый раз. Каждый может убедиться. На других же ТС, как сказал выше, всего при 1200 ордеров и 500К модификаций скорость падает в одиночном прогоне в ~10 раз.

Как победить?

ЗЫ Присмотрелся к красному графику (тестер в режиме оптимизации). Там провал производительности происходит при увеличении числа ордеров на истории четко на 50К штук. Но потом скорость восстанавливается к прежним значениям.

 
Не совсем понимаю стиль написания тестера, когда в его исходник жестко прописываются круглые человеческие числа: 10К, 50К, 100К... Попахивает не хорошим проявлением человеческого фактора.
 
zaskok3:

ТС в режиме оптимизации в ~10 (на глаз) раз быстрее вычисляется, чем в одиночном прогоне.

В логи ничего не принтую. Пробовал сделать read-only SSD-папку tester/logs/ - не помогает.

Под конец прогона OrdersHistoryTotal() ~1200, количество модификаций ~500К.

Как сделать, чтобы одиночный прогон не тормозил?

При единичном прогоне в МТ4 используется одно ядро ЦП, а при оптимизации - сразу несколько ядер. Отсюда и разница в скорости (да, мт4 тоже тоже может использовать несколько ядер!). 

 
Vasiliy Sokolov:

При единичном прогоне в МТ4 используется одно ядро ЦП, а при оптимизации - сразу несколько ядер. Отсюда и разница в скорости (да, мт4 тоже тоже может использовать несколько ядер!). 

В данном случае не может, т.к. оптимизация мнимая: количество вариантов для оптимизации задаю в виде один штука. Предварительно, конечно, избавившись от кэшей оптимизатора.

 
zaskok3:

В данном случае не может, т.к. оптимизация мнимая: количество вариантов для оптимизации задаю в виде один штука. Предварительно, конечно, избавившись от кэшей оптимизатора.

Не воспроизводится. При единичном прогоне время оптимизации стандартного советника MovingAverage занимает около 4-5 секунд (все тики, 1 год). При оптимизации с еденичным прогоном время примерно тоже - 4 секунды. 

 
Единичный прогон может быть медленнее единичной оптимизации, т.к. в первом случае требуется также сгенерировать график баланса и отчет (графические функции весьма медленные). В любом случае, десятикратная разница не воспроизводится.
 
zaskok3:

Набросал советник для тестирования производительности тестера:

Ваш советник весьма странно работает в тестере. Первый раз при единичном прогоне действительно прогоняется достаточно медленно. Но со второго прогона начинает работать гораздо быстрее. Прогоняется до половины, а затем моментально завершает оставшуюся часть.
 
Vasiliy Sokolov:
Ваш советник весьма странно работает в тестере. Первый раз при единичном прогоне действительно прогоняется достаточно медленно. Но со второго прогона начинает работать гораздо быстрее. Прогоняется до половины, а затем моментально завершает оставшуюся часть.

Скорее всего, эквити около нуля, вот и реакция. Увеличьте начальный баланс.

А скорость можно увидеть в текстовом файле в папке tester/files/. По нему и строил график выше. Разница в разы будет не только ощущаться, но и подкрепляться конкретными цифрами.

Vasiliy Sokolov:
Единичный прогон может быть медленнее единичной оптимизации, т.к. в первом случае требуется также сгенерировать график баланса и отчет (графические функции весьма медленные). В любом случае, десятикратная разница не воспроизводится.
Если не переключаться на вкладку "График", то генерироваться он не будет. Однако, данные по каждой модификации будут сохраняться. Представим, что надо сохранить 500К модификаций. Для этого же достаточно выделить память и просто заполнять массив. Никаких доп. расчетов не требуется по сравнению с включенной оптимизацией. Только еще один массив хранить. Ну и разница в разы даже на тестовом советнике наблюдается хорошо.
 

Заставил обратить внимание на тормоза тестера следующий случай. Стратегии пишу в виде классов. И вот захотелось посмотреть, как выглядит объединенная ТС из нескольких таких стратегий. Для этого было достаточно создать несколько соответствующих объектов, получив очередное удовольствие от удобства ООП. Объединил все пять ТС таким образом в одну. Запустил одиночный прогон и.... вместо пятикратного увеличения времени, получил замедление в сотни раз: 40 минут тестер делал прогон, при этом никак не реагирую на нажатия ("Не отвечает"). Однако, не стал убивать его, т.к. видно было, что в tester/logs он все же пишет. Дождался. Получил, как и ожидал, в конце профит в виде суммы профита пяти соответствующих ТС. Но какой ценой!

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

Причина обращения: