Бета-версия платформы MetaTrader 5 build 2055: Интеграция с Python и массовые улучшения в тестере стратегий - страница 8

 

Долгое время не мог понять, почему у тестерного агента иногда сильно переполняется память,  и только теперь понял, что проблема в неэффективном механизме передачи фрэймов.  Все фрэймы, которые агент отсылает в процессе работы, просто копятся у него.   И только после завершения его работы вся это куча фрэймов отправляется адресату.  Это приводит к нерациональному расходованию памяти, а в случае передачи по сети - ещё и неравномерной её загрузке:  резкие всплески объёма трафика, что тоже негативно может сказываться, особенно если речь идёт об облаке.  Плюс пока агент накапливает у себя фрэймы, сам оптимизатор возможно простаивает без дела, хотя мог бы обрабатывать фрэймы.

Вот код, демонстрирующий, что все фрэймы отсылаются только по завершении работы агента:

#property tester_no_cache true

input int InputParam;

ulong __TickCount= GetTickCount();


bool SendFrameMessage(string name)
{ 
  char data[1000000];
  return FrameAdd(name, GetTickCount()-__TickCount, 0, data);
}


int OnInit()
  {
   SendFrameMessage("OnInit");
   return(INIT_SUCCEEDED);
  }
  
double OnTester()
  {
   SendFrameMessage("OnTester");
   return 0;
  }  

void OnDeinit(const int reason)
  {
   SendFrameMessage("OnDeinit");
   
   // Ждём 3 секунды
   for (uint t= GetTickCount();  GetTickCount()<t+3000; );

   SendFrameMessage("OnDeinit End");  
  }

//-----

void OnTesterInit()
  {
    Print("OnTesterInit");
  }

void OnTesterPass()
  {
   ulong  pass;
   string txt;
   long   time_ms;
   double value;
   char   data[];
   while( FrameNext(pass, txt, time_ms, value, data) )
     Print("Frame from agent ",pass,":  ",txt,",  ",time_ms," ms");
  }

void OnTesterDeinit()
  {
    Print("OnTesterDeinit");
    OnTesterPass();
  }

Запускаем оптимизацию в режиме "Математические вычисления", диапазон входного параметра от 0 до 1.  Получаем результаты:

2019.05.24 08:48:47.251 TestFrames (EURUSD,H1) OnTesterInit
2019.05.24 08:48:50.872 TestFrames (EURUSD,H1) Frame from agent 0:  OnInit,  15 ms
2019.05.24 08:48:50.873 TestFrames (EURUSD,H1) Frame from agent 0:  OnTester,  15 ms
2019.05.24 08:48:50.873 TestFrames (EURUSD,H1) Frame from agent 0:  OnDeinit,  15 ms
2019.05.24 08:48:50.874 TestFrames (EURUSD,H1) Frame from agent 0:  OnDeinit End,  3015 ms
2019.05.24 08:48:50.914 TestFrames (EURUSD,H1) Frame from agent 1:  OnInit,  0 ms
2019.05.24 08:48:50.914 TestFrames (EURUSD,H1) Frame from agent 1:  OnTester,  0 ms
2019.05.24 08:48:50.915 TestFrames (EURUSD,H1) Frame from agent 1:  OnDeinit,  0 ms
2019.05.24 08:48:50.916 TestFrames (EURUSD,H1) Frame from agent 1:  OnDeinit End,  3000 ms
2019.05.24 08:48:50.989 TestFrames (EURUSD,H1) OnTesterDeinit

Видим, что все фрэймы пришли одновременно, хотя отсылались с разницей в 3 секунды.


И кстати, ещё момент. Я задал  #property tester_no_cache true , чтобы исключить кэширование.  Однако в новом билде это не срабатывает, всё-равно кэширует, приходится перекомпилировать.  В прошлом билде работало нормально.

 
Alexey Navoykov:

OnTesterPass срабатывает только на первый фрейм. Правильно было бы через таймер делать проверку.

 
Alexey Navoykov:



И кстати, ещё момент. Я задал  #property tester_no_cache true , чтобы исключить кэширование.  Однако в новом билде это не срабатывает, всё-равно кэширует, приходится перекомпилировать.  В прошлом билде работало нормально.

Всё равно кеширует.

tester_no_cache означает "не использовать при оптимизации ранее накопленный кеш оптимизации"

 
Aidas Geguzis:

Какие именно? Скриншоты, логи?

Любые. Чтобы можно было воспроизвести описанную проблему
 
Alexey Navoykov:

Видим, что все фрэймы пришли одновременно, хотя отсылались с разницей в 3 секунды.


Где мы видим, что все фреймы пришли одновременно?

 
Slava:

tester_no_cache означает "не использовать при оптимизации ранее накопленный кеш оптимизации"

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

