English 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Мастер MQL5: Как написать свой модуль торговых сигналов

Мастер MQL5: Как написать свой модуль торговых сигналов

MetaTrader 5Торговые системы | 28 декабря 2010, 08:20
14 969 57
MetaQuotes
MetaQuotes

Введение

В MetaTrader 5 имеется достаточно мощный инструмент для быстрой проверки торговых идей. Это генератор торговых стратегий Мастера MQL5. Использование Мастера MQL5 для автоматического создания кода советников рассмотрено в статье "Мастер MQL5: Создание эксперта без программирования". Открытость системы генерации кода позволяет добавлять к стандартным свои собственные классы торговых сигналов, системы управления капиталом и модули трейлинга.

В данной статье рассмотрены принципы написания модулей торговых сигналов для их последующего использования при создании экспертов Мастером MQL5.

Эксперт, который создается Мастером MQL5, стоит на четырех столпах - четырех базовых классах:

Рисунок 1. Структура базового класса CExpert

Рисунок 1. Структура базового класса CExpert

Класс CExpert (или его наследник) является главным "двигателем"  торгового робота. Экземпляр класса CExpert содержит в себе по одному экземпляру классов CExpertSignal, CExpertMoney и CExpertTrailing (или их наследников):

  1. CExpertSignal  - является основой генератора торговых сигналов. Экземпляр наследника класса CExpertSignal, включенный в состав класса CExpert, основываясь на встроенных алгоритмах, предоставляет эксперту информацию о возможности входа в рынок, уровнях входа и установки защитных ордеров. Окончательно решение по совершению торговых операций принимает эксперт.
  2. CExpertMoney - является основой системы управления капиталом и рисками. Экземпляр наследника класса CExpertMoney вычисляет объемы для открытия позиций и установки отложенных ордеров. Окончательное решение по объемам принимает эксперт.
  3. CExpertTrailing - является основой модуля сопровождения открытых позиций. Экземпляр наследника класса CExpertTrailing сообщает эксперту о необходимости модификации защитных ордеров позиции. Окончательное решение по модификации ордеров принимает эксперт.

Кроме того, членами класса CExpert являются экземпляры классов:

  • CExpertTrade (для осуществления торговых операций)
  • CIndicators (для управления индикаторами и таймсериями, задействованными в работе эксперта).
  • CSymbolInfo (для получения информации об инструменте)
  • CAccountInfo (для получения информации о состоянии торгового счета)
  • CPositionInfo (для получения информации о позициях)
  • COrderInfo (для получения информации об отложенных ордерах)

Далее по тексту, говоря "эксперт", мы будем подразумевать экземпляр класса CExpert или его наследника.

Более подробно класс CExpert и работа с ним будут рассмотрены в отдельной статье.


1. Базовый класс CExpertSignal

Класс CExpertSignal является основой генератора торговых сигналов. Для связи с "внешним миром" класс CExpertSignal имеет набор публичных виртуальных методов:

Инициализация

 Описание

virtual Init

Инициализация экземпляра класса обеспечивает синхронизацию данных модуля с данными эксперта

virtual ValidationSettings

Проверка корректности установленных параметров

virtual InitIndicators

Создание и инициализация всех индикаторов и таймсерий, необходимых для работы генератора торговых сигналов

Сигналы открытия/разворота/закрытия позиций

 

virtual CheckOpenLong

Генерация сигнала открытия длинной позиции с определением уровней входа и установки защитных ордеров

virtual CheckOpenShort

Генерация сигнала открытия короткой позиции с определением уровней входа и установки защитных ордеров

virtual CheckCloseLong

Генерация сигнала закрытия длинной позиции с определением уровня выхода

virtual CheckCloseShort

Генерация сигнала закрытия короткой позиции с определением уровня выхода

virtual CheckReverseLong

Генерация сигнала разворота длинной позиции, с определением уровней разворота и установки защитных ордеров

virtual CheckReverseShort

Генерация сигнала разворота короткой позиции, с определением уровней разворота и установки защитных ордеров

Управление отложенными ордерами

 

virtual CheckTrailingOrderLong

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

virtual CheckTrailingOrderShort

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

Описание методов

1.1. Методы инициализации:

1.1.1 Init

Метод Init() автоматически вызывается сразу после присоединения экземпляра класса к эксперту. Переопределения метода не требуется.

virtual bool Init(CSymbolInfo* symbol, ENUM_TIMEFRAMES period, double adjusted_point);

1.1.2 ValidationSettings

Метод ValidationSettings()  вызывается из эксперта после установки всех параметров. Необходимо переопределить метод в случае наличия параметров настройки.

virtual bool ValidationSettings();

Переопределенный метод должен возвращать true, если все параметры корректны (пригодны для использования). Если хотя бы один из параметров неверный, метод должен возвращать false (дальнейшая работа невозможна).

Базовый класс CExpertSignal не имеет устанавливаемых параметров, соответственно, метод базового класса, не выполняя никаких проверок, всегда возвращает true.

1.1.3 InitIndicators

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

virtual bool InitIndicators(CIndicators* indicators);

Индикаторы и/или таймсерии должны использоваться через соответствующие классы Стандартной библиотеки. Указатели всех индикаторов и/или таймсерий должны быть добавлены в коллекцию индикаторов эксперта (указатель на которую передается в качестве параметра).

Переопределенный метод должен возвращать true, если все манипуляции с индикаторами и/или таймсериями прошли успешно (они пригодны для использования). В случае если хотя бы одна операция с индикаторами и/или таймсериями завершилась с ошибкой, метод должен возвращать false (дальнейшая работа невозможна).

Базовый класс CExpertSignal не использует индикаторов и таймсерий, соответственно, метод базового класса всегда возвращает true, не выполняя никаких действий.


1.2. Методы проверки сигнала открытия позиции:

1.2.1 CheckOpenLong

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

virtual bool CheckOpenLong(double& price, double& sl, double& tp, datetime& expiration);

Метод должен реализовывать алгоритм проверки условия открытия длинной позиции.  Если условие выполнилось, переменным price, sl, tp и expiration (ссылки на которые передаются в качестве параметров) должны быть присвоены соответствующие значения и метод должен вернуть true. Если условие не выполнилось, метод должен вернуть false.

Базовый класс CExpertSignal не имеет встроенного алгоритма генерации сигнала открытия длинной позиции, поэтому метод базового класса всегда возвращает false.

1.2.2 CheckOpenShort

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

virtual bool CheckOpenShort(double& price, double& sl, double& tp, datetime& expiration);

Метод должен реализовывать алгоритм проверки условия открытия короткой позиции. Если условие выполнилось, переменным price, sl, tp и expiration (ссылки на которые передаются в качестве параметров) должны быть присвоены соответствующие значения и метод должен вернуть true. Если условие не выполнилось, метод должен вернуть false.

Базовый класс CExpertSignal не имеет встроенного алгоритма генерации сигнала открытия короткой позиции, поэтому метод базового класса всегда возвращает false.


1.3. Методы проверки сигнала закрытия позиции:

1.3.1 CheckCloseLong

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

virtual bool CheckCloseLong(double& price);

Метод должен реализовывать алгоритм проверки условия закрытия длинной позиции. Если условие выполнилось, переменной price (ссылка на которую передается в качестве параметра) должно быть присвоено соответствующее значение и метод должен вернуть true. Если условие не выполнилось, метод должен вернуть false.

Базовый класс CExpertSignal не имеет встроенного алгоритма генерации сигнала закрытия длинной позиции, поэтому метод базового класса всегда возвращает false.

1.3.2 CheckCloseShort

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

virtual bool CheckCloseShort(double& price);

Метод должен реализовывать алгоритм проверки условия закрытия короткой позиции. Если условие выполнилось, переменной price (ссылка на которую передается в качестве параметра) должно быть присвоено соответствующее значение и метод должен вернуть true. Если условие не выполнилось, метод должен вернуть false.

Базовый класс CExpertSignal не имеет встроенного алгоритма генерации сигнала закрытия короткой позиции, поэтому метод базового класса всегда возвращает false.


1.4. Методы проверки сигнала разворота позиции:

1.4.1 CheckReverseLong

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

virtual bool CheckReverseLong(double& price, double& sl, double& tp, datetime& expiration);

Метод должен реализовывать алгоритм проверки условия разворота длинной позиции. Если условие выполнилось, переменным price, sl, tp и expiration (ссылки на которые передаются в качестве параметров) должны быть присвоены соответствующие значения и метод должен вернуть true. Если условие не выполнилось, метод должен вернуть false.

В базовом классе CExpertSignal реализован следующий алгоритм генерации сигнала разворота длинной позиции:

  1. Проверяется наличие сигнала закрытия длинной позиции.
  2. Проверяется наличие сигнала открытия короткой позиции.
  3. Если оба сигнала активны (условия выполнены) и цены закрытия и открытия совпадают, переменным price, sl, tp и expiration (ссылки на которые переданы в качестве параметров) присваиваются соответствующие значения и метод возвращает true.
Если условие не выполнилось, метод возвращает false.

1.4.2 CheckReverseShort

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

virtual bool CheckReverseShort(double& price, double& sl, double& tp, datetime& expiration);

Метод должен реализовывать алгоритм проверки условия разворота короткой позиции. Если условие выполнилось, переменным price, sl, tp и expiration (ссылки на которые передаются в качестве параметров) должны быть присвоены соответствующие значения и метод должен вернуть true. Если условие не выполнилось, метод должен вернуть false.

В базовом классе CExpertSignal реализован следующий алгоритм генерации сигнала разворота короткой позиции:

  1. Проверяется наличие сигнала закрытия короткой позиции.
  2. Проверяется наличие сигнала открытия длинной позиции.
  3. Если оба сигнала активны (условия выполнены) и цены закрытия и открытия совпадают, переменным price, sl, tp и expiration (ссылки на которые переданы в качестве параметров) присваиваются соответствующие значения и метод возвращает true.

Если условие не выполнилось, метод возвращает false.


1.5. Методы проверки сигнала модификации отложенного ордера:

1.5.1 CheckTrailingOrderLong

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

virtual bool CheckTrailingOrderLong(COrderInfo* order, double& price)

Метод должен реализовывать алгоритм проверки условия модификации отложенного ордера на покупку. Если условие выполнилось, переменной price (ссылка на которую передается в качестве параметра) должно быть присвоено соответствующее значение и метод должен вернуть true. Если условие не выполнилось, метод должен вернуть false.

Базовый класс CExpertSignal не имеет встроенного алгоритма генерации сигнала модификации отложенного ордера на покупку, поэтому метод базового класса всегда возвращает false.

1.5.2 CheckTrailingOrderShort

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

virtual bool CheckTrailingOrderShort(COrderInfo* order, double& price)

Метод должен реализовывать алгоритм проверки условия модификации отложенного ордера на продажу. Если условие выполнилось, переменной price (ссылка на которую передается в качестве параметра) должно быть присвоено соответствующее значение и метод должен вернуть true. Если условие не выполнилось, метод должен вернуть false.

Базовый класс CExpertSignal не имеет встроенного алгоритма генерации сигнала модификации отложенного ордера на продажу, поэтому метод базового класса всегда возвращает false.


2. Пишем свой генератор торговых сигналов

Теперь, когда мы рассмотрели структуру базового класса CExpertSignal, можно приступать к созданию собственного генератора торговых сигналов.

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

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

Вторая наша задача (не менее важная) - сделать так, чтобы наш класс "увидел" Мастер MQL5. Но, обо всем по порядку.

2.1. Создание класса генератора торговых сигналов

Приступим.

Для начала создадим (например, при помощи того же Мастера MQL5) включаемый файл с расширением mqh.

Выберем в меню Файл пункт "Создать" (или комбинацией клавиш Ctrl+N) и укажем создание включаемого файла:

Рисунок 2. Создаем включаемый файл Мастером MQL5.

Рисунок 2. Создаем включаемый файл Мастером MQL5.

Следует отметить, что для того чтобы этот файл был потом "обнаружен" Мастером MQL5 как генератор сигналов, его следует создать в папке Include\Expert\Signal\.

Для того чтобы не "мусорить" в Стандартной библиотеке, создадим свою папку Include\Expert\Signal\MySignals а в ней файл SampleSignal.mqh, указав эти параметры в Мастере МQL5:

Рисунок 3. Настройка расположения включаемого файла

Рисунок 3. Настройка расположения включаемого файла

В результате работы Мастера MQL5 получился шаблон:

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
// #define MacrosHello   "Hello, world!"
// #define MacrosYear    2010
//+------------------------------------------------------------------+
//| DLL imports                                                      |
//+------------------------------------------------------------------+
// #import "user32.dll"
//   int      SendMessageA(int hWnd,int Msg,int wParam,int lParam);
// #import "my_expert.dll"
//   int      ExpertRecalculate(int wParam,int lParam);
// #import
//+------------------------------------------------------------------+
//| EX5 imports                                                      |
//+------------------------------------------------------------------+
// #import "stdlib.ex5"
//   string ErrorDescription(int error_code);
// #import
//+------------------------------------------------------------------+

Далее следует исключительно "ручная" работа. Уберем лишнее и добавим необходимое (включаемый файл ExpertSignal.mqh Стандартной библиотеки и пока пустое описание класса).

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+

//| включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| Класс CSampleSignal.                                             |
//| Назначение: Класс генератора торговых сигналов.                  |
//|             Является производным от класса CExpertSignal.        |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
  };
//+------------------------------------------------------------------+

Теперь, необходимо определиться с алгоритмами.

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

Вообще, когда что-нибудь пишете, не скупитесь на комментарии. По прошествии некоторого времени, чтение тщательно комментированного кода бывает неожиданно приятным.

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| Класс CSampleSignal.                                             |
//| Назначение: Класс генератора торговых сигналов по пересечению    |
//|             ценой скользящей средней                             |
//|             со входом на последующем откате.                     |
//|             Является производным от класса CExpertSignal.        |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
  };
//+------------------------------------------------------------------+

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

Чтобы получить доступ к этим данным, будем использовать классы стандартной библиотеки CiOpen, CiClose и CiMA. Об индикаторах и таймсериях мы поговорим позже.

А пока, определим список параметров настройки нашего генератора. Во-первых, нам нужно настраивать скользящую среднюю. Это параметры период, сдвиг по оси времени, метод усреднения и объект усреднения.  Во-вторых, нам нужно настраивать уровень входа и уровни установки защитных ордеров и время "жизни" отложенного ордера, так как мы предполагаем работать с отложенными ордерами.

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

Отразим эти изменения в нашем файле:

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| Класс CSampleSignal.                                             |
//| Назначение: Класс генератора торговых сигналов по пересечению    |
//|             ценой скользящей средней                             |
//|             со входом на последующем откате.                     |
//|             Является производным от класса CExpertSignal.        |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
protected:
   //--- параметры настройки
   int                m_period_ma;       // период усреднения средней скользящей
   int                m_shift_ma;        // смещение средней скользящей по оси времени
   ENUM_MA_METHOD     m_method_ma;       // метод усреднения средней скользящей
   ENUM_APPLIED_PRICE m_applied_ma;      // объект усреднения средней скользящей
   double             m_limit;           // уровень установки отложенного ордера относительно средней скользящей
   double             m_stop_loss;       // уровень установки ордера "stop loss" относительно цены открытия
   double             m_take_profit;     // уровень установки ордера "take profit" относительно цены открытия
   int                m_expiration;      // время "жизни" отложенного ордера в барах

public:
   //--- методы установки параметров настройки
   void               PeriodMA(int value)                 { m_period_ma=value;   }
   void               ShiftMA(int value)                  { m_shift_ma=value;    }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;   }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;  }
   void               Limit(double value)                 { m_limit=value;       }
   void               StopLoss(double value)              { m_stop_loss=value;   }
   void               TakeProfit(double value)            { m_take_profit=value; }
   void               Expiration(int value)               { m_expiration=value;  }
  };
//+------------------------------------------------------------------+

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

Для проверки параметров настройки переопределим виртуальный метод ValidationSettings согласно описанию базового класса.

Описание класса:

class CSampleSignal : public CExpertSignal
  {
protected:
   //--- параметры настройки
   int                m_period_ma;       // период усреднения средней скользящей
   int                m_shift_ma;        // смещение средней скользящей по оси времени
   ENUM_MA_METHOD     m_method_ma;       // метод усреднения средней скользящей
   ENUM_APPLIED_PRICE m_applied_ma;      // объект усреднения средней скользящей
   double             m_limit;            // уровень установки отложенного ордера относительно средней скользящей
   double             m_stop_loss;        // уровень установки ордера "stop loss" относительно цены открытия
   double             m_take_profit;      // уровень установки ордера "take profit" относительно цены открытия
   int                m_expiration;       // время "жизни" отложенного ордера в барах

public:
                      CSampleSignal();
   //--- методы установки параметров настройки
   void               PeriodMA(int value)                 { m_period_ma=value;   }
   void               ShiftMA(int value)                  { m_shift_ma=value;    }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;   }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;  }
   void               Limit(double value)                 { m_limit=value;       }
   void               StopLoss(double value)              { m_stop_loss=value;   }
   void               TakeProfit(double value)            { m_take_profit=value; }
   void               Expiration(int value)               { m_expiration=value;  }
   //--- метод проверки параметров настройки
   virtual bool       ValidationSettings();
  };

Реализация метода ValidationSettings():


//+------------------------------------------------------------------+
//| Проверка параметров настройки.                                   |
//| INPUT:  нет.                                                     |
//| OUTPUT: true-если настройки правильные, иначе false.             |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::ValidationSettings()
  {
//--- проверка параметров
   if(m_period_ma<=0)
     {
      printf(__FUNCTION__+": период средней скользящей должен быть больше нуля");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+

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

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

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

Чтобы получить доступ к этим данным, будем использовать следующие классы Стандартной библиотеки:

  • CiOpen - для доступа к цене открытия предыдущего бара,
  • CiClose - для доступа к цене закрытия предыдущего бара,
  • CiMA   - для доступа к значению скользящей средней на предыдущем баре.

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

В этом есть тайный смысл, который мы с вами сейчас и раскроем.

Как использовать данные индикатора или таймсерии?

Во-первых, нужно создать индикатор.

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

В-третьих, нужно проверить правильно ли завершилось копирование.

И только после этих действий можно использовать данные.

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

Объекты этих классов мы разместим в защищенных членах-данных. Для каждого объекта создадим метод инициализации и метод доступа к данным.

Переопределим виртуальный метод InitIndicators (согласно описанию базового класса).

Описание класса:

class CSampleSignal : public CExpertSignal
  {
protected:
   CiMA               m_MA;              // объект для доступа к значениям скользящей средней
   CiOpen             m_open;            // объект для доступа к ценам открытия баров
   CiClose            m_close;           // объект для доступа к ценам закрытия баров
   //--- параметры настройки
   int                m_period_ma;       // период усреднения средней скользящей
   int                m_shift_ma;        // смещение средней скользящей по оси времени
   ENUM_MA_METHOD     m_method_ma;       // метод усреднения средней скользящей
   ENUM_APPLIED_PRICE m_applied_ma;      // объект усреднения средней скользящей
   double             m_limit;            // уровень установки отложенного ордера относительно средней скользящей
   double             m_stop_loss;        // уровень установки ордера "stop loss" относительно цены открытия
   double             m_take_profit;      // уровень установки ордера "take profit" относительно цены открытия
   int                m_expiration;      // время "жизни" отложенного ордера в барах

public:
                      CSampleSignal();
   //--- методы установки параметров настройки
   void               PeriodMA(int value)                 { m_period_ma=value;              }
   void               ShiftMA(int value)                  { m_shift_ma=value;               }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;              }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;             }
   void               Limit(double value)                 { m_limit=value;                  }
   void               StopLoss(double value)              { m_stop_loss=value;              }
   void               TakeProfit(double value)            { m_take_profit=value;            }
   void               Expiration(int value)               { m_expiration=value;             }
   //--- метод проверки параметров настройки
   virtual bool       ValidationSettings();
   //--- метод проверки параметров настройки
   virtual bool       InitIndicators(CIndicators* indicators);

protected:
   //--- метод инициализации объектов
   bool               InitMA(CIndicators* indicators);
   bool               InitOpen(CIndicators* indicators);
   bool               InitClose(CIndicators* indicators);
   //--- методы доступа к данным объектов
   double             MA(int index)                       { return(m_MA.Main(index));       }
   double             Open(int index)                     { return(m_open.GetData(index));  }
   double             Close(int index)                    { return(m_close.GetData(index)); }
  };

Реализация методов InitIndicators, InitMA, InitOpen, InitClose:

//+------------------------------------------------------------------+
//| Инициализация индикаторов и таймсерий.                           |
//| INPUT:  indicators - указатель на объект-коллекцию               |
//|                      индикаторов и таймсерий.                    |
//| OUTPUT: true-в случае успешного завершения, иначе false.         |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::InitIndicators(CIndicators* indicators)
  {
//--- проверка указателя
   if(indicators==NULL)       return(false);
//--- инициализация скользящей средней
   if(!InitMA(indicators))    return(false);
//--- инициализация таймсерии цен открытия
   if(!InitOpen(indicators))  return(false);
//--- инициализация таймсерии цен закрытия
   if(!InitClose(indicators)) return(false);
//--- успешное завершение
   return(true);
  }
//+------------------------------------------------------------------+
//| Инициализация скользящей средней.                                |
//| INPUT:  indicators - указатель на объект-коллекцию               |
//|                      индикаторов и таймсерий.                    |
//| OUTPUT: true-в случае успешного завершения, иначе false.         |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::InitMA(CIndicators* indicators)
  {
//--- инициализация объекта скользящей средней
   if(!m_MA.Create(m_symbol.Name(),m_period,m_period_ma,m_shift_ma,m_method_ma,m_applied_ma))
     {
      printf(__FUNCTION__+": ошибка инициализации объекта");
      return(false);
     }
   m_MA.BufferResize(3+m_shift_ma);
//--- добавление объекта в коллекцию
   if(!indicators.Add(GetPointer(m_MA)))
     {
      printf(__FUNCTION__+": ошибка добавления объекта");
      return(false);
     }
//--- успешное завершение
   return(true);
  }
//+------------------------------------------------------------------+
//| Инициализация таймсерии цен открытия.                            |
//| INPUT:  indicators - указатель на объект-коллекцию               |
//|                      индикаторов и таймсерий.                    |
//| OUTPUT: true-в случае успешного завершения, иначе false.         |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::InitOpen(CIndicators* indicators)
  {
//--- инициализация объекта таймсерии
   if(!m_open.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": ошибка инициализации объекта");
      return(false);
     }
//--- добавление объекта в коллекцию
   if(!indicators.Add(GetPointer(m_open)))
     {
      printf(__FUNCTION__+": ошибка добавления объекта");
      return(false);
     }
//--- успешное завершение
   return(true);
  }
//+------------------------------------------------------------------+
//| Инициализация таймсерии цен закрытия.                            |
//| INPUT:  indicators - указатель на объект-коллекцию               |
//|                      индикаторов и таймсерий.                    |
//| OUTPUT: true-в случае успешного завершения, иначе false.         |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::InitClose(CIndicators* indicators)
  {
//--- инициализация объекта таймсерии
   if(!m_close.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": ошибка инициализации объекта");
      return(false);
     }
//--- добавление объекта в коллекцию
   if(!indicators.Add(GetPointer(m_close)))
     {
      printf(__FUNCTION__+": ошибка добавления объекта");
      return(false);
     }
//--- успешное завершение
   return(true);
  }
//+------------------------------------------------------------------+

Все подготовительные работы выполнены. Как видим, наш класс заметно вырос.

Но теперь мы готовы к генерации торговых сигналов.

Рисунок 4. Торговые сигналы по пересечению цены скользящей средней

Рисунок 4. Торговые сигналы по пересечению цены скользящей средней

Рассмотрим наши алгоритмы еще раз, более подробно.

1. Сигнал на покупку возникает тогда, когда на предыдущем баре выполнились следующие условия:

  • цена открытия бара меньше значения скользящей средней,
  • цена закрытия бара больше значения скользящей средней,
  • скользящая средняя растет.

При этом предложим установить отложенный ордер на покупку с параметрами, определяемыми настройками. Для этого мы переопределим виртуальный метод CheckOpenLong и наполним его соответствующим функционалом.

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

  • цена открытия бара больше значения скользящей средней,
  • цена закрытия бара меньше значения скользящей средней,
  • скользящая средняя снижается.

При этом предложим установить отложенный ордер на продажу с параметрами, определяемыми настройками. Для этого мы переопределим виртуальный метод CheckOpenShort и наполним его соответствующим функционалом.

3. Сигналы на закрытия позиций мы генерировать не будем. Пусть позиции закрываются по Stop Loss/Take Profit ордерам.

Соответственно, виртуальные методы CheckCloseLong и CheckCloseShort мы переопределять не будем.

4. Мы будем предлагать модификацию отложенного ордера вдоль скользящей средней на заданном настройкой "расстоянии".

 Для этого мы переопределим виртуальные методы CheckTrailingOrderLong и CheckTrailingOrderShort, наполнив их соответствующим функционалом.

Описание класса:

class CSampleSignal : public CExpertSignal
  {
protected:
   CiMA               m_MA;              // объект для доступа к значениям скользящей средней
   CiOpen             m_open;            // объект для доступа к ценам открытия баров
   CiClose            m_close;           // объект для доступа к ценам закрытия баров
   //--- параметры настройки
   int                m_period_ma;       // период усреднения средней скользящей
   int                m_shift_ma;        // смещение средней скользящей по оси времени
   ENUM_MA_METHOD     m_method_ma;       // метод усреднения средней скользящей
   ENUM_APPLIED_PRICE m_applied_ma;      // объект усреднения средней скользящей
   double             m_limit;            // уровень установки отложенного ордера относительно средней скользящей
   double             m_stop_loss;        // уровень установки ордера "stop loss" относительно цены открытия
   double             m_take_profit;      // уровень установки ордера "take profit" относительно цены открытия
   int                m_expiration;       // время "жизни" отложенного ордера в барах

public:
                      CSampleSignal();
   //--- методы установки параметров настройки

   void               PeriodMA(int value)                 { m_period_ma=value;              }
   void               ShiftMA(int value)                  { m_shift_ma=value;               }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;              }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;             }
   void               Limit(double value)                 { m_limit=value;                  }
   void               StopLoss(double value)              { m_stop_loss=value;              }
   void               TakeProfit(double value)            { m_take_profit=value;            }
   void               Expiration(int value)               { m_expiration=value;             }
   //--- метод проверки параметров настройки
   virtual bool       ValidationSettings();
   //--- метод проверки параметров настройки
   virtual bool       InitIndicators(CIndicators* indicators);
   //--- методы генерации сигналов входа в рынок
   virtual bool      CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration);
   virtual bool      CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration);
   //--- методы генерации сигналов модификации отложенных ордеров
   virtual bool      CheckTrailingOrderLong(COrderInfo* order,double& price);
   virtual bool      CheckTrailingOrderShort(COrderInfo* order,double& price);

protected:
   //--- метод инициализации объектов
   bool               InitMA(CIndicators* indicators);
   bool               InitOpen(CIndicators* indicators);
   bool               InitClose(CIndicators* indicators);
   //--- методы доступа к данным объектов
   double             MA(int index)                       { return(m_MA.Main(index));       }
   double             Open(int index)                     { return(m_open.GetData(index));  }
   double             Close(int index)                    { return(m_close.GetData(index)); }
  };

Реализация методов CheckOpenLong, CheckOpenShort, CheckTrailingOrderLong, CheckTrailingOrderShort:

//+------------------------------------------------------------------+
//| Проверка выполнения условия для покупки.                         |
//| INPUT:  price      - ссылка для размещения цены открытия,        |
//|         sl         - ссылка для размещения цены stop loss,       |
//|         tp         - ссылка для размещения цены take profit,     |
//|         expiration - ссылка для размещения времени истечения.    |
//| OUTPUT: true-если условие выполнено, иначе false.                |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- подготовка данных
   double spread=m_symbol.Ask()-m_symbol.Bid();
   double ma    =MA(1);
   double unit  =PriceLevelUnit();
//--- проверка условия
   if(Open(1)<ma && Close(1)>ma && ma>MA(2))
     {
      price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
      sl   =m_symbol.NormalizePrice(price-m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price+m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- условие выполнено
      return(true);
     }
//--- условие не выполнено
   return(false);
  }
//+------------------------------------------------------------------+
//| Проверка выполнения условия для продажи.                         |
//| INPUT:  price      - ссылка для размещения цены открытия,        |
//|         sl         - ссылка для размещения цены stop loss,       |
//|         tp         - ссылка для размещения цены take profit,     |
//|         expiration - ссылка для размещения времени истечения.    |
//| OUTPUT: true-если условие выполнено, иначе false.                |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- подготовка данных
   double ma  =MA(1);
   double unit=PriceLevelUnit();
//--- проверка условия
   if(Open(1)>ma && Close(1)<ma && ma<MA(2))
     {
      price=m_symbol.NormalizePrice(ma+m_limit*unit);
      sl   =m_symbol.NormalizePrice(price+m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price-m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- условие выполнено
      return(true);
     }
//--- условие не выполнено
   return(false);
  }
//+------------------------------------------------------------------+
//| Проверка выполнения условия для модификации ордера на покупку.   |
//| INPUT:  order - указатель на объект-ордер,                       |
//|         price - ссылка для размещения новой цены открытия.       |
//| OUTPUT: true-если условие выполнено, иначе false.                |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderLong(COrderInfo* order,double& price)
  {
//--- проверка указателя
   if(order==NULL) return(false);
//--- подготовка данных
   double spread   =m_symbol.Ask()-m_symbol.Bid();
   double ma       =MA(1);
   double unit     =PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
//--- проверка условия
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- условие выполнено
   return(true);
  }
//+------------------------------------------------------------------+
//| Проверка выполнения условия для модификации ордера на продажу.   |
//| INPUT:  order - указатель на объект-ордер,                       |
//|         price - ссылка для размещения новой цены открытия.       |
//| OUTPUT: true-если условие выполнено, иначе false.                |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderShort(COrderInfo* order,double& price)
  {
//--- проверка указателя
   if(order==NULL) return(false);
//--- подготовка данных
   double ma  =MA(1);
   double unit=PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma+m_limit*unit);
//--- проверка условия
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- условие выполнено
   return(true);
  }
//+------------------------------------------------------------------+

Первую задачу мы решили. Приведенный выше код - это "исходник" класса генератора торговых сигналов, удовлетворяющего нашему "Техническому Заданию".


2.2. Создание описания созданного класса торговых сигналов для Мастера MQL5

Теперь перейдем к решению второй задачи. Наш сигнал должен "опознаваться" генератором торговых стратегий Мастера MQL5.

