English 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Программируем режимы работы советника с помощью ООП

Программируем режимы работы советника с помощью ООП

MetaTrader 5Примеры | 19 декабря 2014, 11:26
8 211 0
Denis Kirichenko
Denis Kirichenko

Введение

В данной статье речь пойдет о программировании режимов, в которых может работать MQL5-советник. Цель статьи - описать идею "каждому режиму – своя реализация". Такой подход, по мнению автора, позволяет выполнять задачи на разных этапах разработки торгового робота более эффективно.

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


1. Этапы разработки

Разработка торгового робота (советника) – это многоаспектный процесс. Ключевыми здесь выступают 2 блока: алгоритмизация идеи и тестирование. Причем тестируется как торговая логика робота, так и сам код алгоритма.

Схематично этапы данного процесса можно представить так (рис.1).

Рис.1 Этапы разработки и внедрения торгового робота

Рис.1. Этапы разработки и внедрения торгового робота

Пятый этап "Алготрейдинг" венчает все усилия разработчика, программиста, аналитика и других специалистов, участвующих в этом деле. Чаще всего все эти роли выполняет один человек. Пусть это будет трейдер-программист.

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

Отмечу, что на каждом этапе от разработчика требуются свои инструменты, знания и умения.

Мне представляется, что разработчик сталкивается с такой простой матрицей вариантов (рис.2).

Матрица вариантов

Рис.2. Матрица вариантов

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


2. Режимы в MQL5

MQL5-среда представляет возможности для работы с роботом в разных режимах. Всего их 7. Позже рассмотрим каждый.

С точки зрения типа файла программы можно выделить 2 группы:

  1. режимы, требующие файл исходного кода и исполняемый файл;
  2. режимы, требующие только исполняемый файл.

К первой группе относятся режимы отладки и профилирования.

Другой критерий для классификации режимов – это работа советника на потоке реальных котировок или исторических. С историческими котировками связаны все режимы тестирования.

Программным образом определяются 6 режимов. Исходя из результатов, можно сделать вывод о том, работает ли советник в обычном (релиз) режиме или нет. Готовая программа (файл с расширением *.ex5), которая и кодировалась с целью работы на финансовых рынках, будет работать именно в этом режиме. Готовая программа позволяет обратиться и к другим режимам в Тестере стратегий.

Создадим перечисление режимов работы MQL-программы под названием ENUM_MQL_MODE:

//+------------------------------------------------------------------+
//| MQL-режим                                                        |
//+------------------------------------------------------------------+
enum ENUM_MQL_MODE
  {
   MQL_MODE_RELEASE=0,       // Релиз
   MQL_MODE_DEBUG=1,         // Отладка
   MQL_MODE_PROFILER=2,      // Профилирование  
   MQL_MODE_TESTER=3,        // Тестирование
   MQL_MODE_OPTIMIZATION=4,  // Оптимизация
   MQL_MODE_VISUAL=5,        // Визуальное тестирование 
   MQL_MODE_FRAME=6,         // Сбор фреймов
  };

Позже оно понадобится для определения типа режима, в котором работает робот.


2.1. Функции определения и проверки режима

Напишем простую функцию, которая пройдется по всем режимам и выведет информацию в журнал.

//+------------------------------------------------------------------+
//| Проверка всех MQL-режимов                                        |
//+------------------------------------------------------------------+
void CheckMqlModes(void)
  {
//--- если режим отладки
   if(MQLInfoInteger(MQL_DEBUG))
      Print("Debug mode: yes");
   else
      Print("Debug mode: no");
//--- если режим профилирования кода
   if(MQLInfoInteger(MQL_PROFILER))
      Print("Profile mode: yes");
   else
      Print("Profile mode: no");
//--- если режим тестирования
   if(MQLInfoInteger(MQL_TESTER))
      Print("Tester mode: yes");
   else
      Print("Tester mode: no");
//--- если режим оптимизации
   if(MQLInfoInteger(MQL_OPTIMIZATION))
      Print("Optimization mode: yes");
   else
      Print("Optimization mode: no");
//--- если режим визуального тестирования
   if(MQLInfoInteger(MQL_VISUAL_MODE))
      Print("Visual mode: yes");
   else
      Print("Visual mode: no");
//--- если режим сбора фреймов результатов оптимизации
   if(MQLInfoInteger(MQL_FRAME_MODE))
      Print("Frame mode: yes");
   else
      Print("Frame mode: no");
  }