2019.05.24 08:39:17.010 Tester  1 blocks of results read from cache in 0 ms

Приходится перекомпилировать.

Slava:

Где мы видим, что все фреймы пришли одновременно?

Ну на время в левом столбце посмотрите.  Я там даже жёлтым выделил ключевой момент.  Два фрэйма посланные с разницей в 3 секунды, а время прихода одновременное.

 
Alexey Navoykov:

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

Приходится перекомпилировать.

Ну на время в левом столбце посмотрите.  Я там даже жёлтым выделил ключевой момент.  Два фрэйма посланные с разницей в 3 секунды, а время прихода одновременное.

Кеш, если есть, загружается по-любому. Ни о чём не говорит. Что написано в подробных логах?

Где написано время прихода фреймов? Как понять, что время прихода фреймов одинаковое?

 
Slava:

Где написано время прихода фреймов? Как понять, что время прихода фреймов одинаковое?

В левом столбце распечатки лога вашего терминала, которую я привёл.

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

fxsaber:

OnTesterPass срабатывает только на первый фрейм. Правильно было бы через таймер делать проверку.

Так вот видим, что сработал он только по завершении работы агента.  До этого он не сработал НИ РАЗУ.

Но OK, если угодно, можно добавить вызов по таймеру:

void OnTesterInit()
  {
    Print("OnTesterInit");
    EventSetTimer(1);
  }

void OnTimer()
{
  Print("OnTimer");
  OnTesterPass();
}

Результат не меняется:

2019.05.24 10:35:32.148 TestFrames (EURUSD,H1) OnTesterInit
2019.05.24 10:35:33.151 TestFrames (EURUSD,H1) OnTimer
2019.05.24 10:35:34.145 TestFrames (EURUSD,H1) OnTimer
2019.05.24 10:35:35.158 TestFrames (EURUSD,H1) OnTimer
2019.05.24 10:35:35.670 TestFrames (EURUSD,H1) Frame from agent 0:  OnInit,  0 ms
2019.05.24 10:35:35.671 TestFrames (EURUSD,H1) Frame from agent 0:  OnTester,  0 ms
2019.05.24 10:35:35.671 TestFrames (EURUSD,H1) Frame from agent 0:  OnDeinit,  16 ms
2019.05.24 10:35:35.671 TestFrames (EURUSD,H1) Frame from agent 0:  OnDeinit End,  3016 ms
2019.05.24 10:35:35.741 TestFrames (EURUSD,H1) Frame from agent 1:  OnInit,  0 ms
2019.05.24 10:35:35.742 TestFrames (EURUSD,H1) Frame from agent 1:  OnTester,  15 ms
2019.05.24 10:35:35.742 TestFrames (EURUSD,H1) Frame from agent 1:  OnDeinit,  15 ms
2019.05.24 10:35:35.742 TestFrames (EURUSD,H1) Frame from agent 1:  OnDeinit End,  3015 ms
2019.05.24 10:35:35.809 TestFrames (EURUSD,H1) OnTesterDeinit

Для пущей уверенности, можно ещё и в начало OnInit добавить паузу, прежде чем посылать фрэймы, чтобы быть уверенным, что терминал успел подготовиться к приёму фрэймов.  Но результат тот же.

Удивительно однако, что сам Slava не знает, как устроена у них работа с фрэймами, а вместо этого сыпет какие-то странные вопросы.  И я сам вынужден им объяснять, как оно у них работает.

 

При приходе фрейма посылается windows message. Когда этот месседж дойдёт до чарта, который положит событие TesterPass в очередь эксперту - неизвестно. Когда эксперт обработает событие TesterPass - неизвестно. При переполнении системной очереди сообщений доставка сообщения не гарантирована.

Пока вы находитесь в обработчике OnTesterPass новое событие TesterPass не кладётся в очередь. Это как с тиками.

По окончанию оптимизации эксперту гарантированно выдаётся событие TesterDeinit. В обработчике OnTesterDeinit можно вычитать все фреймы с нуля - попробуйте.

Оптимизация стратегий - Алгоритмический трейдинг, торговые роботы - MetaTrader 5
Оптимизация стратегий - Алгоритмический трейдинг, торговые роботы - MetaTrader 5
  • www.metatrader5.com
Тестер стратегий позволяет тестировать и оптимизировать торговые стратегии (советники) перед началом использования их в реальной торговле. При тестировании советника происходит его однократная прогонка с начальными параметрами на исторических данных. При оптимизации торговая стратегия прогоняется несколько раз с различным набором параметров...
 

Я понял, откуда непонятки с 3 секундными задержками.

В процессе прохода оптимизации можно вызвать сколько угодно раз функцию FrameAdd. Это - не посылка. Это коллекционирование фреймов.

Реально посылка всех собранных фреймов производится после удачного завершения прохода оптимизации. Перед отсылкой результата прохода.

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