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

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

MetaTrader 5Торговые системы | 13 января 2011, 13:21
6 171 3
MetaQuotes
MetaQuotes

Введение

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

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

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

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

  1. Класс CExpert (или его наследник) является главным "двигателем" эксперта. Экземпляр класса CExpert, содержит в себе по одному экземпляру классов CExpertSignal, CExpertMoney и CExpertTrailing (или их наследников).
  2. Класс CExpertSignal является основой генератора торговых сигналов. Экземпляр наследника класса CExpertSignal, включенный в состав класса CExpert, основываясь на встроенных алгоритмах, предоставляет эксперту информацию о возможности входа в рынок, уровнях входа и установки защитных ордеров. Решение по входу в рынок принимает эксперт. Более подробно класс CExpertSignal и работа с ним рассмотрены в статье "Мастер MQL5: Как написать свой модуль торговых сигналов".
  3. Класс CExpertMoney является основой механизма управления капиталом и рисками. Экземпляр наследника класса CExpertMoney, включенный в состав класса CExpert, основываясь на встроенных алгоритмах, предоставляет эксперту информацию о возможных объемах открытия позиций и установки отложенных ордеров. Решение по объемам принимает эксперт.
  4. Класс CExpertTrailing является основой механизма сопровождения открытых позиций. Экземпляр наследника класса CExpertTrailing, включенный в состав класса CExpert, основываясь на встроенных алгоритмах, предоставляет эксперту информацию о возможности модификации защитных ордеров позиции. Решение по модификации ордеров принимает эксперт. Более подробно класс CExpertTrailing и работа с ним будут рассмотрены в отдельной статье.

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

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

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

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


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

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

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

 Описание

virtual Init

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

Percent

Установка значения параметра "Процент риска"

virtual ValidationSettings

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

virtual InitIndicators

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

Методы проверки необходимости открытия/разворота/закрытия позиций

 

virtual CheckOpenLong

Определение объема для открытия длинной позиции

virtual CheckOpenShort

Определение объема для открытия короткой позиции

virtual CheckReverse

Определение объема для разворота позиции

virtual CheckClose

Определение необходимости закрытия позиции


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


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

1.1.1 Init

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

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

1.1.2 Percent

Метод Percent() вызывается для настройки соответствующего параметра. Параметр может принимать значения от 0.0 до 100.0 включительно. Значение параметра по умолчанию 100.0. Переопределения метода не требуется.

void Percent(double percent);

1.1.3 ValidationSettings

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

virtual bool ValidationSettings();

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

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

1.1.4 InitIndicators

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

virtual bool InitIndicators(CIndicators* indicators);

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

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

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

1.2. Методы определения объема позиции

1.2.1 CheckOpenLong

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

virtual double CheckOpenLong(double price, double sl);

Метод должен реализовывать алгоритм расчета объема для открытия длинной позиции.  Метод должен возвращать рассчитанное значение объема.

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

1.2.2 CheckOpenShort

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

virtual double CheckOpenShort(double price, double sl);

Метод должен реализовывать алгоритм расчета объема для открытия короткой позиции.  Метод должен возвращать рассчитанное значение объема.

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

1.2.3 CheckReverse

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

virtual double CheckReverse(CPositionInfo* position, double sl);

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

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

1.2.4 CheckClose

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

virtual double CheckClose(CPositionInfo* position);

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

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


2. Пишем свой механизм управления капиталом и рисками

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

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

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

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

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

Приступим.

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

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

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

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

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

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

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

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

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

//+------------------------------------------------------------------+
//|                                                  SampleMoney.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
//+------------------------------------------------------------------+

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

//+------------------------------------------------------------------+
//|                                                  SampleMoney.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\ExpertMoney.mqh>
//+------------------------------------------------------------------+
//| Класс CSampleMoney.                                              |
//| Назначение: Класс управления капиталом и рисками.                |
//|             Является производным от класса CExpertMoney.         |
//+------------------------------------------------------------------+
class CSampleMoney : public CExpertMoney
  {
  };
//+------------------------------------------------------------------+

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

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

Отразим это в нашем файле.

