Получение событий об изменении стакана цен

Событие OnBookEvent генерируется терминалом при изменении состояния стакана цен и обрабатывается функцией OnBookEvent, определенной в исходном коде. Для того чтобы терминал стал посылать MQL-программе уведомления OnBookEvent по конкретному символу, следует предварительно подписаться на их получение с помощью функции MarketBookAdd.

Для того чтобы отписаться от получения события OnBookEvent по символу, необходимо вызвать функцию MarketBookRelease.

Событие OnBookEvent является широковещательным — это означает, что достаточно одной MQL-программе на графике подписаться на события OnBookEvent, и все остальные программы на том же графике тоже начнут получать их, при наличии в коде обработчика OnBookEvent. Поэтому необходимо анализировать имя символа, которое передается в обработчик в качестве параметра.

Прототип обработчика OnBookEvent следующий.

void OnBookEvent(const string &symbol)

События OnBookEvent ставятся в очередь, даже если в данный момент еще не закончена обработка предыдущего события OnBookEvent.

Важно, что события OnBookEvent являются лишь уведомлениями и не несут в себе состояния стакана заявок. Для получения данных стакана следует вызвать функцию MarketBookGet.

При этом следует учитывать, что вызов MarketBookGet, даже если он производится непосредственно из обработчика OnBookEvent, получит текущее актуальное состояние стакана на момент вызова MarketBookGet, которое не обязательно совпадает с тем состоянием стакана, которое инициировало отправку события OnBookEvent. Такое может случиться при поступлении в терминал последовательности очень быстрых изменений стакана.

В связи с этим, для получения максимально полной хронологии изменений стакана необходимо писать реализацию OnBookEvent с приоритетом на оптимизацию по скорости выполнения.

Вместе с тем, гарантированного способа получения всех уникальных состояний стакана в MQL5 не существует.

Если ваша программа начала успешно получать уведомления, а затем при открытом рынке они пропали (а тики продолжают приходить), это может свидетельствовать о проблемах в подписке. В частности, неверно спроектированная другая MQL-программа могла отменить подписку большее количество раз, чем требовалось. В таких случаях рекомендуется повторить подписку с помощью нового вызова MarketBookAdd после предопределенного таймаута (например, несколько десятков секунд или минуту).

Пример безбуферного индикатора MarketBookEvent.mq5 позволяет отслеживать поступление событий OnBookEvent и выводит имя символа и текущее время (миллисекундный системный счетчик) в комментарий. Для наглядности мы используем функцию многострочного комментария из файла Comments.mqh из раздела Вывод сообщений в окно графика.

Интересно, что если оставить входной параметр WorkSymbol пустым (значение по умолчанию), сам индикатор не инициирует подписку на стакан, но сможет перехватывать сообщения, заказанные другими MQL-программами на том же графике. Мы это проверим.

#include <MQL5Book/Comments.mqh>
   
input string WorkSymbol = ""// WorkSymbol (if empty, intercept events initiated by others)
   
void OnInit()
{
   if(StringLen(WorkSymbol))
   {
      PRTF(MarketBookAdd(WorkSymbol));
   }
   else
   {
      Print("Start listening to OnBookEvent initiated by other programs");
   }
}
   
void OnBookEvent(const string &symbol)
{
   ChronoComment(symbol + " " + (string)GetTickCount());
}
 
void OnDeinit(const int)
{
   Comment("");
   if(StringLen(WorkSymbol))
   {
      PRTF(MarketBookRelease(WorkSymbol));
   }
}

Давайте запустим на графике MarketBookEvent с настройками по умолчанию (без собственной подписки), а затем добавим индикатор MarketBookAddRelease из предыдущего раздела, причем укажем для него список из нескольких символов с доступными стаканами (в примере ниже это — "XAUUSD,BTCUSD,USDCNH"). На каком именно графике запускать индикаторы — не важно: это может быть и совсем другой символ, вроде EURUSD.

Сразу после запуска MarketBookEvent график будет пуст (без комментариев), потому что подписок еще нет. После того как стартует MarketBookAddRelease (в журнале должно появиться три строки со статусом успешной подписки true), в комментариях начнут попеременно появляться названия символов, по мере обновления их стаканов (сами стаканы мы пока не научились читать, об этом речь пойдет в следующем разделе).

Вот как это выглядит на экране.

Уведомления об изменении стаканов "чужих" символов
Уведомления об изменении стаканов "чужих" символов

Если теперь удалить индикатор MarketBookAddRelease, он отменит свои подписки, и комментарий перестанет обновляться. Последующее удаление MarketBookEvent очистит комментарий.

Обратите внимание, что между запросом на отмену подписки и моментом, когда события стакана реально перестают обновлять комментарий, проходит некоторое время (секунда-две).

Вы можете запустить на графике только индикатор MarketBookEvent с каким-либо символом в его параметре WorkSymbol, чтобы убедиться в работе уведомлений внутри одной программы. MarketBookAddRelease был ранее использован лишь для того, чтобы продемонстрировать широковещательную природу уведомлений — иными словами, включение подписки на изменения стакана в одной программе действительно влияют на получение уведомлений в другой.