![Мастер MQL5: Как написать свой модуль управления капиталом и рисками](https://c.mql5.com/i/articles/overlay.png)
Мастер MQL5: Как написать свой модуль управления капиталом и рисками
Введение
В MetaTrader 5 имеется мощный инструмент для быстрой проверки торговых идей. Это генерация экспертов с помощью Мастера MQL5 на основе готовых торговых стратегий.
Эксперт, который создается Мастером MQL5, стоит на четырех столпах - четырех базовых классах:
Рисунок 1. Структура базового класса CExpert
- Класс CExpert (или его наследник) является главным "двигателем" эксперта. Экземпляр класса CExpert, содержит в себе по одному экземпляру классов CExpertSignal, CExpertMoney и CExpertTrailing (или их наследников).
- Класс CExpertSignal является основой генератора торговых сигналов. Экземпляр наследника класса CExpertSignal, включенный в состав класса CExpert, основываясь на встроенных алгоритмах, предоставляет эксперту информацию о возможности входа в рынок, уровнях входа и установки защитных ордеров. Решение по входу в рынок принимает эксперт. Более подробно класс CExpertSignal и работа с ним рассмотрены в статье "Мастер MQL5: Как написать свой модуль торговых сигналов".
- Класс CExpertMoney является основой механизма управления капиталом и рисками. Экземпляр наследника класса CExpertMoney, включенный в состав класса CExpert, основываясь на встроенных алгоритмах, предоставляет эксперту информацию о возможных объемах открытия позиций и установки отложенных ордеров. Решение по объемам принимает эксперт.
- Класс CExpertTrailing является основой механизма сопровождения открытых позиций. Экземпляр наследника класса CExpertTrailing, включенный в состав класса CExpert, основываясь на встроенных алгоритмах, предоставляет эксперту информацию о возможности модификации защитных ордеров позиции. Решение по модификации ордеров принимает эксперт. Более подробно класс CExpertTrailing и работа с ним будут рассмотрены в отдельной статье.
Кроме того, членами класса CExpert являются экземпляры классов:
- CExpertTrade (для осуществления торговых операций)
- CIndicators (для управления индикаторами и таймсериями, задействованными в работе эксперта).
- CSymbolInfo (для получения информации об инструменте)
- CAccountInfo (для получения информации о состоянии торгового счета)
- CPositionInfo (для получения информации о позициях)
- COrderInfo (для получения информации об отложенных ордерах)
Далее по тексту, говоря "эксперт", мы будем подразумевать экземпляр класса CExpert или его наследника.
Более подробно класс CExpert и работа с ним будут рассмотрены в отдельной статье.
1. Базовый класс CExpertMoney
Как уже говорилось выше, класс CExpertMoney является основой механизма управления капиталом и рисками. Для связи с "внешним миром" класс CExpertMoney имеет набор публичных виртуальных методов:
Инициализация | Описание |
virtual Init | Инициализация экземпляра класса обеспечивает синхронизацию данных модуля с данными эксперта |
Установка значения параметра "Процент риска" | |
virtual ValidationSettings | Проверка корректности установленных параметров |
virtual InitIndicators | Создание и инициализация всех индикаторов и таймсерий, необходимых для работы механизма управления капиталом и рисками |
Методы проверки необходимости открытия/разворота/закрытия позиций |
|
virtual CheckOpenLong | Определение объема для открытия длинной позиции |
virtual CheckOpenShort | Определение объема для открытия короткой позиции |
virtual CheckReverse | Определение объема для разворота позиции |
virtual CheckClose | Определение необходимости закрытия позиции |
Описание методов
1.1. Методы инициализации
Метод Init() автоматически вызывается сразу после присоединения экземпляра класса к эксперту. Переопределения метода не требуется.
virtual bool Init(CSymbolInfo* symbol, ENUM_TIMEFRAMES period, double adjusted_point);
Метод Percent() вызывается для настройки соответствующего параметра. Параметр может принимать значения от 0.0 до 100.0 включительно. Значение параметра по умолчанию 100.0. Переопределения метода не требуется.
void Percent(double percent);
Метод ValidationSettings() вызывается из эксперта после установки всех параметров. Необходимо переопределить метод в случае наличия дополнительных параметров настройки.
virtual bool ValidationSettings();
Переопределенный метод должен возвращать true, если все параметры корректны (пригодны для использования). Если хотя бы один из параметров неверный, метод должен возвращать false (дальнейшая работа невозможна). Переопределенный метод должен вызывать метод базового класса с проверкой результата.
Метод InitIndicators() осуществляет создание и инициализацию всех необходимых индикаторов и таймсерий. Вызывается из эксперта после установки всех параметров и успешной проверки их корректности. Необходимо переопределить метод в том случае, если механизм управления капиталом и рисками использует в работе хотя бы один индикатор или таймсерию.
virtual bool InitIndicators(CIndicators* indicators);
Индикаторы и/или таймсерии должны использоваться через соответствующие классы Стандартной библиотеки. Указатели всех индикаторов и/или таймсерий должны быть добавлены в коллекцию индикаторов эксперта (указатель на которую передается в качестве параметра).
Переопределенный метод должен возвращать true, если все манипуляции с индикаторами и/или таймсериями прошли успешно (они пригодны для использования). В случае, если хотя бы одна операция с индикаторами и/или таймсериями завершилась с ошибкой, метод должен возвращать false (дальнейшая работа невозможна).
1.2. Методы определения объема позиции
Метод CheckOpenLong() производит расчет объема для открытия длинной позиции. Вызывается экспертом для определения объема открытия длинной позиции. Необходимо переопределить метод в случае, если предполагается рассчитывать объем открытия длинной позиции по алгоритму, отличному от реализованного в базовом классе.
virtual double CheckOpenLong(double price, double sl);
Метод должен реализовывать алгоритм расчета объема для открытия длинной позиции. Метод должен возвращать рассчитанное значение объема.
Метод CheckOpenShort() производит расчет объема для открытия короткой позиции. Вызывается экспертом для определения объема открытия короткой позиции. Необходимо переопределить метод в случае, если предполагается рассчитывать объем открытия короткой позиции по алгоритму, отличному от реализованного в базовом классе.
virtual double CheckOpenShort(double price, double sl);
Метод должен реализовывать алгоритм расчета объема для открытия короткой позиции. Метод должен возвращать рассчитанное значение объема.
Метод CheckReverse() производит расчет объема для разворота позиции. Вызывается экспертом для определения объема торговой операции разворота позиции. Необходимо переопределить метод в случае, если предполагается рассчитывать объем разворота позиции по алгоритму, отличному от реализованного в базовом классе (например, разворот удвоенным объемом).
virtual double CheckReverse(CPositionInfo* position, double sl);
Метод должен реализовывать алгоритм расчета объема для разворота позиции, информацию о которой можно получить по указателю position. Метод должен возвращать рассчитанное значение объема для разворота позиции.
Метод CheckClose() проверяет необходимость закрытия позиции (с точки зрения управления капиталом и рисками). Вызывается экспертом для определения необходимости закрытия позиции. Необходимо переопределить метод в случае, если предполагается закрывать позицию по алгоритму, отличному от реализованного в базовом классе (например, частичное закрытие позиции).
virtual double CheckClose(CPositionInfo* position);
Метод должен реализовывать алгоритм определения необходимости закрытия позиции, информацию о которой можно получить по указателю position. Метод должен возвращать рассчитанное значение объема для закрытия позиции.
2. Пишем свой механизм управления капиталом и рисками
Теперь, когда мы рассмотрели структуру базового класса CExpertMoney, можно приступать к созданию собственного механизма управления капиталом и рисками. Для простоты далее по тексту вместо "механизм управления капиталом и рисками" будем использовать"манименеджер".
Как уже говорилось выше, класс CExpertMoney представляет собой набор публичных виртуальных "веревочек" - методов, "подергав" за которые эксперт может узнать мнение манименеджера по поводу объема входа в рынок в ту или другую сторону.
Поэтому нашей первоочередной задачей является создание собственного класса манименеджера, унаследовав его от класса CExpertMoney и переопределив соответствующие виртуальные методы с реализацией необходимых алгоритмов.
Вторая наша задача (не менее важная) - сделать так, чтобы наш класс "увидел" Мастер MQL5. Но, обо всем по порядку.
2.1. Создание класса генератора торговых сигналов
Приступим.
Для начала создадим (например, при помощи того же Мастера MQL5) включаемый файл с расширением mqh.
Выберем в меню Файл пункт "Создать" (или комбинацией клавиш Ctrl+N) и укажем создание включаемого файла:
Рисунок 2. Создаем включаемый файл Мастером MQL5
Следует отметить, что для того чтобы этот файл был потом "обнаружен" Мастером MQL5 как манименеджер, его следует создать в папке Include\Expert.
Для того чтобы не "мусорить" в Стандартной библиотеке, создадим свою папку Include\Expert\Money\MyMoneys, а в ней файл SampleMoney.mqh, указав эти параметры в Мастере МQL5:
Рисунок 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():
//+------------------------------------------------------------------+ //| Проверка параметров настройки. | //| 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.
Далее нужно учесть то, что мы не можем бесконечно наращивать торговый объем. Существуют два ограничения на объем позиции:
- Максимальный объем для заключения сделки для символа, указанный в настройках сервера (SYMBOL_VOLUME_MAX).
- Наличие необходимого количества свободных средств на депозите.
Реализация методов 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 должны быть скопированы "один в один".
Добавим описатель в исходный код.
//+------------------------------------------------------------------+ //| 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
Входные параметры, указанные в разделе описания параметров манименеджера, стали доступными:
Рисунок 6. Входные параметры созданного манименеджера в Мастере MQL5
Наилучшие значения входных параметров реализованной торговой стратегии могут быть найдены при помощи Тестера стратегий терминала MetaTrader 5.
На рис.7 приведены результаты тестирования советника, торгующего по данной системе управления капиталом (EURUSD H1, период тестирования 01.01.2010-05.01.2011).
Рисунок 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.
![Собери свой торговый советник в Мастере MQL5](https://c.mql5.com/2/0/masterMQL5__2.png)
![Реализация мультивалютного режима в MetaTrader 5](https://c.mql5.com/2/0/Multicurrency_Expert_Advisor.png)
![Эконометрический подход к анализу графиков](https://c.mql5.com/2/0/econometrics.png)
![Ордерa, позиции и сделки в MetaTrader 5](https://c.mql5.com/2/0/TradeIndo_MQL5.png)
![MQL5 - Язык торговых стратегий для клиентского терминала MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Такая конструкция при большом количестве ордеров в истории сильно будет подтормаживать. Недавно Рош публиковал статью, как в кеш копировать ордера за последние сутки. В своего эксперта вставил и ММ перестал тормозить тесты.
Такая конструкция при большом количестве ордеров в истории сильно будет подтормаживать. Недавно Рош публиковал статью, как в кеш копировать ордера за последние сутки. В своего эксперта вставил и ММ перестал тормозить тесты.
Спасибо за внимание.
Код приведён для примера.
Поскольку, советник не привязан к определённому тайфрейму, нет возможности определить необходимую глубину запроса истории торговли.
Например при тестировании (или работе) на дневных свечах, история за последние сутки Вам вряд ли поможет.
Так что, выбирайте глубину истории исходя из конкретной ситуации (что Вы и сделали).