//+------------------------------------------------------------------+
//|                                                  SampleMoney.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\ExpertMoney.mqh>
//+------------------------------------------------------------------+
//| Класс CSampleMoney.                                              |
//| Назначение: Класс управления капиталом и рисками                 |
//|             с удвоением объема после убыточной сделки.           |
//|             Является производным от класса CExpertMoney.         |
//+------------------------------------------------------------------+
class CSampleMoney : public CExpertMoney
  {
  };
//+------------------------------------------------------------------+

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

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

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

//+------------------------------------------------------------------+
//|                                                  SampleMoney.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\ExpertMoney.mqh>
//+------------------------------------------------------------------+
//| Класс CSampleMoney.                                              |
//| Назначение: Класс управления капиталом и рисками                 |
//|             с удвоением объема после убыточной сделки.           |
//|             Является производным от класса CExpertMoney.         |
//+------------------------------------------------------------------+
class CSampleMoney : public CExpertMoney
  {
protected:
   //--- параметры настройки
   double            m_lots;   // объем сделки для "нормальных" условий

public:
                     CSampleMoney();
   //--- методы установки параметров настройки
   void              Lots(double lots) { m_lots=lots; }
  };
//+------------------------------------------------------------------+
//| Конструктор CSampleMoney.                                        |
//| INPUT:  нет.                                                     |
//| OUTPUT: нет.                                                     |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
void CSampleMoney::CSampleMoney()
  {
//--- установка значений по умолчанию
   m_lots=0.1;
  }
//+------------------------------------------------------------------+

Отдельно рассмотрим, как правильно реализовать метод ValidationSettings(). Тонкость состоит в том, что базовый класс уже имеет один параметр настройки, который тоже требует проверки.

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

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

//+------------------------------------------------------------------+
//| Проверка параметров настройки.                                   |
//| INPUT:  нет.                                                     |
//| OUTPUT: true-если настройки правильные, иначе false.             |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleMoney::ValidationSettings()
  {
//--- вызов метода базового класса
   if(!CExpertMoney::ValidationSettings()) return(false);
//--- проверка параметров
   if(m_lots<m_symbol.LotsMin() || m_lots>m_symbol.LotsMax())
     {
      printf(__FUNCTION__+": объем сделки должен быть в диапазоне от %f до %f",m_symbol.LotsMin(),m_symbol.LotsMax());
      return(false);
     }
   if(MathAbs(m_lots/m_symbol.LotsStep()-MathRound(m_lots/m_symbol.LotsStep()))>1.0E-10)
     {
      printf(__FUNCTION__+": объем сделки должен быть кратен %f",m_symbol.LotsStep());
      return(false);
     }
//--- успешное завершение
   return(true);
  }

С настройками мы закончили, перейдем к "работе" манименеджера. Нам понадобится метод, который будет определять факт убыточности предыдущей сделки и, в случае необходимости, ее (сделки) объем. Объявим его в описании класса:

class CSampleMoney : public CExpertMoney
  {
protected:
   //--- параметры настройки
   double            m_lots;  // объем сделки для "нормальных" условий

public:
                    CSampleMoney();
   //--- методы установки параметров настройки
   void             Lots(double lots) { m_lots=lots; }
   //--- метод проверки параметров настройки
   virtual bool      ValidationSettings();

protected:
   double            CheckPrevLoss();
  };

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

//+------------------------------------------------------------------+
//| Определяет убыточность предыдущей сделки.                        |
//| INPUT:  нет.                                                     |
//| OUTPUT: объем предыдущей сделки-если сделка убыточная, иначе 0.0 |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
double CSampleMoney::CheckPrevLoss()
  {
   double lot=0.0;
//--- запрос истории сделок и ордеров
   HistorySelect(0,TimeCurrent());
//--- переменные
   int       deals=HistoryDealsTotal();  // всего сделок в истории
   CDealInfo deal;
//--- поиск предущей сделки
   for(int i=deals-1;i>=0;i--)
     {
      if(!deal.SelectByIndex(i))
        {
         printf(__FUNCTION__+": ошибка выбора сделки по индексу");
         break;
        }
      //--- проверка символа
      if(deal.Symbol()!=m_symbol.Name()) continue;
      //--- проверка прибыли
      if(deal.Profit()<0.0) lot=deal.Volume();
      break;
     }
//--- возвращаем объем
   return(lot);
  }

Рассмотрим наши алгоритмы еще раз, более подробно (хотя подробнее уже некуда).

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

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

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

//+------------------------------------------------------------------+
//| Класс CSampleMoney.                                              |
//| Назначение: Класс управления капиталом и рисками                 |
//|             с удвоением объема после убыточной сделки.           |
//|             Является производным от класса CExpertMoney.         |
//+------------------------------------------------------------------+
class CSampleMoney : public CExpertMoney
  {
protected:
   //--- параметры настройки
   double            m_lots;  // объем сделки для "нормальных" условий

public:
                    CSampleMoney();
   //--- методы установки параметров настройки
   void             Lots(double lots) { m_lots=lots; }
   //--- метод проверки параметров настройки
   virtual bool      ValidationSettings();
   //--- методы определения объема
   virtual double    CheckOpenLong(double price,double sl);
   virtual double    CheckOpenShort(double price,double sl);

protected:
   double            CheckPrevLoss();
  };

Реализации методов CheckOpenLong и CheckOpenShort практически не отличаются. Оба метода определяют необходимость наращивания объема вызывая ранее реализованный метод CheckPrevLoss.

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

  1. Максимальный объем для заключения сделки для символа, указанный в настройках сервера (SYMBOL_VOLUME_MAX).
  2. Наличие необходимого количества свободных средств на депозите.

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

//+------------------------------------------------------------------+
//| Определение объема для открытия длинной позиции.                 |
//| INPUT:  нет.                                                     |
//| OUTPUT: lot-if successful, 0.0 otherwise.                        |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
double CSampleMoney::CheckOpenLong(double price,double sl)
  {
   if(m_symbol==NULL) return(0.0);
//--- выбор размера лота
   double lot=2*CheckPrevLoss();
   if(lot==0.0) lot=m_lots;
//--- проверка лимитов
   double maxvol=m_symbol.LotsMax();
   if(lot>maxvol) lot=maxvol;
//--- проверка маржинальных требований
   if(price==0.0) price=m_symbol.Ask();
   maxvol=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,price,m_percent);
   if(lot>maxvol) lot=maxvol;
//--- возвращаем торговый объем
   return(lot);
  }
//+------------------------------------------------------------------+
//| Определение объема для открытия короткой позиции.                |
//| INPUT:  нет.                                                     |
//| OUTPUT: lot-if successful, 0.0 otherwise.                        |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
double CSampleMoney::CheckOpenShort(double price,double sl)
  {
   if(m_symbol==NULL) return(0.0);
//--- выбор размера лота
   double lot=2*CheckPrevLoss();
   if(lot==0.0) lot=m_lots;
//--- проверка лимитов
   double maxvol=m_symbol.LotsMax();
   if(lot>maxvol) lot=maxvol;
//--- проверка маржинальных требований
   if(price==0.0) price=m_symbol.Bid();
   maxvol=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,price,m_percent);
   if(lot>maxvol) lot=maxvol;
//--- возвращаем торговый объем
   return(lot);
  }

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


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

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

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

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

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

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

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

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

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

//| Title=Торговля с удвоением лота после убытка                     |

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

Пишем:

//| Type=Money                                                       |

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

У нас будет:

//| Name=Sample                                                      |

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

//| Class=CSampleMoney                                               |

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

//| Page=                                                            |

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

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

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

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

//| Parameter=Lots,double,0.1                                        |
//| Parameter=Percent,double,100.0                                   |

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

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

По пунктам 2-7 нужно дать дополнительные пояснения. Разделы описателя класса содержат ключевые слова (Title, Type, Name, Class, Page, Parameter). К сожалению, Мастер MQL5 не может интерпретировать всевозможные комбинации символов как части описания класса.

Поэтому, во избежание лишних ошибок, нужно писать так:
[Слэш][Слэш][ВертикальнаяЛиния][Пробел]<КлючевоеСлово>[ЗнакРавенства]<Описание>;

<Описание> может содержать пробелы только для ключевого слова Title. Пункты 1 и 8 должны быть скопированы "один в один".

Описатель класса (первая строка) должен быть найден в файле не позднее 20 строки.

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

//+------------------------------------------------------------------+
//|                                                  SampleMoney.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\ExpertMoney.mqh>
#include <Trade\DealInfo.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Торговля с удвоением лота после убытка                     |
//| Type=Money                                                       |
//| Name=Sample                                                      |
//| Class=CSampleMoney                                               |
//| Page=                                                            |
//| Parameter=Lots,double,0.1                                        |
//| Parameter=Percent,double,100.0                                   |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Класс CSampleMoney.                                              |
//| Назначение: Класс управления капиталом и рисками                 |
//|             с удвоением объема после убыточной сделки.           |
//|             Является производным от класса CExpertMoney.         |
//+------------------------------------------------------------------+
class CSampleMoney : public CExpertMoney
  {
protected:
   //--- параметры настройки
   double            m_lots;  // объем сделки для "нормальных" условий

public:
                     CSampleMoney();
   //--- методы установки параметров настройки
   void              Lots(double lots) { m_lots=lots; }
   //--- метод проверки параметров настройки
   virtual bool      ValidationSettings();
   //--- методы определения объема
   virtual double    CheckOpenLong(double price,double sl);
   virtual double    CheckOpenShort(double price,double sl);

protected:
   double            CheckPrevLoss();
  };
//+------------------------------------------------------------------+
//| Конструктор CSampleMoney.                                        |
//| INPUT:  нет.                                                     |
//| OUTPUT: нет.                                                     |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
void CSampleMoney::CSampleMoney()
  {
//--- установка значений по умолчанию
   m_lots=0.1;
  }
//+------------------------------------------------------------------+
//| Проверка параметров настройки.                                   |
//| INPUT:  нет.                                                     |
//| OUTPUT: true-если настройки правильные, иначе false.             |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
bool CSampleMoney::ValidationSettings()
  {
//--- вызов метода базового класса
   if(!CExpertMoney::ValidationSettings()) return(false);
//--- проверка параметров
   if(m_lots<m_symbol.LotsMin() || m_lots>m_symbol.LotsMax())
     {
      printf(__FUNCTION__+": объем сделки должен быть в диапазоне от %f до %f",m_symbol.LotsMin(),m_symbol.LotsMax());
      return(false);
     }
   if(MathAbs(m_lots/m_symbol.LotsStep()-MathRound(m_lots/m_symbol.LotsStep()))>1.0E-10)
     {
      printf(__FUNCTION__+": объем сделки должен быть кратен %f",m_symbol.LotsStep());
      return(false);
     }
//--- успешное завершение
   return(true);
  }
//+------------------------------------------------------------------+
//| Определение объема для открытия длинной позиции.                 |
//| INPUT:  нет.                                                     |
//| OUTPUT: lot-if successful, 0.0 otherwise.                        |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
double CSampleMoney::CheckOpenLong(double price,double sl)
  {
   if(m_symbol==NULL) return(0.0);
//--- выбор размера лота
   double lot=2*CheckPrevLoss();
   if(lot==0.0) lot=m_lots;
//--- проверка лимитов
   double maxvol=m_symbol.LotsMax();
   if(lot>maxvol) lot=maxvol;
//--- проверка маржинальных требований
   if(price==0.0) price=m_symbol.Ask();
   maxvol=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,price,m_percent);
   if(lot>maxvol) lot=maxvol;
//--- возвращаем торговый объем
   return(lot);
  }
//+------------------------------------------------------------------+
//| Определение объема для открытия короткой позиции.                |
//| INPUT:  нет.                                                     |
//| OUTPUT: lot-if successful, 0.0 otherwise.                        |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
double CSampleMoney::CheckOpenShort(double price,double sl)
  {
   if(m_symbol==NULL) return(0.0);
//--- выбор размера лота
   double lot=2*CheckPrevLoss();
   if(lot==0.0) lot=m_lots;
//--- проверка лимитов
   double maxvol=m_symbol.LotsMax();
   if(lot>maxvol) lot=maxvol;
//--- проверка маржинальных требований
   if(price==0.0) price=m_symbol.Bid();
   maxvol=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,price,m_percent);
   if(lot>maxvol) lot=maxvol;
//--- возвращаем торговый объем
   return(lot);
  }
