Обсуждение статьи "Универсальный торговый эксперт: Событийная модель и прототип торговой стратегии (Часть 2)"

 

Опубликована статья Универсальный торговый эксперт: Событийная модель и прототип торговой стратегии (Часть 2):

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

Данная статья продолжает знакомить читателей с универсальным торговым движком CStrategy. В первой статье Универсальный торговый эксперт: Торговые режимы стратегий (Часть 1) были подробно разобраны торговые режимы и функции по их организации. Была предложена универсальная схема эксперта, состоящая из четырех методов, два из которых открывают новые позиции а другие два — закрывают. Разная комбинация вызовов этих методов определяет тот или иной торговый режим, например, такому эксперту можно задать режим только покупок или только продаж, сопровождение ранее открытых позиций или режим ожидания. Благодаря этим режимам эксперт приобретает возможность гибкой настройки своей работы в зависимости от торгового времени или даже дня недели.

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

Также в данной статье описываются два важнейших класса всего торгового движка — это классы CStrategy и CPosition. Первый из них является ядром всей торговой логики эксперта, он объединяет события и режимы в единый гибкий каркас, который непосредственно наследует эксперт пользователя. Второй класс является основой универсальных торговых операций. В него помещены действия с открытой позицией (например закрытие позиции или изменение ее уровня Stop Loss или Take Profit). Благодаря этому все торговые действия становятся однотипными и платформонезависимыми.

Доступ к событиям, происходящим на других инструментах, структура MarketEvent

При проектировании торговой системы, анализирующей сразу несколько инструментов, как правило, требуется создать механизм, отслеживающий изменение цен на нескольких инструментах. Однако штатная функция OnTick вызывается только в момент прихода нового тика на том инструменте, на котором был запущен эксперт. С другой стороны, в распоряжении разработчиков торговых систем имеется функция OnBookEvent, реагирующая на изменения стакана. В отличие от OnTick, функция OnBookEvent будет вызываться при изменении стакана того инструмента, на который была осуществлена подписка с помощью функции MarketBookAdd.

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

Таким образом, в системных функциях, реагирующих на события NewTick, BookEvent и Timer, можно разместить вызов некоего промежуточного модуля (назовем его условно EventProcessor), который бы в свою очередь анализировал изменение цен на нескольких инструментах одновременно и генерировал бы то или иное событие. Каждое событие имело бы унифицированное описание в виде структуры и отправлялось бы управляющим методам стратегии. Стратегия, получив соответствующее событие в виде структуры, реагировала бы на него или пропускала. При этом системная функция, которая была бы фактическим инициатором этого события для конечного эксперта, оставалось бы неизвестной.

В самом деле, если эксперт получил уведомление о приходе нового тика, то не имеет значения, как была получена данная информация: через OnTick, OnTimer или OnBookEvent. Важно лишь то, что новый тик для указанного инструмента действительно пришел. Обработчик событий может быть один на несколько стратегий. Например, если каждую стратегию представить в виде пользовательского класса, то сразу несколько экземпляров этих классов можно хранить в специальном списке стратегий. При этом каждая из стратегий списка имела бы возможность получения нового события, генерируемого модулем EventProcessor. Схематично модель создания и распространения событий можно представить на следующем графике:

Рис. 1. Схема создания и распространения событий

Автор: Vasiliy Sokolov

 
Спасибо автору. Материал статьи крайне полезен и к тому же великолепно изложен. Давно хотел навести порядок в своих подходах к экспертописанию, а тут автор статьи уже прошел все муки творчества и предлагает готовое решение. Супер! С нетерпением жду продолжения.


Ударим "торговым движком" по бездорожью автоматизации торговых систем, мукам творчества и разгильдяйству разработчиков!

 

Спасибо автору за содержательную статью, но у меня небольшие сомнения в надежности программной реализации.

В предложенном вами коде все функции-обработчики событий обращаются к общей переменной event_type или к структуре m_event в общем экземпляре CStrategy.

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

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

Исходя из этого, объединенный обработчик событий и блок данных, предлагаемые в статье, ИМХО - не совсем хорошая идея.

 
Eugene Myzrov:
Спасибо автору. Материал статьи крайне полезен и к тому же великолепно изложен. Давно хотел навести порядок в своих подходах к экспертописанию, а тут автор статьи уже прошел все муки творчества и предлагает готовое решение. Супер! С нетерпением жду продолжения.


Ударим "торговым движком" по бездорожью автоматизации торговых систем, мукам творчества и разгильдяйству разработчиков!

Спасибо!

