Разрабатываем мультивалютный советник (Часть 30): От торговой стратегии — к запуску мультивалютного советника
Введение
В прошлой части мы начали выполнять работу, направленную не на расширение торговой логики, а на устранение практических неудобств, выявленных при реальном использовании конвейера автоматической оптимизации. Продолжили разделение между библиотечной (ядром) и проектной (конкретной стратегией) частями кода. Это нужно, чтобы для подключения новой торговой идеи достаточно было настроить параметры в рамках проектного репозитория — без необходимости вмешиваться в код библиотечной части. Хотя этот процесс ещё не завершён окончательно, он уже демонстрирует свою эффективность и будет продолжен.
Мы внедрили ограничения по времени выполнения задач оптимизации. Эта функция даёт гибкий контроль над продолжительностью всего конвейера: мы можем намеренно сократить длительность первых двух этапов, не дожидаясь полного завершения генетического поиска, если уже получено достаточно качественных решений. Такой подход особенно ценен при итеративной разработке и быстрой проверке перспектив применяемых торговых стратегий.
Также был улучшен интерфейс советника оптимизации. Вместо скупого вывода номера текущей задачи, советник отображает гораздо более детальную информацию — этап оптимизации, символ, таймфрейм, прошедшее и оставшееся время, а также общий прогресс по проекту.
В совокупности все эти доработки позволили продемонстрировать полный рабочий цикл — от создания проекта до получения готового к тестированию советника с корректно нормированными объёмами позиций, который в перспективе может быть установлен на реальный торговый счёт. А при хороших результатах такой советник можно установить и на несколько торговых счетов. Но этот следующий шаг мы пока ещё не рассматривали. Поэтому попробуем в рамках данной статьи решить практическую задачу — не только получить, но и запустить три разных экземпляра итогового советника на различных торговых счетах с разными параметрами. Начнём с краткого описания небольших доработок, а затем перейдём к общему обзору всего проекта и составления дорожной карты с учётом накопленного опыта за прошедшее время.
Доработка CConsoleDialog
В процессе разработки мультивалютного советника мы старались уделять внимание различным аспектам. Понятное дело, что больший приоритет имели задачи, связанные с обеспечением выполнения прямой задачи — показывать хорошие результаты при торговле. А разработка внешнего вида советника при работе в терминале не является необходимой составляющей, без которой невозможно обойтись, поэтому мы занимались ею по остаточному принципу. На текущий момент мы воспользовались разработанным классом диалога, унаследованным от соответствующего класса из стандартной библиотеки, чтобы отображать на графике терминала многострочную текстовую информацию с возможностью масштабирования и скроллинга (CConsoleDialog).
Простой интерфейс позволял отобразить, какие торговые инструменты используются, и каково количество экземпляров торговых стратегий. Если же во входных параметрах итогового советника был включен менеджер закрытия или риск-менеджер, то они тоже выводили свою информацию о текущем состоянии. В целом, окно графика с запущенным советником выглядело примерно так:

Однако в ходе использования были обнаружены некоторые некритические ошибки: при перезапуске, вызванном различными причинами (перекомпиляция, смена параметров, перезапуск терминала) окно советника дублировалось, то есть не удалялись графические объекты старого окна при создании нового. Причина была в недостаточно полноценно реализованном механизме уничтожения окна при срабатывании функции OnDeinit().
Кроме того, в процессе написания статьи терминал находился в процессе внедрения нового движка отображения графиков Blend2D (от которого в конце концов было принято решение отказаться). Одним из заметных эффектов перехода стало сглаживание экранных шрифтов всех текстовых элементов графика. Но например, на экране с разрешением 1920х1080 мелкий текст, которым написаны название торгового инструмента, имя советника, подписи по осям цены и времени стали выглядеть менее приятно. Поэтому мы решили эту проблему кардинальным образом: отключили показ вообще всех элементов на том графике, на котором будет развёрнуто окно интерфейса советника. В самом деле, то, что раньше оставалось видимым на экране вокруг окна советника, всё равно никак не использовалось. Если мы захотим посмотреть на график торгового инструмента, на котором запущен советник, то можно просто открыть ещё один график рядом.
Это автоматически устраняет и рисование торговых уровней и стрелочек открытия/закрытия позиций по текущему торговому инструменту поверх окна советника. Раньше их приходилось отключать сначала вручную, потом программно. Становится не нужна кнопка минимизации окна советника, так как за ним всё равно ничего нет. После некоторых манипуляций, убирающих последствия неочевидного способа отрисовки рамки вокруг объектов OBJ_EDIT, получилось добиться такого внешнего вида окна:

К сожалению, для отключения минимизации пришлось внести некоторые изменения в классы CDialog и CAppDialog из стандартной библиотеки, поэтому они были добавлены в отдельном файле в состав нашего репозитория. Но вернёмся после небольшого отступления к основной теме.
Обзор проекта
Итак, цель проекта: разработать методологию построения мультивалютных советников на основе одной или нескольких простых торговых стратегий (правил открытия и закрытия позиций), которая позволит объединить множество экземпляров торговых стратегий, отличающихся значениями своих параметров, в один итоговый советник. Попробуем составить иерархическую схему, которая будет охватывать всё сделанное в рамках данного проекта. На самом верхнем уровне нам потребуется выполнить следующие шаги:
- Шаг 0. Подготовка окружения. Ранее весь написанный программный код был разделён на библиотечную и проектную часть. Библиотечной частью мы назвали тот код, который будет использоваться без внесения изменений. Проектной частью — тот код, в который для новых торговых стратегий потребуется вносить изменения. Удобно эти две части иметь в виде двух отдельных репозиториев кода, поэтому в начале их нужно клонировать из готовых репозиториев или создать с нуля.
- Шаг 1. Разработка торговой стратегии. Предполагается, что торговая стратегия, положенная в основу всей дальнейшей работы, будет достаточно проста, чтобы параллельная работа большого количества экземпляров торговой стратегии не приводила к нехватке вычислительных и временных ресурсов. Торговая стратегия должна быть оформлена в виде отдельного класса, унаследованного от готового базового класса торговых стратегий.
- Шаг 2. Создание конвейера оптимизации. Нам необходимо определиться, на каких торговых инструментах и таймфреймах будут работать одиночные экземпляры торговой стратегии внутри итогового советника, сколько их будет, на каком временном интервале будет проводиться оптимизация и так далее. Все эти параметры надо как-то зафиксировать. Для этого мы создаём конвейер оптимизации. Так мы будем называть базу данных с определённой структурой, и несколько вспомогательных советников. База данных изначально будет хранить значения всех исходных параметров, а впоследствии — промежуточные результаты дальнейшей оптимизации и окончательные результаты для построения итогового советника. Вспомогательные советники будут наполнять базу данных результатами.
В рамках одного конвейера оптимизации мы можем создать один или несколько проектов оптимизации — целостные наборы исходных значений параметров в базе данных, обработка которых приводит к появлению одного итогового советника (точнее, одной группы одиночных экземпляров торговой стратегии, которую сможет загрузить и использовать итоговый советник). - Шаг 3. Запуск конвейера оптимизации. Когда база данных проекта оптимизации заполнена, и вспомогательные советники скомпилированы, можно приступить к процессу оптимизации, разбитому на несколько этапов. Этапы выполняются последовательно. Мы остановились пока на выполнении трёх этапов для одного проекта оптимизации. На первом проводится оптимизацию одиночного экземпляра торговой стратегии. На втором подбираются из многих хороших одиночных экземпляров, полученных на первом этапе, группы из небольшого количества экземпляров, которые при совместной работе показывает наилучшие результаты по нормированной прибыли. На третьем этапе происходит объединение всех групп, полученных на втором этапе, в одну нормированную итоговую группу. Она сохраняется в отдельную базу данных для итогового советника.
- Шаг 4. Запуск итоговых советников. После получения базы данных итогового советника, необходимо распределить её по нескольким экземплярам итоговых советников и настроить их на использование соответствующих параметров из базы данных при запуске на торговых счетах.
Так в целом выглядит укрупнённый набор действий, приводящий к заявленной цели. Рассмотрим каждый шаг подробнее.
Шаг 0. Подготовка окружения
Цель данного шага состоит в том, чтобы разместить на выбранном компьютере все необходимые файлы для осуществления дальнейших шагов.
- Шаг 0.1. Установить терминал. Для проведения оптимизации нам желательно иметь отдельную копию терминала и достаточно свободного места на диске для размещения исторических данных по нужным торговым инструментам и базы данных с результатами оптимизации. Следует отметить, что база данных размещается в общей папке данных всех терминалов, которая располагается, как правило, на системном диске, так что необходимо убедиться в достаточности свободного места на нём. В зависимости от состава проектов оптимизации, размер базы данных может достигать нескольких гигабайт.
Разместим новую копию терминала в папке C:/MT5_Projects/MetaTrader5/. Все дальнейшие пути мы будем указывать относительно этой корневой папки. - Шаг 0.2. Библиотечный репозиторий. Нам понадобится сделать форк или клонировать библиотечный репозиторий Adwizard в папку MQL5/Shared Projects/Adwizard. Это библиотечная часть, в которой никаких правок делать не надо, если разместить её именно в указанной папке. Для клонирования можно выполнить из папки MQL5/Shared Projects/ такую консольную команду: git clone https://forge.mql5.io/antekov/Adwizard.gitЕсли предварительно сделать форк репозитория в своё хранилище MQL5 Algo Forge, то он появится в списке доступных репозиториев внутри MetaEditor, и клонирование можно будет выполнить прямо из этого редактора. Или в простейшем случае можно просто скачать архив этого репозитория и распаковать его в указанную папку.
- Шаг 0.3. Проектный репозиторий. Для второго репозитория можно сделать то же самое, что и для предыдущего: создать форк или клонировать репозиторий проекта советника. В этом репозитории будет располагаться конкретная торговая стратегия и файлы советников оптимизации. Готовый репозиторий SimpleCandles можно использовать для примера и как шаблон для создания своих торговых стратегий и проектов их оптимизации. Все правки, связанные с созданием итоговых советников разных проектов оптимизации будут выполняться в ней. Поэтому клонируем его, выполнив из папки MQL5/Shared Projects/ консольную команду: git clone https://forge.mql5.io/antekov/SimpleCandles.gitНа последующих шагах мы рассмотрим, какие изменения в него может понадобиться вносить. К концу этой статьи мы планируем сделать всё необходимое, поэтому после клонирования или распаковки из архива он уже будет содержать всё необходимое для решения поставленной задачи. Новые изменения понадобится вносить только если необходимо будет модифицировать проекты оптимизации: поменять или добавить торговые инструменты, таймфреймы, интервалы оптимизации или добавить новые проекты для получения дополнительных итоговых советников.
После завершения этого шага у нас есть два репозитория кода: библиотечный (Adwizard) и проектный (SimpleCandles), расположенные в папке Shared Projects рабочей папке MQL5 выделенной копии торгового терминала MetaTrader 5:

Если вас смущает понятие репозитория, то можете рассматривать их просто как две папки с набором файлов, расположенные в нужных местах. Репозиториями они становятся, если получают возможность вести историю всех сделанных изменений во вложенных файлах. Если же эта функциональность не используется, то по сути — это обычные папки на компьютере.
Шаг 1. Разработка торговой стратегии
Цель этого шага — получить программную реализацию торговой стратегии, которую можно будет использовать на разработанном конвейере автоматической оптимизации. За время работы над циклом статей мы сделали реализацию двух простых торговых стратегий для демонстрации работоспособности разрабатываемых инструментов. Первая стратегия под названием SimpleVolumes была описана в части 1, а вторая под названием SimpleCandles — в части 24 и части 25.
Сейчас мы не будем разрабатывать новую стратегию, а воспользуемся уже готовой. Как видно из предыдущего шага, мы взяли проектный репозиторий со стратегией SimpleCandles. Это связано с тем, что для её мы уже оформили в виде отдельного репозитория и внесли различные дополнительные правки, которые потребовалось вносить по мере развития проекта в целом. Вот как выглядел состав файлов этого репозитория до начала работы над данной частью:

Посмотрим, что это за файлы. Прежде всего, в папке Strategies располагается единственный файл
- SimpleCandlesStrategy.mqh — файл с классом самой торговой стратегии SimpleCandles. Вся торговая логика сосредоточена только в нём. Если бы мы хотели использовать другую торговую стратегию, то её реализацию мы могли бы расположить в этой же папке.
Далее в папке Optimization располагаются файлы для создания и запуска конвейера автоматической оптимизации:
- CreateProject.mq5 — советник создания проекта автоматической оптимизации в базе данных оптимизации. Каждый проект в базе данных представлен в виде трёх этапов, состоящих из одной или нескольких работ. Каждая работа состоит из одной или нескольких задач оптимизации, выполняемых советниками этапов.
- Stage1.mq5 — советник первого этапа конвейера автоматической оптимизации. Проводит оптимизацию одиночного экземпляра торговой стратегии.
- Stage2.mq5 — советник второго этапа конвейера автоматической оптимизации. В процессе оптимизации подбирает из многих хороших одиночных экземпляров, полученных на первом этапе, группу из небольшого количества экземпляров (как правило, 8 или 16), которая при совместной работе показывает наилучшие результаты по нормированной прибыли.
- Stage3.mq5 — советник третьего этапа конвейера автоматической оптимизации. Объединяет все группы, полученные на втором этапе, нормирует размеры позиций и сохраняет итоговую группы с масштабирующим множителем в заданную в настройках базу данных эксперта.
- Optimization.mq5 — советник, запускающий задачи из проекта автоматической оптимизации. Сам процесс последовательного выполнения таких задач мы тоже раньше называли конвейером автоматической оптимизации.
И наконец, в корневой папке проектного репозитория расположен файл
- SimpleCandles.mq5 — итоговый советник, объединяющий много одиночных экземпляров торговых стратегий типа SimpleCandles. Информацию о составе этих экземпляров он будет брать из базы данных эксперта. А в базу данных эксперта эту информацию будет помещать советник третьего этапа конвейера автоматической оптимизации.
На данном шаге мы рассмотрим только файл класса торговой стратегии и файл советника первого этапа. Остальные файлы будут рассмотрены на следующих шагах.
Класс торговой стратегии
Для создания нужного класса торговой стратегии мы сделали следующее:
- Создали новый класс, унаследованный от класса CVirtualStartegy из библиотеки Adwizard
#include "../../Adwizard/Virtual/VirtualStrategy.mqh" // ... //+------------------------------------------------------------------+ //| Торговая стратегия c использованием однонаправленных свечей | //+------------------------------------------------------------------+ class CSimpleCandlesStrategy : public CVirtualStrategy { // ... };
- Конструктор нового класса сделали непубличным и добавили статический метод класса, через вызов которого будут создаваться объекты этого класса. Для этого воспользовались написанным ранее макросом STATIC_CONSTRUCTOR():
class CSimpleCandlesStrategy : public CVirtualStrategy { protected: string m_symbol; // Символ (торговый инструмент) ENUM_TIMEFRAMES m_timeframe; // Период графика (таймфрейм) // ... // Закрытый конструктор CSimpleCandlesStrategy(string p_params); public: // Статический конструктор STATIC_CONSTRUCTOR(CSimpleCandlesStrategy); };
- Зарегистрировали новый класс как наследник класса CFactorable, конструктор которого будет принимать только одну строку со всеми значениями параметров инициализации. Для этого тоже воспользовались макросом, написанным ранее:
class CSimpleCandlesStrategy : public CVirtualStrategy { // ... }; // Регистрация класса-наследника CFactorable REGISTER_FACTORABLE_CLASS(CSimpleCandlesStrategy);
- В конструкторе для инициализации полей класса воспользовались методами чтения значений разного типа из строки инициализации. Эти методы унаследованы от класса CFactorable:
//+------------------------------------------------------------------+ //| Конструктор | //+------------------------------------------------------------------+ CSimpleCandlesStrategy::CSimpleCandlesStrategy(string p_params) { // Читаем параметры из строки инициализации m_params = p_params; m_symbol = ReadString(p_params); m_timeframe = (ENUM_TIMEFRAMES) ReadLong(p_params); m_signalSeqLen = (int) ReadLong(p_params); m_periodATR = (int) ReadLong(p_params); m_stopLevel = ReadDouble(p_params); m_takeLevel = ReadDouble(p_params); m_maxCountOfOrders = (int) ReadLong(p_params); m_maxSpread = (int) ReadLong(p_params); if(IsValid()) { // ... } }
- Переопределили два виртуальных метода из родительского класса для обработки тика и преобразования объекта в строку и написали их реализацию:
class CSimpleCandlesStrategy : public CVirtualStrategy { //... public: // ... virtual string operator~() override; // Преобразование объекта в строку virtual void Tick() override; // Обработчик события OnTick };
Здесь мы упомянули основные вещи, а более подробно про создание новой стратегии можно посмотреть в части 24. После того, как класс торговой стратегии готов, можно создать советник первого этапа оптимизации для этой конкретной торговой стратегии.
Советник первого этапа оптимизации
Для любой торговой стратегии мы можем придерживаться такой структуры для создания советника первого этапа оптимизации:
- Определяем константу с именем советника. Наличие этой константы проверяется в идущем следом подключаемом коде для выполнения необходимых действий. К ней не предъявляется никаких особых требований, за исключением уникальности в рамках одного проекта.
- Подключаем нужную стратегию. Советник оптимизации должен иметь доступ к исходному коду торговой стратегии.
- Подключаем общую часть из библиотеки Adwizard. Всё остальное, помимо торговой стратегии, необходимое для работы советника оптимизации первого этапа, реализовано в соответствующем подключаемом файле в библиотечной части.
- Задаём входные параметры советника. Через них можно будет передавать значения параметров самой торговой стратегии, поэтому добавляем столько входных параметров, сколько нужно для реализованной стратегии с соблюдением соответствия типов.
- Задаём функцию формирования строки инициализации стратегии. В советнике первого этапа обязательно должна присутствовать функция с сигнатурой string GetStrategyParams(), которая будет из входных параметров советника конструировать и возвращать строку инициализации для последующего создания экземпляра класса нашей торговой стратегии. Более подробно работа со строками инициализации рассматривалась в части 10, а последние доработки были сделаны в части 24.
Вот как это выглядит в коде:
// 1. Определяем константу с именем советника #define __NAME__ "SimpleCandles" + MQLInfoString(MQL_PROGRAM_NAME) // 2. Подключаем нужную стратегию #include "../Strategies/SimpleCandlesStrategy.mqh"; // 3. Подключаем общую часть советника первого этапа из библиотеки Adwizard #include "../../Adwizard/Experts/Stage1.mqh" //+------------------------------------------------------------------+ //| 4. Входные параметры для стратегии | //+------------------------------------------------------------------+ sinput string symbol_ = ""; // Символ sinput ENUM_TIMEFRAMES period_ = PERIOD_CURRENT; // Таймфрейм для свечей input group "=== Параметры сигнала к открытию" input int signalSeqLen_ = 6; // Количество однонаправленных свечей input int periodATR_ = 0; // Период ATR (если 0, то TP/SL в пунктах) input group "=== Параметры отложенных ордеров" input double stopLevel_ = 25000; // Stop Loss (в доле ATR или пунктах) input double takeLevel_ = 3630; // Take Profit (в доле ATR или пунктах) input group "=== Параметры управление капиталом" input int maxCountOfOrders_ = 9; // Макс. количество одновременно отрытых ордеров input int maxSpread_ = 10; // Макс. допустимый спред (в пунктах) //+------------------------------------------------------------------+ //| 5. Функция формирования строки инициализации стратегии | //| из входных параметров | //+------------------------------------------------------------------+ string GetStrategyParams() { return StringFormat( "class CSimpleCandlesStrategy(\"%s\",%d,%d,%d,%.3f,%.3f,%d,%d)", (symbol_ == "" ? Symbol() : symbol_), period_, signalSeqLen_, periodATR_, stopLevel_, takeLevel_, maxCountOfOrders_, maxSpread_ ); }
Итак, торговая стратегия создана, советник первого этапа для оптимизации параметров одиночных экземпляров этой торговой стратегии тоже создан. Переходим к следующему шагу.
Шаг 2. Создание проекта оптимизации
Теперь наша цель состоит подготовке всего необходимого для запуска конвейера оптимизации. В проектном репозитории мы уже выполняли такой шаг, но сейчас мы хотим внести изменения в проект, например, поменять символы, таймфреймы, количество прогонов или диапазоны изменения входных параметров торговой стратегии. Поэтому эти изменения надо как-то внести и сохранить и затем создать проект оптимизации в базе данных.
Ранее вся информация о проекте оптимизации была помещена внутри файла Optimization/CreateProject.mq5. Но в процессе работы выяснилось, что для разных проектов оптимизации есть общие части, которые могут быть вынесены в библиотечный репозиторий. Поэтому теперь в проектном репозитории в данном файле осталось по сути только перечисление входных параметров с их значениями по умолчанию. Именно в этих значениях мы указываем желаемые параметры создания проекта оптимизации.
Ещё в этом файле в проектной части осталось определение функции создания строки с перечислением параметров для тестера paramsTemplate1(). В ней указывается, какие входные параметры советника первого этапа участвуют в одном прогоне оптимизации, а какие — нет, в каких пределах и с каким шагом могут изменяться оптимизируемые параметры.
Всё остальное перешло в файл CreateProject.mqh, который вошёл в состав библиотеки Adwizard в папку Experts. Точнее, в этот файл перешло всё содержимое прежнего файла советника создания проекта оптимизации, но мы добавили в него с помощью директив препроцессора блоки кода, которые могут не участвовать в компиляции, если они должны быть заменены на блоки кода из внешнего файла.
Например, если во внешнем файле проектного репозитория Optimization/CreateProject.mq5 объявлена константа __INPUT_PARAMS__, то блок входных параметров будет браться именно из этого файла, а из библиотечного файла Experts/CreateProject.mqh аналогичный блок браться не будет.
Мы хотели создать три проекта оптимизации с разными наборами торговых инструментов. Пусть, например, в первом проекта мы будем работать с символами GBPUSD, EURUSD, EURGBP. Во втором проекте возьмем тройку символов AUDUSD, AUDCAD, USDCAD. В третьем проекте пусть будет, например, GBPJPY, EURJPY, USDJPY. Выбор именно таких торговых инструментов сделан просто для примера, не стоит искать в этих наборах какой-то мистический смысл. Вместо большого количества символов в каждом проекте мы взяли только по три для уменьшения общего времени обработки. С другой стороны, если советник будет работать с тремя символами, то он уже точно будет считаться мультивалютным.
Чтобы упростить создание разных проектов оптимизации, создадим под каждый из них отдельный файл, используя CreateProject.mq5 как шаблон. То есть каждый из них будет являться советником создания проекта, а отличия будут только в значениях входных параметров по умолчанию. Все три проекта будут использовать одну и ту же разновидность торговой стратегии.
Приведём пример первого такого файла для GBPUSD, EURUSD, EURGBP:
// 1. Определяем константу - признак наличия входных параметров #define __INPUT_PARAMS__ // 2. Определяем константу - признак наличия функции шаблона параметров первого этапа #define __PARAMS_TEMPLATE1__ // 3. Определяем константу - признак наличия функции шаблона параметров второго этапа // #define __PARAMS_TEMPLATE2__ // 4. Определяем константу - признак наличия функции шаблона параметров третьего этапа // #define __PARAMS_TEMPLATE3__ // 5. Подключаем шаблон советника создания проекта #include "../../Adwizard/Experts/CreateProject.mqh" //+------------------------------------------------------------------+ //| Входные параметры | //+------------------------------------------------------------------+ sinput group "::: База данных" sinput string fileName_ = "article.19684.db.sqlite"; // - Файл базы данных оптимизации sinput group "::: Параметры проекта - Основные" sinput string projectName_ = "SimpleCandles"; // - Название sinput string projectVersion_ = "1.01"; // - Версия sinput string symbols_ = "GBPUSD,EURUSD,EURGBP"; // - Символы sinput string timeframes_ = "M3,M5,M12"; // - Таймфреймы //sinput ENUM_OPT_STAGE_ORDER // stageOrder_ = OPT_STAGE_ORDER_SEQUENTAL; // - Последовательность этапов sinput group "::: Параметры проекта - Интервал оптимизации" sinput datetime fromDate_ = D'2025-01-01'; // - Дата начала sinput datetime toDate_ = D'2025-10-01'; // - Дата окончания sinput group "::: Параметры проекта - Счёт" sinput string mainSymbol_ = "GBPUSD"; // - Основной символ sinput int deposit_ = 100000; // - Начальный депозит sinput group "::: Этап 1. Поиск" sinput string stage1ExpertName_ = "Stage1.ex5"; // - Советник этапа sinput string stage1Criterions_ = "6,6,6,6,6,6"; // - Критерии оптимизации для задач sinput long stage1MaxDuration_ = 120; // - Макс. продолж. задач (с) sinput group "::: Этап 2. Группировка" sinput string stage2ExpertName_ = "Stage2.ex5"; // - Советник этапа sinput string stage2Criterion_ = "6"; // - Критерий оптимизации для задач sinput long stage2MaxDuration_ = 300; // - Макс. продолж. задач (с) //sinput bool stage2UseClusters_= false; // - Использовать кластеризацию? sinput double stage2MinCustomOntester_ = 500; // - Мин. значение норм. прибыли sinput uint stage2MinTrades_ = 20; // - Мин. кол-во сделок sinput double stage2MinSharpeRatio_ = 0.7; // - Мин. коэфф. Шарпа sinput uint stage2Count_ = 8; // - Кол-во стратегий в группе (1 - 16) sinput group "::: Этап 3. Итог" sinput string stage3ExpertName_ = "Stage3.ex5"; // - Советник этапа sinput ulong stage3Magic_ = 1968401; // - Magic sinput bool stage3Tester_ = true; // - Для тестера? // Шаблон параметров оптимизации на первом этапе string paramsTemplate1(COptimizationProject *p) { string params = StringFormat( "symbol_=%s\n" "period_=%d\n" "; === Параметры сигнала к открытию\n" "signalSeqLen_=4||2||1||8||Y\n" "periodATR_=28||28||2||210||N\n" "; === Параметры отложенных ордеров\n" "stopLevel_=2.34||0.01||0.01||20.0||Y\n" "takeLevel_=4.55||0.01||0.01||10.0||Y\n" "; === Параметры управление капиталом\n" "maxCountOfOrders_=20||1||1||30||N\n" "maxSpread_=100||10||1||100||N\n", p.m_symbol, p.StringToTimeframe(p.m_timeframe)); return params; } //+------------------------------------------------------------------+
Посмотрим на группу параметров "Параметры проекта — Основные". С названием и версией проекта всё очевидно, далее идут два параметра, в которых мы будем передавать списки символов и таймфреймов, разделённых точкой с запятой. Они будут использоваться для получения одиночных экземпляров торговой стратегии. Для каждого символа будут браться по очереди все таймфреймы. Таким образом, если мы указали в значениях по умолчанию три символа и три таймфрейма, то это приведёт к созданию девяти комбинаций, которые будут встречаться в одиночных экземплярах торговых стратегий.
Сохраним этот файл в проектном репозитории в папке Optimization под именем CreateProject.1968401.mq5. То есть к исходному имени файла мы добавили значение магического номера, который указан в параметрах третьего этапа. У двух других файлов магические номера будут другие, например, 1968402 и 1968403, поэтому мы можем точно также включить их в имена советников создания проектов и получить разные файлы для разных проектов. Использовать именно такой способ формирования имён необязательно, достаточно того, чтобы имена этих советников были разными.
Константы __PARAMS_TEMPLATE2__ и __PARAMS_TEMPLATE3__ в файле проектной части не были объявлены (остались закомментированы), поэтому функции для генерации параметров второго и третьего этапа оптимизации будут браться из библиотечной части (файла Experts/CreateProject.mqh):
#ifndef __PARAMS_TEMPLATE2__ // Шаблон параметров оптимизации на втором этапе string paramsTemplate2(COptimizationProject *p) { // Находим идентификатор родительской работы для текущей работы // по совпадению символа и таймфрейма на текущем и родительском этапе int i; SEARCH(p.m_stage.parent_stage.jobs, (p.m_stage.parent_stage.jobs[i].symbol == p.m_symbol && p.m_stage.parent_stage.jobs[i].timeframe == p.m_timeframe), i); ulong parentJobId = p.m_stage.parent_stage.jobs[i].id_job; string params = StringFormat( "idParentJob_=%I64u\n" "useClusters_=%s\n" "minCustomOntester_=%f\n" "minTrades_=%u\n" "minSharpeRatio_=%.2f\n" "count_=%u\n", parentJobId, (string) false, //(string) stage2UseClusters_, stage2MinCustomOntester_, stage2MinTrades_, stage2MinSharpeRatio_, stage2Count_ ); return params; } #endif #ifndef __PARAMS_TEMPLATE3__ // Шаблон параметров оптимизации на третьем этапе string paramsTemplate3(COptimizationProject *p) { string params = StringFormat( "groupName_=%s\n" "advFileName_=%s\n" "passes_=\n", StringFormat("%s_v.%s_%s", p.name, p.version, TimeToString(toDate_, TIME_DATE)), StringFormat("%s-%I64u%s.db.sqlite", p.name, stage3Magic_, (stage3Tester_ ? ".test" : ""))); return params; } #endif
Советники второго и третьего этапов мы можем использовать практически те же самые, что были написаны в предыдущей части, так как код их библиотечной части не содержит упоминания об используемых классах торговых стратегий. А в проектном репозитории в их код понадобится добавить команду включения файла новой стратегии. Тогда код советника для второго этапа оптимизации (Optimization/Stage2.mq5) будет выглядеть так:
// 1. Определяем константу с именем советника #define __NAME__ "SimpleCandles" + MQLInfoString(MQL_PROGRAM_NAME) // 2. Подключаем нужную стратегию #include "../Strategies/SimpleCandlesStrategy.mqh"; // 3. Подключаем общую часть советника второго этапа из библиотеки Adwizard #include "../../Adwizard/Experts/Stage2.mqh"
И аналогично для советника третьего этапа оптимизации (Optimization/Stage3.mq5):
// 1. Определяем константу с именем советника #define __NAME__ "SimpleCandles" + MQLInfoString(MQL_PROGRAM_NAME) // 2. Подключаем нужную стратегию #include "../Strategies/SimpleCandlesStrategy.mqh"; // 3. Подключаем общую часть советника третьего этапа из библиотеки Adwizard #include "../../Adwizard/Experts/Stage3.mqh"
Если в будущем мы захотим подключить новую стратегию, то для этого понадобится внести некоторые изменения в советник создания проекта в базе данных оптимизации. Как минимум, изменения коснутся шаблона входных параметров для советника первого этапа, так как в новой торговой стратегии состав входных параметров будет отличаться от такового для текущей стратегии.
Очень важно не забыть скомпилировать советники оптимизации для каждого этапа, причём обязательно не в debug-режиме, чтобы они могли запускаться на удалённых агентах тестирования. Также должны быть скомпилированы советники создания проектов оптимизации.

После этого мы можем по очереди запустить на графике терминала (не в тестере!) каждый советник создания проекта оптимизации:

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

Как видно, в таблице projects у нас появилось три записи для трёх проектов. Имена и версии проектов берутся напрямую из параметров советников создания проектов, а описание проекта сейчас генерируется автоматически по дате начала и окончания интервала оптимизации. При желании, такое поведение можно поменять, но для этого придется вносить правки в библиотечный код.
Для разных проектов можно использовать или отдельные базы данных или одну базу данных оптимизации. Поскольку мы задали достаточно строгое ограничение по времени для каждого запуска процессов оптимизации на первом и втором этапах (120 и 300 секунд), то количество проходов получится не очень большим. Следовательно, объём базы данных по завершению оптимизации тоже окажется гораздо меньшим, по сравнению с тем случаем, если бы мы не стали ограничивать время.
В результате этого шага мы создали задания на запуск конвейера автоматической оптимизации. Сам запуск будет выполняться на следующем шаге другим советником.
Шаг 3. Запуск конвейера оптимизации
Цель этого шага — скомпилировать и запустить советник автоматической оптимизации проектов. Он располагается в проектном репозитории в файле Optimization/Optimization.mq5. В нём нам достаточно указать только константу с выбранным ранее именем файла базы данных оптимизации:
// Константы с параметрами по умолчанию для проекта: // - Файл с основной базой данных #define OPT_FILEMNAME "article.19684.db.sqlite" // - Путь к интерпретатору Python #define OPT_PYTHONPATH "C:\\Python\\Python312\\python.exe" #include "../../Adwizard/Experts/Optimization.mqh"
Константа с путём к интерпретатору Python не используется, так как мы пока отказались включать в конвейер оптимизации какие-либо этапы, реализованные на Python. В будущем они, возможно, появятся снова, и тогда эта константа будет использована.
Основной код советника автоматической оптимизации полностью располагается в библиотечной части и подключается к данному файлу в конце. Скомпилируем его.
Работа конвейера автоматической оптимизации может занимать довольно продолжительное время. Его продолжительность зависит от выбранного временного интервала оптимизации (чем больше — тем дольше), сложности самой торговой стратегии (чем сложнее — тем дольше) и, конечно, количества доступных агентов тестирования для проведения оптимизации (чем больше — тем быстрее). Но за счёт ограничения времени выполнения задач оптимизации на первом и втором этапах конвейера оптимизации мы можем примерно оценить общее время работы.
Если в одном проекте оптимизации у нас есть три торговых инструмента, три таймфрейма, а в параметре
sinput string stage1Criterions_ = "6,6,6,6,6,6"; // - Критерии оптимизации для задач
указано через запятую шесть раз значение критерия "6" (Custom max), то на первом этапе конвейера будет выполнено всего 3 * 3 * 6 = 54 запуска оптимизации советника Optimization/Stage1.ex5 (54 задачи оптимизации). С учётом параметра
sinput long stage1MaxDuration_ = 120; // - Макс. продолж. задач (с)
продолжительность каждой задачи будет ограничена 2 минутами (120 секунд). Тогда на весь первый этап одного проекта потребуется около 54 * 2 = 108 минут.
На втором этапе будет выполняться подбор лучших групп для каждой комбинации символ-таймфрейм, поэтому будет проведено 3 * 3 = 9 запусков оптимизации советника Optimization/Stage2.ex5. С учетом параметров
sinput string stage2Criterion_ = "6"; // - Критерий оптимизации для задач sinput long stage2MaxDuration_ = 300; // - Макс. продолж. задач (с)
продолжительность одной задачи оптимизации с критерием "6" (Custom max) будет составлять 5 минут (300 секунд). Второй этап оптимизации одного проекта займёт тогда 9 * 5 = 45 минут.
Продолжительность третьего этапа, на котором будет выполняться один одиночный запуск тестирования советника Optimization/Stage3.ex5 не задана, но можно сделать грубую оценку, что на его прохождение понадобится, например, минут 30.
Тогда весь конвейер автоматической оптимизации для трёх проектов займет примерно 3 * (108 + 45 + 30) = 549 минут или около 9 часов.
Запустим конвейер автоматической оптимизации, перетащив советник Optimization/Optimization.ex5 на любой график терминала:

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

При старте каждого нового процесса оптимизации терминал создаёт и переключается на отображение нового графика с визуализацией результатов текущего процесса оптимизации. Каждая точка на нём соответствует результату одного прогона советника первого этапа с каким-то набором параметров. Высота точки — это значение пользовательского критерия, в качестве которого мы используем нормированную годовую прибыль при просадке 10% при депозите $10000:

Как видно на рисунке выше, за 1 минуту 46 секунд с момента старта оптимизации советника Stage1.ex5 для символа GBPUSD на таймфрейме M3 было выполнено 1187 прогонов из запланированных 10496. Среди них есть уже больше десятка прогонов, на которых была достигнута прибыль в диапазоне от $3000 до $6000 и несколько десятков со значением более $500.
В параметре
sinput double stage2MinCustomOntester_ = 500; // - Мин. значение норм. прибыли
мы задали значение 500, то есть на второй этап будут отбираться только такие результаты первого этапа, которые давали значение нормированной прибыли более $500. За 2 минуты таких результатов набралось уже не так мало. С учётом того, что на каждой комбинации символ-таймфрейм мы запускаем оптимизацию шесть раз, на второй этап пройдут уже несколько сотен хороших комбинаций параметров. Поэтому, похоже, что время для одной задачи оптимизации на первом этапе выбрано достаточное.
Но здесь стоит отметить, что в оптимизации были задействованы 1 агент на локальном компьютере и 32 дополнительных агента тестирования в локальной сети. При увеличении количества используемых агентов за те же самые 2 минуты количество выполненных прогонов только увеличится, а вот при меньшем количестве агентов, наоборот, уменьшится. В последнем случае может потребоваться увеличивать отведённое время выполнения одной задачи оптимизации, чтобы за него успевало найтись достаточное количество хороших экземпляров для второго этапа.
После завершения выполнения всех задач конвейера автоматической оптимизации мы увидим, что все три проекта находятся в состоянии Done (выполнен):

Советник автоматической оптимизации переходит в состояние ожидания новых задач. Они могут появиться, если мы, например, добавим в эту же базу данных оптимизации новый проект, или поменяем статус существующего проекта. Можно его спокойно удалить с графика.
Результатом работы конвейера являются созданные файлы баз данных итоговых советников в общей папке данных терминалов. Они предназначены для сохранения всей необходимой информации итогового советника, работающего на торговом счёте. На данном шаге в эти базы данных добавлена только информация о составе используемой группы одиночных экземпляров торговых стратегий.
Имена файлов этих баз данных генерируются из имени проекта и магического номера, заданного в настройках советника третьего этапа. Как видно на следующем рисунке, в общей папке у нас появились два новых файла, имена которых начинаются с имени проекта "SimpleCandles":

Вообще-то мы ожидали увидеть три файла, но сейчас давайте не будем исследовать причины отсутствия файла для магического номера 1968401. Мы к этому обязательно вернёмся в дальнейшем.
База данных оптимизации, как мы и предполагали, заняла относительно немного места: размер файла article.19684.db.sqlite составил всего около 130 МБ.
Итак, базы данных итоговых советников у нас появились, можно приступать к следующему шагу.
Шаг 4. Запуск итоговых советников
Цель последнего шага — запустить итоговые советники на торговых счетах или прогнать их в тестере стратегий для оценки результатов оптимизации. Рассмотрим сразу действия по запуску на торговом счёте.
Возьмём имеющийся файл итогового советника в проектной части SimpleCandles.mq5, и сохраним его под тремя разными именами. В имя каждого добавим для наглядности основные отличительные параметры. Например, имя SimpleCandles-MQ-100K-10.mq5 будет означать, что советник планируется запускать на демо-счёте от MetaQuotes, начальный баланс счёта будет равен $100000, а максимальная допустимая расчётная просадка будет составлять 10%. Вот как будет выглядеть корневая папка проектного репозитория после этого:

Для запуска итогового советника важно, чтобы по его имени и магическому номер генерировалось такое же имя базы данных итогового советника, которое у нас есть. Иначе он создаст пустую базу данных эксперта и завершит свою работу, так как в ней нет группы с нужным идентификатором. Можно, кстати так и поступить, чтобы понять, как должна называться база данных для запущенного итогового советника.
Запустим, например, скомпилированный файл SimpleCandles-MQ-100K-10.ex5 на графике и увидим, что в общей папке данных терминалов появился файл с именем SimpleCandles-MQ-100K-10-1968401.db.sqlite:

Значит, именно так должна называться база данных для этого итогового советника. Поэтому мы можем взять любой из файлов SimpleCandles-1968402.test.db.sqlite или SimpleCandles-1968403.test.db.sqlite, и создать его копию с нужным именем SimpleCandles-MQ-100K-10-1968401.db.sqlite.
Если итоговый советник находит свою базу под нужным именем, то он пытается загрузить группу стратегий с указанным идентификатором или последнюю добавленную группу, если идентификатор равен 0. Мы указали во всех трёх итоговых советниках идентификатор группы, равный 1:
input group "::: Использовать группу стратегий" sinput int groupId_ = 1; // - ID группы из новой библиотеки (0 - последняя)
Так как мы запускали конвейер один раз, то в каждой базе данных итогового советника создалась одна группа стратегий с идентификатором 1:

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

Мы получили шесть новых файлов баз данных итоговых советников. Файлы, в имени которых присутствует суффикс .test могут использоваться только в тестере стратегий, а файлы без этого суффикса будут использоваться при работе итоговых советников на торговом счёте. Ещё раз напомним, что такое разделение сделано для предотвращения ситуации, когда запуск тестирования мог бы случайно внести изменения в базу данных советника, который уже работает на торговом счёте.
Добавление к имени базы данных магического номера — это ещё одна ступень защиты от внесения изменений одним итоговым советником в базу данных другого советника. Мы специально задали магический номер во входных параметрах по умолчанию, чтобы любой запуск не требовал его изменения в диалоге параметров, но он был бы там виден.
Поскольку эти файлы размещаются в общей папке данных терминалов, то они будут доступны для любого терминала, установленного на данном компьютере. Воспользуемся тремя новыми установками терминала, размещёнными в отдельной папке, например, C:/MT5

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

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

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

Как видно, на протяжении 9 месяцев интервала тестирования у торговой стратегии были разные периоды успешной и не очень успешной торговли, но итоговый результат продемонстрирован достаточно неплохой. Размеры позиций подобраны корректно, и просадка за весь период не превысила максимальной расчётной 10%. В этом тесте советнику было разрешено использовать весь имеющийся размер средств на счёте.
Заключение
Итак, мы проделали полный путь от формулирования торговой стратегии до превращения её в несколько итоговых мультивалютных советников, работающих на торговых счетах. Продемонстрировали на тестах потенциал улучшения результатов от объединения большого количества экземпляров простой торговой стратегии в одном советнике.
Мы получили возможность спокойно создавать отдельные советники для каждого счёта со своими индивидуальными параметрами, которые всегда будут загружаться правильно. В будущем мы рассматриваем возможность выноса интерфейса работы с параметрами на внешний уровень веб-приложения и создания API по управлению советником. Насколько это необходимо не совсем понятно, но время покажет.
Однако не всё получается так, как задумано. Например, мы столкнулись с тем, что один из проектов оптимизации не привёл к созданию базы данных итогового советника. Попробуем разобраться в причинах такого поведения и продолжим работу по улучшению кода в целом.
Спасибо за внимание, до встречи!
Важное предупреждение
Все результаты, изложенные в этой статье и всех предшествующих статьях цикла, основываются только на данных тестирования на истории и не являются гарантией получения хоть какой-то прибыли в будущем. Работа в рамках данного проекта носит исследовательский характер. Все опубликованные результаты могут быть использованы всеми желающими на свой страх и риск.
| # | Имя | Версия | Описание | Последние изменения |
|---|---|---|---|---|
| SimpleCandles | Рабочая папка проекта (внутри MQL5/Shared Projects) | |||
| 1 | SimpleCandles-MQ-100K-10.mq5 SimpleCandles-MQ-200K-07.mq5 SimpleCandles-MQ-300K-05.mq5 | 1.05 | Итоговые советники для параллельной работы нескольких групп модельных стратегий. Параметры будут браться из встроенной библиотеки групп. Их может быть больше, каждый из них может использоваться как шаблон | Часть 30 |
| └ Optimization | Папка советников оптимизации проекта | |||
| 2 | CreateProject.1968401.mq5 CreateProject.1968401.mq5 CreateProject.1968401.mq5 | 1.05 | Советник-скрипт создания проекта с этапами, работами и задачами оптимизации. | Часть 30 |
| 3 | Optimization.mq5 | 1.03 | Советник для автоматической оптимизации проектов | Часть 29 |
| 4 | Stage1.mq5 | 1.04 | Советник оптимизации одиночного экземпляра торговой стратегии (Этап 1) | Часть 30 |
| 5 | Stage2.mq5 | 1.04 | Советник оптимизации группы экземпляров торговых стратегий (Этап 2) | Часть 30 |
| 6 | Stage3.mq5 | 1.04 | Советник, сохраняющий сформированную нормированную группу стратегий в базу данных эксперта с заданным именем. | Часть 30 |
| └ Strategies | Папка стратегий проекта | Часть 25 | ||
| 7 | SimpleCandlesStrategy.mqh | 1.03 | Класс торговой стратегии SimpleCandles | Часть 30 |
| Adwizard | Папка библиотеки Adwizard (внутри MQL5/Shared Projects) | |||
| └ Base | Базовые классы, от которых наследуются другие классы проекта | |||
| 8 | Advisor.mqh | 1.04 | Базовый класс эксперта | Часть 10 |
| 9 | Factorable.mqh | 1.06 | Базовый класс объектов, создаваемых из строки | Часть 28 |
| 10 | FactorableCreator.mqh | 1.00 | Класс создателей, связывающих названия и статические конструкторы классов-наследников CFactorable | Часть 24 |
| 11 | Interface.mqh | 1.01 | Базовый класс визуализации различных объектов | Часть 4 |
| 12 | Receiver.mqh | 1.04 | Базовый класс перевода открытых объемов в рыночные позиции | Часть 12 |
| 13 | Strategy.mqh | 1.04 | Базовый класс торговой стратегии | Часть 10 |
| └ Database | Файлы для работы со всеми типами баз данных, используемых советниками проекта | |||
| 14 | Database.mqh | 1.13 | Класс для работы с базой данных | Часть 29 |
| 15 | db.adv.schema.sql | 1.00 | Схема базы данных итогового советника | Часть 22 |
| 16 | db.cut.schema.sql | 1.00 | Схема урезанной базы данных оптимизации | Часть 22 |
| 17 | db.opt.schema.sql | 1.06 | Схема базы данных оптимизации | Часть 29 |
| 18 | Storage.mqh | 1.01 | Класс работы с хранилищем Key-Value для итогового советника в базе данных эксперта | Часть 23 |
| └ Experts | Файлы с общими частями используемых советников разного типа | |||
| CreateProject.mqh | 1.07 | Библиотечный файл для советника-скрипта создания проекта с этапами, работами и задачами оптимизации | Часть 30 | |
| 19 | Expert.mqh | 1.24 | Библиотечный файл для итогового советника. Параметры групп могут браться базы данных эксперта | Часть 28 |
| 20 | Optimization.mqh | 1.06 | Библиотечный файл для советника, управляющего запуском задач оптимизации | Часть 29 |
| 21 | Stage1.mqh | 1.19 | Библиотечный файл для советника оптимизации одиночного экземпляра торговой стратегии (Этап 1) | Часть 23 |
| 22 | Stage2.mqh | 1.04 | Библиотечный файл для советника оптимизации группы экземпляров торговых стратегий (Этап 2) | Часть 23 |
| 23 | Stage3.mqh | 1.04 | Библиотечный файл для советника, сохраняющего сформированную нормированную группу стратегий в базу данных эксперта с заданным именем. | Часть 23 |
| └ Optimization | Классы, отвечающие за работу автоматической оптимизации | |||
| 24 | OptimizationJob.mqh | 1.00 | Класс для работы этапа проекта оптимизации | Часть 25 |
| 25 | OptimizationProject.mqh | 1.00 | Класс для проекта оптимизации | Часть 25 |
| 26 | OptimizationStage.mqh | 1.00 | Класс для этапа проекта оптимизации | Часть 25 |
| 27 | OptimizationTask.mqh | 1.01 | Класс для задачи оптимизации (для создания) | Часть 29 |
| 28 | Optimizer.mqh | 1.04 | Класс для менеджера автоматической оптимизации проектов | Часть 29 |
| 29 | OptimizerTask.mqh | 1.06 | Класс для задачи оптимизации (для конвейера) | Часть 29 |
| └ Strategies | Примеры торговых стратегий, используемые для демонстрации работы проекта | |||
| 24 | HistoryStrategy.mqh | 1.00 | Класс торговой стратегии воспроизведения истории сделок | Часть 16 |
| 25 | SimpleVolumesStrategy.mqh | 1.11 | Класс торговой стратегии с использованием тиковых объемов | Часть 22 |
| └ Utils | Вспомогательные утилиты, макросы для сокращения кода | |||
| 26 | ConsoleDialog.mqh | 1.01 | Класс для вывода текстовой информации на график | Часть 28 |
| 26 | ExpertHistory.mqh | 1.00 | Класс для экспорта истории сделок в файл | Часть 16 |
| 27 | Macros.mqh | 1.07 | Полезные макросы для операций с массивами | Часть 26 |
| 28 | MTTester.mqh | — | Файл для работы с тестером стратегий из библиотеки MultiTester | Часть 28 |
| 29 | NewBarEvent.mqh | 1.00 | Класс определения нового бара для конкретного символа | Часть 8 |
| 30 | SymbolsMonitor.mqh | 1.01 | Класс получения информации о торговых инструментах (символах) | Часть 28 |
| └ Virtual | Классы для создания различных объектов, объединённых использованием системы виртуальных торговых ордеров и позиций | |||
| 31 | Money.mqh | 1.01 | Базовый класс управления капиталом | Часть 12 |
| 32 | TesterHandler.mqh | 1.07 | Класс для обработки событий оптимизации | Часть 23 |
| 33 | VirtualAdvisor.mqh | 1.12 | Класс эксперта, работающего с виртуальными позициями (ордерами) | Часть 28 |
| 34 | VirtualChartOrder.mqh | 1.02 | Класс графической виртуальной позиции | Часть 28 |
| 35 | VirtualCloseManager.mqh | 1.00 | Класс менеджера закрытия | Часть 28 |
| 36 | VirtualHistoryAdvisor.mqh | 1.00 | Класс эксперта воспроизведения истории сделок | Часть 16 |
| 37 | VirtualInterface.mqh | 1.00 | Класс графического интерфейса советника | Часть 4 |
| 38 | VirtualOrder.mqh | 1.09 | Класс виртуальных ордеров и позиций | Часть 22 |
| 39 | VirtualReceiver.mqh | 1.04 | Класс перевода открытых объемов в рыночные позиции (получатель) | Часть 23 |
| 40 | VirtualRiskManager.mqh | 1.06 | Класс управления риском (риск-менеждер) | Часть 28 |
| 41 | VirtualStrategy.mqh | 1.09 | Класс торговой стратегии с виртуальными позициями | Часть 23 |
| 42 | VirtualStrategyGroup.mqh | 1.04 | Класс группы торговых стратегий или групп торговых стратегий | Часть 28 |
| 43 | VirtualSymbolReceiver.mqh | 1.00 | Класс символьного получателя | Часть 3 |
Также исходный код доступен в публичных репозиториях SimpleCandles и Adwizard
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Особенности написания Пользовательских Индикаторов
Как создать и адаптировать RL-агент с LLM и квантовым кодированием в алгоритмическом трейдинге на MQL5
Создание торговой панели администратора на MQL5 (Часть X): Интерфейс из внешних ресурсов
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования