Библиотеки: HistoryTicks

 

HistoryTicks:

Советники в MetaTrader 4 пропускают тики, пришедшие в во время любых пауз: выполнение торговых приказов, вычисления, ожидание и т.д. Такая потеря информации может привести к серьезному искажению заложенной логики в ТС. Особенно для ТС, где используется анализ Ask-цен, спред и т.д.

Например, стандартное написание MetaTrader 4 советника не позволяет гарантированно выяснить OHLC-Ask для текущего бара, даже если советник был запущен до начала его формирования.

Данная библиотека/инструментарий позволяет наделить любой советник информацией о прошедших тиках между соседними NewTick-событиями - вызовы OnTick(). Для этого нужно в начале исходника прописать следующую строку:

#include <fxsaber\HistoryTicks\HistoryTicks.mqh> // Библиотека доступа советников к прошедшим тикам


Пример

В качестве демонстрации описанной возможности приложен советник, из кода которого хорошо видна логика происходящего.

#property strict

#include <fxsaber\HistoryTicks\HistoryTicks.mqh> // Библиотека доступа советников к прошедшим тикам

#define TOSTRING(A) #A + " = " + (string)(A) + " "

void OnTick()
{
  static int Num = 0;
  
  // Распечатываем все тики, что пришли во время выполнения предыдущей OnTick
  for (int i = 0; i < ArraySize(LastTicks); i++)  
    Print(TOSTRING(Num++) + TOSTRING(LastTicks[i].time) + TOSTRING(LastTicks[i].bid) + TOSTRING(LastTicks[i].ask));
    
  Print(TOSTRING(ArraySize(HistoryTicks))); // Количество всего сохраненных тиков за время работы советника
    
  Sleep(10000); // Несмотря на длительную паузу, накопление тиков для следующей OnTick будет происходить
}

В коде видно, что стали доступны два тиковых массива:

  • HistoryTicks - все тики с момента запуска советника;
  • LastTicks - все тики с момента последнего события NewTick.


Индикатор

Работа таких советников возможна только при условии, что будет запущен индикатор HistoryTicks. Иначе на каждом тике любой такой советник будет выдавать следующее предупреждение:

2018.03.26 00:05:14.924 HistoryTicks_Example EURGBP,M1: Run the HistoryTicks_EURGBP-indicator!!!

Этот приложенный индикатор и транслирует получаемые им тики во все советники своего символа. Индикатор следит за тем, чтобы не было запущено несколько его копий на одном и том же символе. Также при его удалении с графика сохраняет все накопленные тики в соответствующий файл песочницы терминала.


Использование

В итоге алгоритм работы с модифицированными строкой советниками следующий (на примере EURUSD):

  • Запустить индикатор HistoryTicks на любом графике EURUSD;
  • Запустить советники на любых графиках EURUSD.

Теперь на каждом вызове OnTick можно прогонять в цикле логику ТС через все тики (массив LastTicks), будучи уверенным в отсутствии пропусков, а так же в OnTick достучаться до любого тика (с момента запуска советника) через массив HistoryTicks.


Особенности

  • Используется библиотека TypeToBytes;
  • Модифицированные таким образом (одна строка) советники будут работать только на Реал/Демо-счетах;
  • Чтобы советник работал в Тестере Стратегий, упомянутую строку нужно закомментировать;
  • В исходниках есть кроссплатформенные функции (файл Data_String.mqh), которые позволяют помещать/извлекать любые данные в/из строки. Например, это дает возможность производить удобный обмен произвольными данным между любыми MQL-программами за счет string-параметра (sparam) пользовательских событий;
  • Данная библиотека может служить ядром для написания MQL4-варианта функции CopyTicks, что вместе с другими решениями двигает код к еще большей кроссплатформенности;
  • В MetaTrader 5 из-за штатного MQL-доступа к тиковой истории смысл в таком дополнительном функционале отсутствует (хоть предложенное LastTicks-решение и видится более удобным). Однако, представленный подход к обмену различными данными может быть актуален и для MetaTrader 5;
  • Замер скорости показал, что подобные решения вызывают задержку в несколько микросекунд, редко давая всплески до нескольких единиц миллисекунд. Поэтому вопрос производительности предложенного инструментария остро не встает;
  • Передача данных идет через нулевое пользовательское событие (id == CHARTEVENT_CUSTOM). При необходимости изменить номер события потребуется править исходник;
  • Тики в соответствующих массивах расположены от более ранних/старых к более поздним/свежим. Последний тик - конец массива.

Автор: fxsaber

 

Тики народ собирает с древних времен почти всегда с одной целью - прогнать советник по ним в Тестере.

Парадокс в том, что боевой советник по тикам, наверное, никто не прогоняет в реал-тайме. Теперь это не так.


Индикаторы выполняются в одном потоке. Если есть опасения, что среди запущенных индикаторов есть медленный, можно History-индикатор переделать в советник: заменить OnCalculate на OnTick. Тогда будет выделен собственный поток для кода-передатчика и медленные индикаторы не будут на него влиять.


Добавлю, что "получение всех тиков" - это получение максимального возможного количества тиков, что позволяет Терминал. Известно, что сам MQL4 не позволяет получить абсолютно все тики (несмотря на мифы), что можно наблюдать в MarketWatch-графике. Поэтому "получение всех тиков" советником - это все тики, что получал бы пустой советник (индикатор)

void OnTick() {}
 