Ivan Negreshniy:

Спасибо автору за содержательную статью, но у меня небольшие сомнения в надежности программной реализации.

В предложенном вами коде все функции-обработчики событий обращаются к общей переменной event_type или к структуре m_event в общем экземпляре CStrategy.

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

...

Спасибо за интересное замечание. Действительно, события в MetaTrader асинхронные. Однако выполнение пользовательских потоков происходит строго последовательно. Это значит, что другие события не будут обрабатываться до тех пор, пока эксперт не закончит обработку текущего события. Приведенный ниже код иллюстрирует сказанное:

//+------------------------------------------------------------------+
//|                                                   TestAsynch.mq5 |
//|                                 Copyright 2015, Vasiliy Sokolov. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
#property version   "1.00"
bool need_check = true;
#define EVENT_CHECK_ASYNCH 1
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   if(need_check)
   {
      EventChartCustom(ChartID(), EVENT_CHECK_ASYNCH, 0.0, 0.0, "Проверка асинхронности");
   }
   if(need_check)
      printf("Сначала завершается пользовательский поток");
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   if(id == CHARTEVENT_CUSTOM+EVENT_CHECK_ASYNCH && need_check)
   {
      printf("Потом вызывается событие OnChartEvent");
      need_check = false;
   }
  }
//+------------------------------------------------------------------+

 Его выполнение выдает строки в следующей последовательности:

2016.01.15 13:51:31.724 TestAsynch (NZDUSD,W1)  Потом вызывается событие OnChartEvent
2016.01.15 13:51:31.722 TestAsynch (NZDUSD,W1)  Сначала завершается пользовательский поток

Таким образом, никаких ошибок вызванных совместным изменением общей переменной  m_event просто нет, т.к. код выполняется последовательно. Замечу также, что сама структура является приватной и доступна лишь по ссылке специальным методам. Поэтому ее фактическое размещение внутри CStrategy не имеет значение, структура  с легкостью может быть создана непосредственно в методах-обработчиках событий и также передана экземплярам стратегий.

 
Vasiliy Sokolov:

Спасибо!

Спасибо за интересное замечание. Действительно, события в MetaTrader асинхронные. Однако выполнение пользовательских потоков происходит строго последовательно. Это значит, что другие события не будут обрабатываться до тех пор, пока эксперт не закончит обработку текущего события. Приведенный ниже код иллюстрирует сказанное:

 Его выполнение выдает строки в следующей последовательности:

Таким образом, никаких ошибок вызванных совместным изменением общей переменной  m_event просто нет, т.к. код выполняется последовательно. Замечу также, что сама структура является приватной и доступна лишь по ссылке специальным методам. Поэтому ее фактическое размещение внутри CStrategy не имеет значение, структура  с легкостью может быть создана непосредственно в методах-обработчиках событий и также передана экземплярам стратегий.

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

При этом существуют критичные по времени задачи, требующие распараллеливания, например расчеты с большими объемами ценовых, исторических данных, выполняемые с помощью OpenCL или более конкретные, актуальные для меня задачи - обучение нейросетей по различным символам и периодам, выполняемое с помощью многопоточного движка, описанного в моей статье.
https://www.mql5.com/ru/articles/706

Создание нейросетевых торговых роботов на базе MQL5 Wizard и Hlaiman EA Generator
Создание нейросетевых торговых роботов на базе MQL5 Wizard и Hlaiman EA Generator
  • 2013.08.29
  • Ivan Negreshniy
  • www.mql5.com
В статье рассматривается метод автоматизированного создания нейросетевых торговых роботов на базе MQL5 Wizard и Hlaiman EA Generator. Узнайте, как легко начать работать с нейронными сетями, минуя длительные этапы изучения теоретических материалов и написания собственного кода.
 
Ivan Negreshniy:

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

При этом существуют критичные по времени задачи, требующие распараллеливания, например расчеты с большими объемами ценовых, исторических данных, выполняемые с помощью OpenCL или более конкретные, актуальные для меня задачи - обучение нейросетей по различным символам и периодам, выполняемое с помощью многопоточного движка, описанного в моей статье.
https://www.mql5.com/ru/articles/706

Распараллеливание в MetaTrader происходит за счет многопоточного тестера стратегий. Таким образом, если Вы запустите стратегию, написанную с помощью описываемого движка в тестере стратегий, то она автоматически станет многопоточной. Т.к. сторонних dll нет, можно использовать MQL Networl Cloud на полную катушку. То, о чем Вы пишете, относится к работе самого MetaTrader. Да, движок, как и любой эксперт или скрипт в MetaTrader, является однопоточным, однако оптимизатор позволяет выполнять многопоточные и в т.ч. облачные вычисления представленного кода.

Что касается самой производительности движка - то здесь тоже все в порядке. Вы можете убедится в этом, выполнив профилирование. Затраты на инфраструктуру и доставку событий минимальны. Основное время выполнения сосредоточено в вызовах системных функций и пользовательских методах BuyInit, SellInit, BuySupport, SellSupport. По расчетам, сделанным на основе профилирования, движок способен обрабатывать многие десятки событий в секунду, перенаправляя их без особого труда множеству стратегий одновременно.

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

 
Большое спасибо Vasiliy Sokolov за усилия по продвижение хорошего стиля программирования вообще и ООП в частности.
Статья четко изложена и очень полезна, по крайней мере, для начинающих в MQL, к коим отношу себя. :)
Прошу ответить на следующий вопрос:
В моих торговых алгоритмах позиции 
рыночными ордерами типа Buy/Sell открываются в особых ситуациях - если цена уже проскочила соответствующий уровень или перед окончанием торговой сессии.
В основном позиции открываются/закрываются на пробое уровня вверх/вниз (для Long) путем размещения стоп-ордеров типа BuyStop/SelStop, которые пересчитываются в начале нового бара.
Не могли бы Вы подсказать, как можно было бы ввести размещение и изменение стоп-ордеров в описанные классы ? 
 
Mike:
Большое спасибо Vasiliy Sokolov за усилия по продвижение хорошего стиля программирования вообще и ООП в частности.
Статья четко изложена и очень полезна, по крайней мере, для начинающих в MQL, к коим отношу себя. :)
Прошу ответить на следующий вопрос:
В моих торговых алгоритмах позиции 
рыночными ордерами типа Buy/Sell открываются в особых ситуациях - если цена уже проскочила соответствующий уровень или перед окончанием торговой сессии.
В основном позиции открываются/закрываются на пробое уровня вверх/вниз (для Long) путем размещения стоп-ордеров типа BuyStop/SelStop, которые пересчитываются в начале нового бара.
Не могли бы Вы подсказать, как можно было бы ввести размещение и изменение стоп-ордеров в описанные классы ? 

Приветствую. В данный момент алгоритмы по управлению отложенными ордерами прорабатываются, но конкретной реализации в текущей версии движка пока нет. Единственное, что могу предложить на текущий момент, это разместить код по выставлению отложенных ордеров в методах BuyInit и SellInit. Там же необходимо делать перебор отложенных ордеров и все те действия, которые обычно приходится делать в обычных экспертах.

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

 
Vasiliy Sokolov:

Приветствую. В данный момент алгоритмы по управлению отложенными ордерами прорабатываются, но конкретной реализации в текущей версии движка пока нет. Единственное, что могу предложить на текущий момент, это разместить код по выставлению отложенных ордеров в методах BuyInit и SellInit. Там же необходимо делать перебор отложенных ордеров и все те действия, которые обычно приходится делать в обычных экспертах.

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

Спасибо, Василий, будем ждать.  :)
 
Василий, огромное спасибо за статью(-и)! Просто великолепно и очень полезно для начинающего!
 

Василий, как "руководство по применению ООП в трейдинге" Ваши работы очень познавательны и полезны, а вот, как "рабочий торговый движок" очень бедны. Я, в частности, о разнообразии "административных функций".

Сегодня МТ5 по доступности и лояльности к трейдеру близится к МТ4 (добавлена хэдж-торговля). За многие годы МТ4 накопило достаточно богатый административный функционал в свободном доступе:

* частичное закрытие позиций (я про контроль за этим процессом со стороны торгового движка);

* разнообразие расчёта СТОПов;

* динамические СТОПы;

* виртуальные СТОПы;

* профессиональный ММ (это контроль за распределением средств м\у стратегиями). Конечный, а главное устойчивый результат торговли, зависит в большей степени не от правильного входа и выхода в рынок (хоя и это важно), а от правильного инвестирования;

* виртуальная троговля;

* построение сетей. Т.е. взаимосвязь серии ордеров, объединённых м\у собой единой логикой формирования размеров лотов каждой позиции в серии.

* оставляет желать лучшего и реализация обработки исключений при содании торговых приказов (реквоты, ошибка № 130 [МТ4], STOPLEVEL, FREEZELEVEL и т.д. и т.п.).

Возникает вопрос: "Будете в свободном доступе развивать дальше свой движок?"