Первое необходимое условие мы выполнили: разместили файл там, где его "обнаружит" Мастер MQL5. Но этого мало. Мастер MQL5 должен не только "обнаружить" файл, но и "опознать" его. Для этого нам нужно добавить в исходный текст описатель класса для Мастера MQL5.

Описатель класса - это блок комментариев, составленный по определенным правилам.

Рассмотрим эти правила.

1. Блок комментариев должен начинаться строками:

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |

2. Следующая строка - это текстовый описатель (то, что мы увидим в Мастере MQL5 при выборе сигнала) в формате "//| Title=<Текст> |". Если текст великоват для одной строки, следом за ней можно добавить еще одну (но не более). 

В нашем случае получится:

//| Title=Сигнал по пересечению цены и скользящей средней            |
//| со входом на откате                                              |

3. Дальше следует строка с указанием типа класса в формате "//| Type=<Тип> |". Поле <Тип> должно иметь значение Signal (кроме сигналов Мастер MQL5 знает и другие типы классов).

Пишем:

//| Type=Signal                                                      |

4. Следующая строка в формате "//| Name=<Имя> |" - короткое имя сигнала (используется Мастером MQL5 для генерации уникальных имен глобальных переменных эксперта).

У нас будет:

//| Name=Sample                                                      |

5. Имя класса - важный элемент описания. В строке с форматом "//| Class=<ИмяКласса> |", параметр <ИмяКласса> должен совпадать с именем нашего класса:

//| Class=CSampleSignal                                              |

6. Эта строка нами не заполняется, но присутствовать обязана (это ссылка на раздел справки):

//| Page=                                                            |

7. Далее идут описания параметров настройки сигнала.

Это набор строк (количество строк совпадает с количеством параметров настройки).

Формат каждой строки "//| Parameter=<ИмяМетода>,<ТипПараметра>,<ЗначениеПоУмолчанию> |".

Наш набор параметров будет выглядеть так:

//| Parameter=PeriodMA,int,12                                        |
//| Parameter=ShiftMA,int,0                                          |
//| Parameter=MethodMA,ENUM_MA_METHOD,MODE_EMA                       |
//| Parameter=AppliedMA,ENUM_APPLIED_PRICE,PRICE_CLOSE               |
//| Parameter=Limit,double,0.0                                       |
//| Parameter=StopLoss,double,50.0                                   |
//| Parameter=TakeProfit,double,50.0                                 |
//| Parameter=Expiration,int,10                                      |

8. Блок комментариев должен заканчиваться строками:

//+------------------------------------------------------------------+
// wizard description end

Добавим описатель в исходный код.

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Сигнал по пересечению цены и скользящей средней            |
//| со входом на откате                                              |
//| Type=Signal                                                      |
//| Name=Sample                                                      |
//| Class=CSampleSignal                                              |
//| Page=                                                            |
//| Parameter=PeriodMA,int,12                                        |
//| Parameter=ShiftMA,int,0                                          |
//| Parameter=MethodMA,ENUM_MA_METHOD,MODE_EMA                       |
//| Parameter=AppliedMA,ENUM_APPLIED_PRICE,PRICE_CLOSE               |
//| Parameter=Limit,double,0.0                                       |
//| Parameter=StopLoss,double,50.0                                   |
//| Parameter=TakeProfit,double,50.0                                 |
//| Parameter=Expiration,int,10                                      |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Класс CSampleSignal.                                             |
//| Назначение: Класс генератора торговых сигналов по пересечению    |
//|             ценой скользящей средней                             |
//|             со входом на последующем откате.                     |
//|             Является производным от класса CExpertSignal.        |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
protected:
   CiMA               m_MA;               // объект для доступа к значениям скользящей средней
   CiOpen             m_open;             // объект для доступа к ценам открытия баров
   CiClose            m_close;            // объект для доступа к ценам закрытия баров
   //--- параметры настройки
   int                m_period_ma;        // период усреднения средней скользящей
   int                m_shift_ma;         // смещение средней скользящей по оси времени
   ENUM_MA_METHOD     m_method_ma;       // метод усреднения средней скользящей
   ENUM_APPLIED_PRICE m_applied_ma;      // объект усреднения средней скользящей
   double             m_limit;            // уровень установки отложенного ордера относительно средней скользящей
   double             m_stop_loss;        // уровень установки ордера "stop loss" относительно цены открытия
   double             m_take_profit;      // уровень установки ордера "take profit" относительно цены открытия
   int                m_expiration;       // время "жизни" отложенного ордера в барах

public:
                      CSampleSignal();
   //--- методы установки параметров настройки
   void               PeriodMA(int value)                 { m_period_ma=value;              }
   void               ShiftMA(int value)                  { m_shift_ma=value;               }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;              }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;             }
   void               Limit(double value)                 { m_limit=value;                  }
   void               StopLoss(double value)              { m_stop_loss=value;              }
   void               TakeProfit(double value)            { m_take_profit=value;            }
   void               Expiration(int value)               { m_expiration=value;             }
   //--- метод проверки параметров настройки
   virtual bool       ValidationSettings();
   //--- метод проверки параметров настройки
   virtual bool       InitIndicators(CIndicators* indicators);
   //--- методы генерации сигналов входа в рынок
   virtual bool      CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration);
   virtual bool      CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration);
   //--- методы генерации сигналов модификации отложенных ордеров
   virtual bool      CheckTrailingOrderLong(COrderInfo* order,double& price);
   virtual bool      CheckTrailingOrderShort(COrderInfo* order,double& price);

protected:
   //--- метод инициализации объектов
   bool               InitMA(CIndicators* indicators);
   bool               InitOpen(CIndicators* indicators);
   bool               InitClose(CIndicators* indicators);
   //--- методы доступа к данным объектов
   double             MA(int index)                       { return(m_MA.Main(index));       }
   double             Open(int index)                     { return(m_open.GetData(index));  }
   double             Close(int index)                    { return(m_close.GetData(index)); }
  };
//+------------------------------------------------------------------+
//| Конструктор CSampleSignal.                                       |
//| INPUT:  нет.                                                     |
//| OUTPUT: нет.                                                     |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
void CSampleSignal::CSampleSignal()
  {
//--- установка значений по-умолчанию
   m_period_ma  =12;
   m_shift_ma   =0;
   m_method_ma  =MODE_EMA;
   m_applied_ma =PRICE_CLOSE;
   m_limit      =0.0;
   m_stop_loss  =50.0;
   m_take_profit=50.0;
   m_expiration =10;
  }
