![Мастер MQL5: Как написать свой модуль торговых сигналов](https://c.mql5.com/i/articles/overlay.png)
Мастер MQL5: Как написать свой модуль торговых сигналов
Введение
В MetaTrader 5 имеется достаточно мощный инструмент для быстрой проверки торговых идей. Это генератор торговых стратегий Мастера MQL5. Использование Мастера MQL5 для автоматического создания кода советников рассмотрено в статье "Мастер MQL5: Создание эксперта без программирования". Открытость системы генерации кода позволяет добавлять к стандартным свои собственные классы торговых сигналов, системы управления капиталом и модули трейлинга.
В данной статье рассмотрены принципы написания модулей торговых сигналов для их последующего использования при создании экспертов Мастером MQL5.
Эксперт, который создается Мастером MQL5, стоит на четырех столпах - четырех базовых классах:
Рисунок 1. Структура базового класса CExpert
Класс CExpert (или его наследник) является главным "двигателем" торгового робота. Экземпляр класса CExpert содержит в себе по одному экземпляру классов CExpertSignal, CExpertMoney и CExpertTrailing (или их наследников):
- CExpertSignal - является основой генератора торговых сигналов. Экземпляр наследника класса CExpertSignal, включенный в состав класса CExpert, основываясь на встроенных алгоритмах, предоставляет эксперту информацию о возможности входа в рынок, уровнях входа и установки защитных ордеров. Окончательно решение по совершению торговых операций принимает эксперт.
- CExpertMoney - является основой системы управления капиталом и рисками. Экземпляр наследника класса CExpertMoney вычисляет объемы для открытия позиций и установки отложенных ордеров. Окончательное решение по объемам принимает эксперт.
- 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. Методы инициализации:
Метод Init() автоматически вызывается сразу после присоединения экземпляра класса к эксперту. Переопределения метода не требуется.
virtual bool Init(CSymbolInfo* symbol, ENUM_TIMEFRAMES period, double adjusted_point);
Метод ValidationSettings() вызывается из эксперта после установки всех параметров. Необходимо переопределить метод в случае наличия параметров настройки.
virtual bool ValidationSettings();
Переопределенный метод должен возвращать true, если все параметры корректны (пригодны для использования). Если хотя бы один из параметров неверный, метод должен возвращать false (дальнейшая работа невозможна).
Базовый класс CExpertSignal не имеет устанавливаемых параметров, соответственно, метод базового класса, не выполняя никаких проверок, всегда возвращает true.
Метод InitIndicators() осуществляет создание и инициализацию всех необходимых индикаторов и таймсерий. Вызывается из эксперта после установки всех параметров и успешной проверки их корректности. Необходимо переопределить метод в том случае, если генератор торговых сигналов использует в работе хотя бы один индикатор или таймсерию.
virtual bool InitIndicators(CIndicators* indicators);
Индикаторы и/или таймсерии должны использоваться через соответствующие классы Стандартной библиотеки. Указатели всех индикаторов и/или таймсерий должны быть добавлены в коллекцию индикаторов эксперта (указатель на которую передается в качестве параметра).
Переопределенный метод должен возвращать true, если все манипуляции с индикаторами и/или таймсериями прошли успешно (они пригодны для использования). В случае если хотя бы одна операция с индикаторами и/или таймсериями завершилась с ошибкой, метод должен возвращать false (дальнейшая работа невозможна).
Базовый класс CExpertSignal не использует индикаторов и таймсерий, соответственно, метод базового класса всегда возвращает true, не выполняя никаких действий.
1.2. Методы проверки сигнала открытия позиции:
Метод CheckOpenLong() производит генерацию сигнала открытия длинной позиции с определением уровней входа и установки защитных ордеров. Вызывается экспертом для определения необходимости открытия длинной позиции. Необходимо переопределить метод в случае, если предполагается генерация сигнала открытия длинной позиции.
virtual bool CheckOpenLong(double& price, double& sl, double& tp, datetime& expiration);
Метод должен реализовывать алгоритм проверки условия открытия длинной позиции. Если условие выполнилось, переменным price, sl, tp и expiration (ссылки на которые передаются в качестве параметров) должны быть присвоены соответствующие значения и метод должен вернуть true. Если условие не выполнилось, метод должен вернуть false.
Базовый класс CExpertSignal не имеет встроенного алгоритма генерации сигнала открытия длинной позиции, поэтому метод базового класса всегда возвращает false.
Метод CheckOpenShort() производит генерацию сигнала открытия короткой позиции с определением уровней входа и установки защитных ордеров. Вызывается экспертом для определения необходимости открытия короткой позиции. Необходимо переопределить метод в случае, если предполагается генерация сигнала открытия короткой позиции.
virtual bool CheckOpenShort(double& price, double& sl, double& tp, datetime& expiration);
Метод должен реализовывать алгоритм проверки условия открытия короткой позиции. Если условие выполнилось, переменным price, sl, tp и expiration (ссылки на которые передаются в качестве параметров) должны быть присвоены соответствующие значения и метод должен вернуть true. Если условие не выполнилось, метод должен вернуть false.
Базовый класс CExpertSignal не имеет встроенного алгоритма генерации сигнала открытия короткой позиции, поэтому метод базового класса всегда возвращает false.
1.3. Методы проверки сигнала закрытия позиции:
Метод CheckCloseLong() производит генерацию сигнала закрытия длинной позиции с определением уровня выхода. Вызывается экспертом для определения необходимости закрытия длинной позиции. Необходимо переопределить метод в случае, если предполагается генерация сигнала закрытия длинной позиции.
virtual bool CheckCloseLong(double& price);
Метод должен реализовывать алгоритм проверки условия закрытия длинной позиции. Если условие выполнилось, переменной price (ссылка на которую передается в качестве параметра) должно быть присвоено соответствующее значение и метод должен вернуть true. Если условие не выполнилось, метод должен вернуть false.
Базовый класс CExpertSignal не имеет встроенного алгоритма генерации сигнала закрытия длинной позиции, поэтому метод базового класса всегда возвращает false.
Метод CheckCloseShort() производит генерацию сигнала закрытия короткой позиции с определением уровня выхода. Вызывается экспертом для определения необходимости закрытия короткой позиции. Необходимо переопределить метод в случае, если предполагается генерация сигнала закрытия короткой позиции.
virtual bool CheckCloseShort(double& price);
Метод должен реализовывать алгоритм проверки условия закрытия короткой позиции. Если условие выполнилось, переменной price (ссылка на которую передается в качестве параметра) должно быть присвоено соответствующее значение и метод должен вернуть true. Если условие не выполнилось, метод должен вернуть false.
Базовый класс CExpertSignal не имеет встроенного алгоритма генерации сигнала закрытия короткой позиции, поэтому метод базового класса всегда возвращает false.
1.4. Методы проверки сигнала разворота позиции:
Метод CheckReverseLong производит генерацию сигнала разворота длинной позиции с определением уровней разворота и установки защитных ордеров. Вызывается экспертом для определения необходимости разворота длинной позиции. Необходимо переопределить метод в случае, если предполагается генерация сигнала разворота длинной позиции по алгоритму, отличному от реализованного в базовом классе.
virtual bool CheckReverseLong(double& price, double& sl, double& tp, datetime& expiration);
Метод должен реализовывать алгоритм проверки условия разворота длинной позиции. Если условие выполнилось, переменным price, sl, tp и expiration (ссылки на которые передаются в качестве параметров) должны быть присвоены соответствующие значения и метод должен вернуть true. Если условие не выполнилось, метод должен вернуть false.
В базовом классе CExpertSignal реализован следующий алгоритм генерации сигнала разворота длинной позиции:
- Проверяется наличие сигнала закрытия длинной позиции.
- Проверяется наличие сигнала открытия короткой позиции.
- Если оба сигнала активны (условия выполнены) и цены закрытия и открытия совпадают, переменным price, sl, tp и expiration (ссылки на которые переданы в качестве параметров) присваиваются соответствующие значения и метод возвращает true.
Метод CheckReverseShort производит генерацию сигнала разворота короткой позиции с определением уровней разворота и установки защитных ордеров. Вызывается экспертом для определения необходимости разворота короткой позиции. Необходимо переопределить метод в случае, если предполагается генерация сигнала разворота короткой позиции по алгоритму, отличному от реализованного в базовом классе.
virtual bool CheckReverseShort(double& price, double& sl, double& tp, datetime& expiration);
Метод должен реализовывать алгоритм проверки условия разворота короткой позиции. Если условие выполнилось, переменным price, sl, tp и expiration (ссылки на которые передаются в качестве параметров) должны быть присвоены соответствующие значения и метод должен вернуть true. Если условие не выполнилось, метод должен вернуть false.
В базовом классе CExpertSignal реализован следующий алгоритм генерации сигнала разворота короткой позиции:
- Проверяется наличие сигнала закрытия короткой позиции.
- Проверяется наличие сигнала открытия длинной позиции.
- Если оба сигнала активны (условия выполнены) и цены закрытия и открытия совпадают, переменным price, sl, tp и expiration (ссылки на которые переданы в качестве параметров) присваиваются соответствующие значения и метод возвращает true.
Если условие не выполнилось, метод возвращает false.
1.5. Методы проверки сигнала модификации отложенного ордера:
Метод CheckTrailingOrderLong() производит генерацию сигнала модификации отложенного ордера на покупку с определением новой цены ордера. Вызывается экспертом для определения необходимости модификации отложенного ордера на покупку. Необходимо переопределить метод в случае, если предполагается генерация сигнала модификации отложенного ордера на покупку.
virtual bool CheckTrailingOrderLong(COrderInfo* order, double& price)
Метод должен реализовывать алгоритм проверки условия модификации отложенного ордера на покупку. Если условие выполнилось, переменной price (ссылка на которую передается в качестве параметра) должно быть присвоено соответствующее значение и метод должен вернуть true. Если условие не выполнилось, метод должен вернуть false.
Базовый класс CExpertSignal не имеет встроенного алгоритма генерации сигнала модификации отложенного ордера на покупку, поэтому метод базового класса всегда возвращает false.
Метод 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.
Следует отметить, что для того чтобы этот файл был потом "обнаружен" Мастером MQL5 как генератор сигналов, его следует создать в папке Include\Expert\Signal\.
Для того чтобы не "мусорить" в Стандартной библиотеке, создадим свою папку Include\Expert\Signal\MySignals а в ней файл SampleSignal.mqh, указав эти параметры в Мастере МQL5:
Рисунок 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. Торговые сигналы по пересечению цены скользящей средней
Рассмотрим наши алгоритмы еще раз, более подробно.
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
Входные параметры, указанные в разделе описания параметров генератора торговых сигналов стали доступными:
Рисунок 6. Входные параметры созданного генератора торговых сигналов в Мастере MQL5
Наилучшие значения входных параметров реализованной торговой стратегии могут быть найдены при помощи Тестера стратегий терминала MetaTrader 5.
Заключение
Генератор торговых стратегий Мастера MQL5 значительно упрощает проверку торговых идей. В основе кода сгенерированного эксперта лежат классы торговых стратегий Стандартной библиотеки, на базе которых строятся конкретные реализации классов торговых сигналов, классов управления капиталом и рисками и классов сопровождения позиций.
В статье рассказывается о том, как написать и подключить в генератор торговых стратегий Мастера MQL5 свой собственный класс торговых сигналов с реализацией сигналов по пересечению ценой скользящей средней, рассматривается структура и формат описания созданного класса для Мастера MQL5.
![Ордерa, позиции и сделки в MetaTrader 5](https://c.mql5.com/2/0/TradeIndo_MQL5.png)
![Механическая Торговая Система "Вилка Чувашова"](https://c.mql5.com/2/17/944_28.png)
![Реализация мультивалютного режима в MetaTrader 5](https://c.mql5.com/2/0/Multicurrency_Expert_Advisor.png)
![Мастер MQL5: Создание эксперта без программирования](https://c.mql5.com/2/0/editor_wizard.png)
![MQL5 - Язык торговых стратегий для клиентского терминала MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Почти 6 лет прошло статья не устарела? просто уверенности нет так как почти каждую неделю терминал вижу обновляется.
Только что скачал уже готовый Код вашего Сигнала и сделал Компиляцию. Мне выдаёт вот эти ошибки. Как их исправить чтобы заработало ?
Причём эти же ошибки выходят и вашем файле, который лежит в архиве и я никак его не менял просто Компилировал.
Если посмотреть как эти параметры прописаны в файле ЭкспертБасе там они со звёздочками, если я в коде перед названием поставлю звёздочки ошибок ещё больше будет. В чём причина ?
https://photos.app.goo.gl/2rPVRPfBDhb65aZC9
Выставите пожалуйста правильный Код.
Даже просмотрев все ответы в этой ветке, Советник всё равно не торгует на истории, только Скользящую линию рисует и больше ничего ни одной сделки не делает.
Ищу хоть какой то советник рабочий с ордерами на покупку и продажу, чтобы экспериментировать с настройками или добавить свои идеи. Хотелось бы иметь простой Шаблон, и просто иметь возможность добавить Условия1 и Условия2 в Код, чтобы на основании их исполнялись сделки. Я просто раньше писал в другой программе (Изи Ленгвич от другой платформы), здесь же простому пользователю очень сложно разобраться в написании своих стратегий. Даже когда выходит ошибка нет возможности по правому клику мышки найти вариант её исправления в Справочном руководстве и приходится искать в интернете и все равно не находится решение.
Выставите пожалуйста правильный Код.
Даже просмотрев все ответы в этой ветке, Советник всё равно не торгует на истории, только Скользящую линию рисует и больше ничего ни одной сделки не делает.
Ищу хоть какой то советник рабочий с ордерами на покупку и продажу, чтобы экспериментировать с настройками или добавить свои идеи. Хотелось бы иметь простой Шаблон, и просто иметь возможность добавить Условия1 и Условия2 в Код, чтобы на основании их исполнялись сделки. Я просто раньше писал в другой программе (Изи Ленгвич от другой платформы), здесь же простому пользователю очень сложно разобраться в написании своих стратегий. Даже когда выходит ошибка нет возможности по правому клику мышки найти вариант её исправления в Справочном руководстве и приходится искать в интернете и все равно не находится решение.
Попробуйте вот это - https://www.mql5.com/en/code/32107