Давайте проверим для каждого режима работу этой функции. Можно вызывать эту функцию в обработчике OnInit.

Для целей тестирования создадим шаблон советника Test1_Modes_EA.mq5.

В input-параметрах сделаем возможность обозначения режима, в котором запускаемый советник будет работать. Здесь важно правильно указать режим, иначе информация будет неточной. Что в итоге и вышло.

Смотрим на релиз-режим.

CL      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Текущий режим: MQL_MODE_RELEASE
QD      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: no
KM      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: no
EK      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
CS      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
RJ      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
GL      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: no

Для релиз-режима флаги всех прочих режимов обнулены. Т.е. функция определила, что это не отладка (Debug mode: no), не профилирование (Profile mode: no) и т.д. Методом отрицания пришли к тому, что работаем в релизе.

Теперь обратимся к режиму отладки.

HG      0       17:27:47.709    Test1_Modes_EA (EURUSD.e,H1)     Текущий режим: MQL_MODE_DEBUG
LD      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: yes
RS      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: no
HE      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
NJ      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
KD      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
RR      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: no

Режим отладки был идентифицирован верно.

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

Данный режим чаще всего используется при формализации и алгоритмизации торговой идеи.

Программным образом отладку определяют с помощью макроса IS_DEBUG_MODE или функции MQLInfoInteger(), идентификатор MQL_DEBUG.

Переходим к режиму профилирования.

GS      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Текущий режим: MQL_MODE_PROFILER
OR      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: no
GE      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: yes
QM      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
CE      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
FM      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
GJ      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: no

Функция точно определила, что работали с Профилировщиком.

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

Программным образом профилирование определяют с помощью макроса IS_PROFILE_MODE или функции MQLInfoInteger(), идентификатор MQL_PROFILER.

Посмотрим теперь на режим тестирования. Информация появится на вкладке "Журнал" Тестера стратегий.

EG      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Текущий режим: MQL_MODE_TESTER
OS      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Debug mode: no
GJ      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Profile mode: no
ER      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Tester mode: yes
ED      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Optimization mode: no
NL      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Visual mode: no
EJ      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Frame mode: no

Режим тестирования был идентифицирован верно.

Этот режим работы советника появляется тогда, когда мы открываем Тестер стратегий.

Макроса для этого режима нет, поэтому средствами MQL5 его можно определить только с помощью функции MQLInfoInteger(), идентификатор MQL_TESTER.

Теперь переходим к оптимизации. Журнал с записями будет находиться в папке агента. В моем случае путь был таким: %Program Files\MetaTrader5\tester\Agent-127.0.0.1-3000\logs

OH      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Текущий режим: MQL_MODE_OPTIMIZATION
KJ      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Debug mode: no
NO      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Profile mode: no
FI      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Tester mode: yes
KE      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Optimization mode: yes
LS      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Visual mode: no
QE      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Frame mode: no

Если режим оптимизации активен, то автоматически включен и режим тестирования.

Режим оптимизации задействуется в Тестере стратегий, если поле "Оптимизация" на вкладке Настройки не отключена.

Узнать о том, что робот тестируется в режиме оптимизации, средствами MQL5 можно путем вызова функции MQLInfoInteger(), идентификатор MQL_OPTIMIZATION.

Обращаемся к режиму визуализации.

JQ      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Текущий режим: MQL_MODE_VISUAL
JK      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Debug mode: no
KF      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Profile mode: no
CP      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Tester mode: yes
HJ      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Optimization mode: no
LK      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Visual mode: yes
KS      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Frame mode: no

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

В этом режиме советник работает в Тестере стратегий, если задано поле "Визуализация" на вкладке Настройки.

Определить факт тестирования MQL5-программы в визуальном режиме можно посредством функции MQLInfoInteger(), идентификатор MQL_VISUAL_MODE.

И последний режим – обработка фреймов.

HI      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Текущий режим: MQL_MODE_FRAME
GR      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Debug mode: no
JR      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Profile mode: no
JG      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Tester mode: yes
GM      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Optimization mode: yes
HR      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Visual mode: no
MI      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Frame mode: no

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

Получим такие записи в журнале "Эксперты":

IO      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Текущий режим: MQL_MODE_FRAME
GE      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: no
ML      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: no
CJ      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
QR      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
PL      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
GS      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: yes

Интересно, что теперь обнаружился только режим сбора фреймов.

Данный режим задействуется в Тестере стратегий, если поле "Оптимизация" на вкладке "Настройки" не отключена. Как показал опыт, режим определяется в теле обработчиков OnTesterInit(), OnTesterPass(), OnTesterDeinit().

Определить факт тестирования робота в режиме сбора фреймов можно при помощи функции MQLInfoInteger()  с идентификатором MQL_FRAME_MODE.

Попробуем закодировать сервисную функцию MqlMode(), которая автоматически укажет, в каком режиме работает советник.

//+------------------------------------------------------------------+
//| Определить текущий MQL-режим                                     |
//+------------------------------------------------------------------+
ENUM_MQL_MODE MqlMode(void)
  {
   ENUM_MQL_MODE curr_mode=WRONG_VALUE;

//--- если режим отладки
   if(MQLInfoInteger(MQL_DEBUG))
      curr_mode=MQL_MODE_DEBUG;
//--- если режим профилирования кода
   else if(MQLInfoInteger(MQL_PROFILER))
      curr_mode=MQL_MODE_PROFILER;
//--- если режим визуального тестирования
   else if(MQLInfoInteger(MQL_VISUAL_MODE))
      curr_mode=MQL_MODE_VISUAL;
//--- если режим оптимизации
   else if(MQLInfoInteger(MQL_OPTIMIZATION))
      curr_mode=MQL_MODE_OPTIMIZATION;
//--- если режим тестирования
   else if(MQLInfoInteger(MQL_TESTER))
      curr_mode=MQL_MODE_TESTER;
//--- если режим сбора фреймов результатов оптимизации
   else if(MQLInfoInteger(MQL_FRAME_MODE))
      curr_mode=MQL_MODE_FRAME;
//--- если релиз-режим
   else
      curr_mode=MQL_MODE_RELEASE;
//---
   return curr_mode;
  }

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

Посмотрим на работу функции во втором шаблоне советника Test2_Modes_EA.mq5. При его запуске в журнале появится запись. Например, для режима профилирования была такая запись:

HG      0       11:23:52.992    Test2_Modes_EA (EURUSD.e,H1)    Текущий режим: MQL_MODE_PROFILER

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


3. Шаблон "режимного советника"

Предлагаю снова вспомнить о том, какие этапы при разработке проходит торговый робот, да и сам разработчик со своим детищем.

На этапе алгоритмизации программист чаще пользуется отладкой и профилированием. При тестировании на истории обращается ко всем режимам, присущим Тестеру стратегий. Финальный режим (релиз) задействуется для онлайн торговли.

На мой взгляд, полноценный робот должен быть многоликим. В том смысле, что требования этапов разработки и тестирования должны быть как-то отражены в его коде.

Тогда, сохраняя основной алгоритм торговой идеи и подчиняясь ему, робот будет иметь некоторые отличия в своем поведении при разных режимах работы. Для решения такой задачи как нельзя лучше подходит инструментарий ООП.

Рис.2 Иерархия классов для "режимного" советника

Рис.3. Иерархия классов для "режимного" советника

Иерархия классов с реализацией различных режимов представлена на рис.3.

Базовый класс CModeBase, инкапсулирующий все общее, будет иметь 2 прямых потомка: класс CModeRelease и класс CModeTester. Первый будет родителем для отладочных классов, а второй – для классов, связанных с тестированием на истории.

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

  1. Открытие по сигналу, если нет позиции;
  2. Закрытие по сигналу, если есть позиция;
  3. Трал по сигналу, если есть позиция.

Сам торговый сигнал будем ловить на стандартном индикаторе MACD при появлении нового бара.

Сигнал на покупку появляется тогда, когда в отрицательной зоне значений индикатора MACD основная линия пересекает сигнальную снизу вверх (рис.4).

Рис.4 Сигнал на покупку

Рис.4. Сигнал на покупку

Сигнал на продажу появляется тогда, когда в положительной зоне значений индикатора основная линия пересекает сигнальную сверху вниз (рис.5).

Рис.5 Сигнал на продажу

Рис.5. Сигнал на продажу

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

Тогда определение базового класса CModeBase может быть таким:

//+------------------------------------------------------------------+
//| Class CModeBase                                                  |
//| Purpose: a base class for MQL-modes                              |            
//+------------------------------------------------------------------+
class CModeBase
  {
//--- === Data members === --- 
private:
   //--- a macd object & values
   CiMACD            m_macd_obj;
   double            m_macd_main_vals[2];
   double            m_macd_sig_vals[2];

protected:
   long              m_pos_id;
   bool              m_is_new_bar;
   uint              m_trailing_stop;
   uint              m_trail_step;
   //--- trade objects
   CSymbolInfo       m_symbol_info;
   CTrade            m_trade;
   CPositionInfo     m_pos_info;
   CDealInfo         m_deal_info;
   //--- mql mode
   ENUM_MQL_MODE     m_mql_mode;

   //--- a new bar object
   CisNewBar         m_new_bar;
   //--- current tick signal flag
   bool              m_is_curr_tick_signal;
   //--- close order type
   ENUM_ORDER_TYPE   m_close_ord_type;
   
//--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CModeBase();
   void             ~CModeBase(void){};
   //--- initialization
   virtual bool      Init(int _fast_ema,int slow_ema,int _sig,ENUM_APPLIED_PRICE _app_price);
   virtual void      Deinit(void){};

   //--- Modules
   virtual void      Main(void){};

   //--- Procedures
   virtual void      Open(void){};
   virtual void      Close(void){};
   virtual void      Trail(void){};

   //--- Service
   static ENUM_MQL_MODE CheckMqlMode(void);
   ENUM_MQL_MODE     GetMqlMode(void);
   void              SetMqlMode(const ENUM_MQL_MODE _mode);
   void              SetTrailing(const uint _trailing,const uint _trail_step);

protected:
   //--- Functions
   ENUM_ORDER_TYPE   CheckOpenSignal(const ENUM_ORDER_TYPE _open_sig);
   ENUM_ORDER_TYPE   CheckCloseSignal(const ENUM_ORDER_TYPE _close_sig);
   ENUM_ORDER_TYPE   CheckTrailSignal(const ENUM_ORDER_TYPE _trail_sig,double &_sl_pr);
   //---
   double            GetMacdVal(const int _idx,const bool _is_main=true);

private:
   //--- Macros
   bool              RefreshIndicatorData(void);
   //--- Normalization
   double            NormalPrice(double d);
   double            NormalDbl(double d,int n=-1);
   double            NormalSL(const ENUM_ORDER_TYPE _ord_type,double op,double pr,
                              uint SL,double stop);
   double            NormalTP(const ENUM_ORDER_TYPE _ord_type,double op,double pr,
                              uint _TP,double stop);
   double            NormalLot(const double _lot);
  };

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

Данные индикатора MACD будут недоступны для потомков. Они представлены приватными членами.

Отмечу, что среди методов есть виртуальные методы: Main(), Open(), Close(), Trail(). Их реализация будет зависеть от текущего режима, в котором работает робот. Для базового класса данные методы останутся пустыми.

Также в базовом классе есть методы, которые сохраняют торговую логику для всех MQL-режимов. К ним относятся все сигнальные методы:

  • CModeBase::CheckOpenSignal(),
  • CModeBase::CheckCloseSignal(),
  • CModeBase::CheckTrailSignal().

Скажу сразу, что в рамках статьи не ставится задача создания кода для всех типов MQL-режима. В качестве примера приведу классы для обычного и визуального тестирования.


3.1. Режим тестирования

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

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

Определение класса CModeTester для обычного тестирования может быть таким:

//+------------------------------------------------------------------+
//| Class CModeTester                                                |
//| Purpose: a class for the tester mode                             |            
//| Derives from class CModeBase.                                    |
//+------------------------------------------------------------------+
class CModeTester : public CModeBase
  {
//--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CModeTester(void){};
   void             ~CModeTester(void){};

   //--- Modules
   virtual void      Main(void);

   //--- Procedures
   virtual void      Open(void);
   virtual void      Close(void);
   virtual void      Trail(void);
  };

Определение главного модуля представлено следующим образом:

//+------------------------------------------------------------------+
//| Главный модуль                                                   |
//+------------------------------------------------------------------+
void CModeTester::Main(void)
  {
//--- 1) закрытие
   this.Close();
//--- 2) открытие
   this.Open();
//--- 3) трал
   this.Trail();
  }

Создадим для режима обычного тестирования возможность вывода в Журнал информации о появлении торговых сигналов.

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

Приведу выдержку из Журнала о сигнале на открытие позиции и ее последующее закрытие.

HE      0       13:34:04.118    Core 1  2014.11.14 22:15:00   ---=== Сигнал на открытие: SELL===---
FI      0       13:34:04.118    Core 1  2014.11.14 22:15:00   Позапрошлый бар, главная: 0.002117; сигнальная: 0.002109
DL      0       13:34:04.118    Core 1  2014.11.14 22:15:00   Прошлый бар, главная: 0.002001; сигнальная: 0.002118
LO      0       13:34:04.118    Core 1  2014.11.14 22:15:00   market sell 0.03 EURUSD.e (1.25242 / 1.25251 / 1.25242)
KH      0       13:34:04.118    Core 1  2014.11.14 22:15:00   deal #660 sell 0.03 EURUSD.e at 1.25242 done (based on order #660)
GE      0       13:34:04.118    Core 1  2014.11.14 22:15:00   deal performed [#660 sell 0.03 EURUSD.e at 1.25242]
OD      0       13:34:04.118    Core 1  2014.11.14 22:15:00   order performed sell 0.03 at 1.25242 [#660 sell 0.03 EURUSD.e at 1.25242]
IK      0       13:34:04.118    Core 1  2014.11.14 22:15:00   CTrade::OrderSend: market sell 0.03 EURUSD.e [done at 1.25242]
IL      0       13:34:04.118    Core 1  2014.11.17 13:30:20   
CJ      0       13:34:04.118    Core 1  2014.11.17 13:30:20   ---=== Сигнал на закрытие: SELL===---
GN      0       13:34:04.118    Core 1  2014.11.17 13:30:20   Позапрошлый бар, главная: -0.001218; сигнальная: -0.001148
QL      0       13:34:04.118    Core 1  2014.11.17 13:30:20   Прошлый бар, главная: -0.001123; сигнальная: -0.001189
EP      0       13:34:04.118    Core 1  2014.11.17 13:30:20   market buy 0.03 EURUSD.e (1.25039 / 1.25047 / 1.25039)
FG      0       13:34:04.118    Core 1  2014.11.17 13:30:20   deal #661 buy 0.03 EURUSD.e at 1.25047 done (based on order #661)
OJ      0       13:34:04.118    Core 1  2014.11.17 13:30:20   deal performed [#661 buy 0.03 EURUSD.e at 1.25047]
PD      0       13:34:04.118    Core 1  2014.11.17 13:30:20   order performed buy 0.03 at 1.25047 [#661 buy 0.03 EURUSD.e at 1.25047]
HE      0       13:34:04.118    Core 1  2014.11.17 13:30:20   CTrade::OrderSend: market buy 0.03 EURUSD.e [done at 1.25047]

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

Поэтому приходится искать "свои" строки. Если есть желание как-то обособить информацию для вывода, то можно записывать ее в файл.

Стратегия для обычного режима тестирования воплощена в коде советника TestMode_tester.mq5.


3.2. Режим визуального тестирования

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

Простая визуализация помогает не только увидеть своими глазами, как торговая система ловит тики, но и сравнить похожие ценовые модели по окончании тестирования.

Определение класса CModeVisual для визуального тестирования может быть таким:

//+------------------------------------------------------------------+
//| Class CModeVisual                                                |
//| Purpose: a class for the tester mode                             |            
//| Derived from class CModeBase.                                    |
//+------------------------------------------------------------------+
class CModeVisual : public CModeTester
  {
//--- === Data members === --- 
private:
   CArrayObj         m_objects_arr;
   double            m_subwindow_max;
   double            m_subwindow_min;
   
//--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CModeVisual(void);
   void             ~CModeVisual(void);

   //--- Procedures
   virtual void      Open(void);
   virtual void      Close(void);

private:
   bool              CreateSignalLine(const bool _is_open_sig,const bool _is_new_bar=true);
   bool              CreateRectangle(const ENUM_ORDER_TYPE _signal);
   void              RefreshRectangles(void);
  };

В классе есть скрытые члены. Член класса m_objects_arr реализует динамический массив типа CArrayObj, в который попадут графические объекты (линии, прямоугольники). Два других члена класса (m_subwindow_max, m_subwindow_min) контролируют максимальный и минимальный размеры подокна индикатора.

Приватные методы отвечают за работу с графическими объектами.

В данном классе нет методов Main() и Trail(). Вызываться будут их родительские аналоги CModeTester::Main() и CModeTester::Trail() соответственно.

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

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

Если позиция была длинной, то цвет прямоугольника будет светло-голубым. Если позиция была короткой, то цвет прямоугольника будет розовым (рис.6).

Рис.6. Графические объекты в визуальном режиме тестирования

Рис.6. Графические объекты в визуальном режиме тестирования

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

В итоге в подокне индикатора MACD получим выраженные участки: неокрашенный (позиции нет), розовый (короткая позиция), светло-голубой (длинная позиция).

Стратегия для визуального режима тестирования воплощена в коде советника TestMode_visual_tester.mq5.


Заключение

В данной статье я стремился продемонстрировать режимные возможности терминала MetaTrader 5 и языка MQL5. Нужно сказать, что мультирежимный подход программирования торгового алгоритма отличается бóльшими затратами с одной стороны, а с другой есть возможность последовательно пройтись по каждому этапу создания будущего робота. Еще раз повторюсь, что здесь как нельзя кстати на подмогу программисту приходит ООП.

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


Прикрепленные файлы |
CisNewBar.mqh (6.99 KB)
Modes.mqh (31.24 KB)
Test1_Modes_EA.mq5 (4.75 KB)
Test2_Modes_EA.mq5 (5.04 KB)
Разнонаправленная торговля и хеджирование позиций в MetaTrader 5 с помощью панели HedgeTerminal, часть 1 Разнонаправленная торговля и хеджирование позиций в MetaTrader 5 с помощью панели HedgeTerminal, часть 1
Статья описывает новый подход в вопросах хеджирования позиций и ставит точку в спорах между пользователями платформ MetaTrader 4 и MetaTrader 5 в этом вопросе. На примере простых схем и диаграмм, общедоступным языком рассказывается об алгоритмах, которые делают такое хеджирование надежным. Статья посвящена описанию новой панели - HedgeTerminal, которая, по сути, является полноценным торговым терминалом внутри самого терминала MetaTrader 5. С ее помощью, благодаря предлагаемой виртуализации торговли, можно управлять своими торговыми позициями так, как это принято в MetaTrader 4.
Основы биржевого ценообразования на примере срочной секции Московской биржи Основы биржевого ценообразования на примере срочной секции Московской биржи
Статья описывает теорию биржевого ценообразования и специфику клиринговых расчетов срочной секции Московской биржи. Материал будет интересен как начинающим трейдерам, желающим получить свой первый биржевой опыт по торговле деривативами, так и опытным форекс-трейдерам, рассматривающих возможность переноса своей торговли на централизованную биржевую площадку.
Разнонаправленная торговля и хеджирование позиций в MetaTrader 5 с помощью API HedgeTerminal, часть 2 Разнонаправленная торговля и хеджирование позиций в MetaTrader 5 с помощью API HedgeTerminal, часть 2
Статья описывает новый подход в вопросах хеджирования позиций и ставит точку в спорах между пользователями платформ MetaTrader 4 и MetaTrader 5 в этом вопросе. Она является продолжением первой части: "Разнонаправленная торговля и хеджирование позиций в MetaTrader 5 с помощью панели API HedgeTerminal". Во второй части описывается интеграция пользовательских экспертов с HedgeTerminalAPI - специальной библиотекой виртуализации, позволяющей торговать разнонаправлено, находясь в комфортном программном окружении, позволяющем легко и просто управлять своими позициями.
Статистические рецепты для трейдера - Гипотезы Статистические рецепты для трейдера - Гипотезы
В данной статье рассматривается базовое понятие математической статистики "гипотеза". На примерах, с применением методов математической статистики, исследуются и проверяются различные гипотезы. Реальные данные обобщаются с помощью непараметрических методов. При обработке данных используются пакет Statistica и портированная библиотека численного анализа ALGLIB MQL5.