Боевой советник на высокочастотном символе (200-350 тиков в минуту) с частыми торговыми приказами (несколько раз в минуту) и пингом 100 ms в стандартном режиме работы теряет ~5% тиков.

В режиме HistoryTicks потерь нет.

 

В MT4 на каждом тике делается

FileSave("RAMDisk\\" + Name, HistoryTicks);


В MT5 скрипт делает

FileLoad("RAMDisk\\" + Name, Ticks);

и на этих тиках создает кастомный символ для MT5-тестера.


По итогу в одно/два нажатия исключительно в MT5 появляется возможность прогонять советник по самым свежим тикам из MT4 с идеальной точностью в любое время.


Боевой советник написан через MT4Orders, поэтому пашет одинаково без каких-либо #ifdef в MT4/5. Гоню MT4-советник в MT5-тестере по свежайшим котирам из MT4 и наблюдаю полное совпадение поведения на боевом счету в MT4 и в MT5-тестере. Оптимизация в MT5 (с фильтрацией тиков на порядок), запуск - MT4.


Настолько удобно и безотказно, что решил написать.

 

Инструментарий HistoryTicks обновлен.

  • Код стал кроссплатформенным и может использоваться в MT5.
  • Тики сохраняются в текстовый файл при выходе из индикатора-накопителя
  • Накопленные тики подхватывают сохраненные в файле тики при старте индикатора-накопителя.
  • Индикатор-накопитель может транслировать свою обновляемую БД во все советники.
  • Если транслятор истории включен, советники в любой момент могут получить БД индикатора-накопителя.
Грубо говоря, если выключить советник, а затем снова включить, то он не потеряет ни одного тика, т.к. БД индикатора-накопителя беспрерывно транслируется на все советники.


Транслятор в MT4 работает только на build1147+.

 
Если нужно, чтобы исторические тики в советнике не съедали драгоценную VPS-память, можно делать на каждом тике
ArrayFree(HistoryTicks);
 

Потребление вычислительных ресурсов сведено к минимуму.


Мониторил загрузку работы 15-и советников, которые получали сотни тысяч исторических тиков + все новые. По итогу загрузка CPU < 0-3%, RAM = 220Mb. Это MT4, как с этим справился бы MT5 - не знаю.

 
  • В исходниках есть кроссплатформенные функции (файл Data_String.mqh), которые позволяют помещать/извлекать любые данные в/из строки. Например, это дает возможность производить удобный обмен произвольными данным между любыми MQL-программами за счет string-параметра (sparam) пользовательских событий;
// Пример передачи/обмена данных между программами через поле комментария чартов

#include <fxsaber\HistoryTicks\Data_String.mqh> // https://www.mql5.com/ru/code/20298

void OnStart()
{
  int ArrayIn[] = {0, 1, 2, 3, 4, 5};  
  ChartSetString(0, CHART_COMMENT, DATA_STRING::ToString(ArrayIn));    // Записали данные в комментарий чарта

  int ArrayOut[];    
  DATA_STRING::FromString(ChartGetString(0, CHART_COMMENT), ArrayOut); // Прочли данные из комментария чарта
  
  ArrayPrint(ArrayOut);
}
 
fxsaber:

Инструментарий HistoryTicks обновлен.

  • Индикатор-накопитель может транслировать свою обновляемую БД во все советники.
  • Если транслятор истории включен, советники в любой момент могут получить БД индикатора-накопителя.
Грубо говоря, если выключить советник, а затем снова включить, то он не потеряет ни одного тика, т.к. БД индикатора-накопителя беспрерывно транслируется на все советники.

Более, чем на порядок, увеличена скорость передачи/приема БД индикатора-накопителя.


Received  121035 ticks: 2018.12.07 13:39:00 - 2018.12.10 14:57:42, TransferTime = 42ms. (2881785 ticks/sec)
 
Делал похожее решение для сбора тиков по множеству символов. У меня почему-то время исполнения CHARTEVENT_CUSTOM иногда доходит до нескольких секунд.
 
secret:
Делал похожее решение для сбора тиков по множеству символов. У меня почему-то время исполнения CHARTEVENT_CUSTOM иногда доходит до нескольких секунд.

Сбор тиков - не цель. Концепция использования такая

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Библиотеки: Virtual

fxsaber, 2018.12.05 11:14

// Пример кроссплатформенного боевого советника

#include <fxsaber/Virtual/Virtual.mqh> // https://www.mql5.com/ru/code/22577

#define OnTick SystemOnTick
  // Сюда прописываем любой MT4-style тиковый советник
  #include <..\Experts\fxsaber\TesterEA\TesterEA.mq4> // https://www.mql5.com/ru/code/22770
#undef OnTick

#include <fxsaber\HistoryTicks\HistoryTicks.mqh> // https://www.mql5.com/ru/code/20298

void OnTick()
{  
  static const bool VirtualInit = (VIRTUAL::Tester(HistoryTicks, SystemOnTick, 1000, false) != -1); // Прогнали в виртуалке советник на тиковой истории с начальным балансом = 1000
  
  if (VirtualInit)
  {
    VIRTUAL::NewTick(LastTicks, SystemOnTick); // Продолжаем гнать советник в виртуале на вновь поступающих тиках (без единого пропуска!)
    Comment(VIRTUAL::ToString(5));
    
//    VirtualToReal(); // Синхронизатор виртуального и реального торговых окружений.
  }
}


EventCustom делается на каждом тике, но не на каждом Custom-тике идет вызов OnTick, поэтому тормозов нет.