//+------------------------------------------------------------------+
//| Проверка параметров настройки.                                   |
//| INPUT:  нет.                                                     |
//| OUTPUT: true-если настройки правильные, иначе false.             |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::ValidationSettings()
  {
//--- проверка параметров
   if(m_period_ma<=0)
     {
      printf(__FUNCTION__+": период скользящей средней должен быть больше нуля");
      return(false);
     }
//--- успешное завершение
   return(true);
  }
//+------------------------------------------------------------------+
//| Инициализация индикаторов и таймсерий.                           |
//| INPUT:  indicators - указатель на объект-коллекцию               |
//|                      индикаторов и таймсерий.                    |
//| OUTPUT: true-в случае успешного завершения, иначе false.         |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::InitIndicators(CIndicators* indicators)
  {
//--- проверка указателя
   if(indicators==NULL)       return(false);
//--- инициализация скользящей средней
   if(!InitMA(indicators))    return(false);
//--- инициализация таймсерии цен открытия
   if(!InitOpen(indicators))  return(false);
//--- инициализация таймсерии цен закрытия
   if(!InitClose(indicators)) return(false);
//--- успешное завершение
   return(true);
  }
//+------------------------------------------------------------------+
//| Инициализация скользящей средней.                                |
//| INPUT:  indicators - указатель на объект-коллекцию               |
//|                      индикаторов и таймсерий.                    |
//| OUTPUT: true-в случае успешного завершения, иначе false.         |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::InitMA(CIndicators* indicators)
  {
//--- инициализация объекта скользящей средней
   if(!m_MA.Create(m_symbol.Name(),m_period,m_period_ma,m_shift_ma,m_method_ma,m_applied_ma))
     {
      printf(__FUNCTION__+": ошибка инициализации объекта");
      return(false);
     }
   m_MA.BufferResize(3+m_shift_ma);
//--- добавление объекта в коллекцию
   if(!indicators.Add(GetPointer(m_MA)))
     {
      printf(__FUNCTION__+": ошибка добавления объекта");
      return(false);
     }
//--- успешное завершение
   return(true);
  }
//+------------------------------------------------------------------+
//| Инициализация таймсерии цен открытия.                            |
//| INPUT:  indicators - указатель на объект-коллекцию               |
//|                      индикаторов и таймсерий.                    |
//| OUTPUT: true-в случае успешного завершения, иначе false.         |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::InitOpen(CIndicators* indicators)
  {
//--- инициализация объекта таймсерии
   if(!m_open.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": ошибка инициализации объекта");
      return(false);
     }
//--- добавление объекта в коллекцию
   if(!indicators.Add(GetPointer(m_open)))
     {
      printf(__FUNCTION__+": ошибка добавления объекта");
      return(false);
     }
//--- успешное завершение
   return(true);
  }
//+------------------------------------------------------------------+
//| Инициализация таймсерии цен закрытия.                            |
//| INPUT:  indicators - указатель на объект-коллекцию               |
//|                      индикаторов и таймсерий.                    |
//| OUTPUT: true-в случае успешного завершения, иначе false.         |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::InitClose(CIndicators* indicators)
  {
//--- инициализация объекта таймсерии
   if(!m_close.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": ошибка инициализации объекта");
      return(false);
     }
//--- добавление объекта в коллекцию
   if(!indicators.Add(GetPointer(m_close)))
     {
      printf(__FUNCTION__+": ошибка добавления объекта");
      return(false);
     }
//--- успешное завершение
   return(true);
  }
//+------------------------------------------------------------------+
//| Проверка выполнения условия для покупки.                         |
//| INPUT:  price      - ссылка для размещения цены открытия,        |
//|         sl         - ссылка для размещения цены stop loss,       |
//|         tp         - ссылка для размещения цены take profit,     |
//|         expiration - ссылка для размещения времени истечения.    |
//| OUTPUT: true-если условие выполнено, иначе false.                |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- подготовка данных
   double spread=m_symbol.Ask()-m_symbol.Bid();
   double ma    =MA(1);
   double unit  =PriceLevelUnit();
//--- проверка условия
   if(Open(1)<ma && Close(1)>ma && ma>MA(2))
     {
      price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
      sl   =m_symbol.NormalizePrice(price-m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price+m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- условие выполнено
      return(true);
     }
//--- условие не выполнено
   return(false);
  }
//+------------------------------------------------------------------+
//| Проверка выполнения условия для продажи.                         |
//| INPUT:  price      - ссылка для размещения цены открытия,        |
//|         sl         - ссылка для размещения цены stop loss,       |
//|         tp         - ссылка для размещения цены take profit,     |
//|         expiration - ссылка для размещения времени истечения.    |
//| OUTPUT: true-если условие выполнено, иначе false.                |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- подготовка данных
   double ma  =MA(1);
   double unit=PriceLevelUnit();
//--- проверка условия
   if(Open(1)>ma && Close(1)<ma && ma<MA(2))
     {
      price=m_symbol.NormalizePrice(ma+m_limit*unit);
      sl   =m_symbol.NormalizePrice(price+m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price-m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- условие выполнено
      return(true);
     }
//--- условие не выполнено
   return(false);
  }
//+------------------------------------------------------------------+
//| Проверка выполнения условия для модификации ордера на покупку.   |
//| INPUT:  order - указатель на объект-ордер,                       |
//|         price - ссылка для размещения новой цены открытия.       |
//| OUTPUT: true-если условие выполнено, иначе false.                |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderLong(COrderInfo* order,double& price)
  {
//--- проверка указателя
   if(order==NULL) return(false);
//--- подготовка данных
   double spread   =m_symbol.Ask()-m_symbol.Bid();
   double ma       =MA(1);
   double unit     =PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
//--- проверка условия
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- условие выполнено
   return(true);
  }
//+------------------------------------------------------------------+
//| Проверка выполнения условия для модификации ордера на продажу.   |
//| INPUT:  order - указатель на объект-ордер,                       |
//|         price - ссылка для размещения новой цены открытия.       |
//| OUTPUT: true-если условие выполнено, иначе false.                |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderShort(COrderInfo* order,double& price)
  {
//--- проверка указателя
   if(order==NULL) return(false);
//--- подготовка данных
   double ma  =MA(1);
   double unit=PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma+m_limit*unit);