//+------------------------------------------------------------------+
//| Определяет убыточность предыдущей сделки.                        |
//| INPUT:  нет.                                                     |
//| OUTPUT: объем предыдущей сделки-если сделка убыточная, иначе 0.0 |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
double CSampleMoney::CheckPrevLoss()
  {
   double lot=0.0;
//--- запрос истории сделок и ордеров
   HistorySelect(0,TimeCurrent());
//--- переменные
   int       deals=HistoryDealsTotal();  // всего сделок в истории
   CDealInfo deal;
//--- поиск предущей сделки
   for(int i=deals-1;i>=0;i--)
     {
      if(!deal.SelectByIndex(i))
        {
         printf(__FUNCTION__+": ошибка выбора сделки по индексу");
         break;
        }
      //--- проверка символа
      if(deal.Symbol()!=m_symbol.Name()) continue;
      //--- проверка прибыли
      if(deal.Profit()<0.0) lot=deal.Volume();
      break;
     }
//--- возвращаем объем
   return(lot);
  }
//+------------------------------------------------------------------+

Ну вот и все. Манименеджер готов к использованию.

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

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

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

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

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

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

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

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

На рис.7 приведены результаты тестирования советника, торгующего по данной системе управления капиталом (EURUSD H1, период тестирования  01.01.2010-05.01.2011).

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

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

При создании советника использовался модуль торговых сигналов, реализованный в статье "Мастер MQL5: Как написать свой модуль торговых сигналов". Параметры советника: (PeriodMA=12, ShiftMA=0, MethodMA=MODE_EMA, AppliedMA=PRICE_CLOSE, Limit=-70, StopLoss=145, TakeProfit=430, Expiration=10, Lots=0.1, Percent=100).


Заключение

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

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

Прикрепленные файлы |
samplemoney.mqh (7.16 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (3)
Dmitiry Ananiev
Dmitiry Ananiev | 18 янв. 2011 в 16:50

 HistorySelect(0,TimeCurrent());

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

 

 

Victor Kirillin
Victor Kirillin | 18 янв. 2011 в 17:23
dimeon:

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

 

 

Спасибо за внимание.

Код приведён для примера.

Поскольку, советник не привязан к определённому тайфрейму, нет возможности определить необходимую глубину запроса истории торговли.

Например при тестировании (или работе) на дневных свечах, история за последние сутки Вам вряд ли поможет.

Так что, выбирайте глубину истории исходя из конкретной ситуации (что Вы и сделали).

Эдуард
Эдуард | 4 мая 2023 в 11:09
Написали бы пример как инициализировать хотя бы базовый класс CExpertMoney, а то не разобраться как его применять!
Собери свой торговый советник в Мастере MQL5 Собери свой торговый советник в Мастере MQL5
Знание языков программирования теперь не является обязательным условием для создания торговых роботов. Если раньше это действительно служило непроходимым препятствием для реализации своих торговых стратегий, то появление Мастера MQL5 в корне изменило ситуацию. Начинающие трейдеры могут перестать тревожиться из-за отсутствия опыта программирования - с новым визардом, позволяющим быстро генерировать код советника, он не понадобится.
Реализация мультивалютного режима в MetaTrader 5 Реализация мультивалютного режима в MetaTrader 5
Интерес к мультивалютному анализу и мультивалютной торговле существует давно. Но только с выпуском в свет терминала MetaTrader 5 и языка программирования MQL5 появилась возможность реализации полноценного мультивалютного режима. В данной статье предложен способ, позволяющий проводить анализ и обработку всех поступающих тиков по множеству финансовых инструментов. В качестве иллюстрации рассмотрен мультивалютный индикатор RSI для индекса доллара USDx.
Эконометрический подход к анализу графиков Эконометрический подход к анализу графиков
В данной статье рассматриваются эконометрические методы исследования, в частности автокорреляционный анализ и анализ условной дисперсии. Что нам даёт описанный в статье подход? Применение нелинейной GARCH-модели позволяет, во-первых, формально представить исследуемый ряд с математической точки зрения, а во-вторых, создать прогноз на заданное количество шагов.
Ордерa, позиции и сделки в MetaTrader 5 Ордерa, позиции и сделки в MetaTrader 5
Надежный торговый робот не может быть создан без понимания механизмов работы торговой системы MetaTrader 5. Клиентский терминал получает от торгового сервера информацию о позициях, ордерах и сделках. Чтобы правильно обработать эти данные средствами MQL5 необходимо хорошо представлять как происходит взаимодействие mql5-программы и среды исполнения терминала.