//--- проверка условия
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- условие выполнено
   return(true);
  }
//+------------------------------------------------------------------+

Ну, вот и все. Сигнал готов к использованию.

Для того чтобы генератор торговых стратегий Мастера MQL5 смог использовать наш сигнал, нужно перезапустить MetaEditor (Мастер MQL5 сканирует папку Include\Expert только при загрузке).

После перезапуска MetaEditor созданный модуль торговых сигналов можно использовать в Мастере MQL5:

Рисунок 5. Созданный генератор торговых сигналов в Мастере MQL5

Рисунок 5. Созданный генератор торговых сигналов в Мастере MQL5

Входные параметры, указанные в разделе описания параметров генератора торговых сигналов стали доступными:

Рисунок 6. Входные параметры созданного генератора торговых сигналов в Мастере MQL5

Рисунок 6. Входные параметры созданного генератора торговых сигналов в Мастере MQL5

Наилучшие значения входных параметров реализованной торговой стратегии могут быть найдены при помощи Тестера стратегий терминала MetaTrader 5.


Заключение

Генератор торговых стратегий Мастера MQL5 значительно упрощает проверку торговых идей. В основе кода сгенерированного эксперта лежат классы торговых стратегий Стандартной библиотеки, на базе которых строятся конкретные реализации классов торговых сигналов, классов управления капиталом и рисками и классов сопровождения позиций. 

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

Прикрепленные файлы |
samplesignal.mqh (15.44 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (57)
Vladimir Karputov
Vladimir Karputov | 12 нояб. 2016 в 17:34
yerlan Imangeldinov:
Почти 6 лет прошло статья не устарела? просто уверенности нет так как почти каждую неделю терминал вижу обновляется.
Именно по написанию модулей торговых сигналов более свежая статья: "Создай торгового робота за шесть часов!"
Nikita Gamolin
Nikita Gamolin | 6 янв. 2023 в 23:57
Как в итоге из Модуля сигналов генерировать сигнал на закрытие через CheckCloseLong/Short? Не увидел как это делать в этой статье https://www.mql5.com/ru/articles/367
FINANSE-BOND
FINANSE-BOND | 15 мая 2023 в 18:12

Только что скачал уже готовый Код вашего Сигнала и сделал Компиляцию. Мне выдаёт вот эти ошибки. Как их исправить чтобы заработало ?

Причём эти же ошибки выходят и вашем файле, который лежит в архиве и я никак его не менял просто Компилировал.

Если посмотреть как эти параметры прописаны в файле ЭкспертБасе там они со звёздочками, если я в коде перед названием поставлю звёздочки ошибок ещё больше будет. В чём причина ? 

https://photos.app.goo.gl/2rPVRPfBDhb65aZC9

FINANSE-BOND
FINANSE-BOND | 20 мая 2023 в 12:37

Выставите пожалуйста правильный Код.

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

Ищу хоть какой то советник рабочий с ордерами на покупку и продажу, чтобы экспериментировать с настройками или добавить свои идеи. Хотелось бы иметь простой Шаблон, и просто иметь возможность добавить Условия1 и Условия2 в Код, чтобы на основании их исполнялись сделки. Я просто раньше писал в другой программе (Изи Ленгвич от другой платформы), здесь же простому пользователю очень сложно разобраться в написании своих стратегий. Даже когда выходит ошибка нет возможности по правому клику мышки найти вариант её исправления в Справочном руководстве и приходится искать в интернете и все равно не находится решение. 

Stanislav Korotky
Stanislav Korotky | 20 мая 2023 в 16:37
FINANSE-BOND #:

Выставите пожалуйста правильный Код.

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

Ищу хоть какой то советник рабочий с ордерами на покупку и продажу, чтобы экспериментировать с настройками или добавить свои идеи. Хотелось бы иметь простой Шаблон, и просто иметь возможность добавить Условия1 и Условия2 в Код, чтобы на основании их исполнялись сделки. Я просто раньше писал в другой программе (Изи Ленгвич от другой платформы), здесь же простому пользователю очень сложно разобраться в написании своих стратегий. Даже когда выходит ошибка нет возможности по правому клику мышки найти вариант её исправления в Справочном руководстве и приходится искать в интернете и все равно не находится решение. 

Попробуйте вот это - https://www.mql5.com/en/code/32107

Ордерa, позиции и сделки в MetaTrader 5 Ордерa, позиции и сделки в MetaTrader 5
Надежный торговый робот не может быть создан без понимания механизмов работы торговой системы MetaTrader 5. Клиентский терминал получает от торгового сервера информацию о позициях, ордерах и сделках. Чтобы правильно обработать эти данные средствами MQL5 необходимо хорошо представлять как происходит взаимодействие mql5-программы и среды исполнения терминала.
Механическая Торговая Система "Вилка Чувашова" Механическая Торговая Система "Вилка Чувашова"
В данной статье вашему вниманию предлагается краткий обзор методики и программный код стратегии механической торговой системы по методике Станислава Чувашова. Рассматриваемый анализ состояния рынка перекликается с подходом Т. Демарка к построению линий тренда для последнего ближайшего отрезка времени, в качестве опорных точек для построения трендовых линий используются фракталы.
Реализация мультивалютного режима в MetaTrader 5 Реализация мультивалютного режима в MetaTrader 5
Интерес к мультивалютному анализу и мультивалютной торговле существует давно. Но только с выпуском в свет терминала MetaTrader 5 и языка программирования MQL5 появилась возможность реализации полноценного мультивалютного режима. В данной статье предложен способ, позволяющий проводить анализ и обработку всех поступающих тиков по множеству финансовых инструментов. В качестве иллюстрации рассмотрен мультивалютный индикатор RSI для индекса доллара USDx.
Мастер MQL5: Создание эксперта без программирования Мастер MQL5: Создание эксперта без программирования
Вы хотите быстро проверить торговую идею, не тратя времени на программирование? Выберите в "Мастере MQL5" нужный тип торговых сигналов, подключите модули сопровождения позиций и управления капиталом - на этом вся работа закончена. Создайте свои реализации модулей или закажите их через сервис "Работа" - и комбинируйте новые модули с уже существующими.