- Генерация тиков в тестере
- Управление ходом времени в тестере: таймер, Sleep, GMT
- Визуализация тестирования: график, объекты, индикаторы
- Мультивалютное тестирование
- Критерии оптимизации
- Получение финансовых показателей теста: TesterStatistics
- Событие OnTester
- Авто-настройка: ParameterGetRange и ParameterSetRange
- Группа OnTester-событий для контроля оптимизации
- Отправка фреймов данных с агентов в терминал
- Получение фреймов данных в терминале
- Директивы препроцессора для тестера
- Управление видимостью индикаторов: TesterHideIndicators
- Эмуляция пополнения депозита и снятия средств
- Принудительная остановка тестирования: TesterStop
- Большой пример эксперта
- Математические вычисления
- Отладка и профилирование
- Ограничения работы функций в тестере
Авто-настройка: ParameterGetRange и ParameterSetRange
В предыдущем разделе мы научились передавать тестеру критерий оптимизации, но обошли вниманием один важный нюанс. Если заглянуть в журналы наших оптимизаций, там можно в большом количестве встретить такие сообщения об ошибках.
...
|
Иными словами, каждые несколько тестовых проходов что-то неправильно со входными параметрами, и такой прогон не выполняется. Дело в том, что в обработчике OnInit имеется проверка:
if(FastOsMA >= SlowOsMA) return INIT_PARAMETERS_INCORRECT; |
С нашей стороны вполне логично налагать такое ограничение, чтобы период медленной MA был больше периода быстрой. Но тестер подобных прикладных тонкостей нашего алгоритма не знает, и потому пытается перебирать самые разные сочетания периодов, включая и некорректные. В принципе, это обычная ситуация для оптимизации, но она имеет одно негативное последствие.
Поскольку мы применяем генетическую оптимизацию, в каждом поколении оказывается несколько забракованных образцов, которые не участвуют в дальнейших мутациях. По тем или иным причинам оптимизатор MetaTrader 5 не восполняет эти потери, то есть не генерирует им замену. А меньший размер популяции может негативно сказываться на качестве. Таким образом, следует придумать способ, как обеспечить перебор входных настроек только в корректных сочетаниях. Тут нам на помощь приходят две функции MQL5 API: ParameterGetRange и ParameterSetRange.
Обе функции имеют по два перегруженных прототипа, отличающихся типами параметров: long и double. Вот как описаны 2 варианта функции ParameterGetRange.
bool ParameterGetRange(const string name, bool &enable, long &value, long &start, long &step, long &stop)
bool ParameterGetRange(const string name, bool &enable, double &value, double &start, double &step, double &stop)
Функция получает для заданной по имени входной переменной информацию о её текущем значении (value), диапазоне значений (start, stop) и шаге изменения (step) при оптимизации. Кроме того в переменную enable записывается признак того, включена ли оптимизация по входной переменной с именем name.
Функция возвращает признак успеха (true) или ошибки (false).
Функция может вызываться только из трех специальных обработчиков, связанных с оптимизацией: OnTesterInit, OnTesterPass и OnTesterDeinit. Мы расскажем про них в следующем разделе. Но как можно догадаться из названий, OnTesterInit вызывается перед началом оптимизации, OnTesterDeinit — по окончании оптимизации, а OnTesterPass — после каждого прохода в процессе оптимизации. Нас пока интересует только OnTesterInit. Она, также как и две другие функции, не имеет параметров и может быть описана с типом void, то есть ничего не возвращать.
Два варианта функции ParameterSetRange имеют похожие прототипы и выполняют обратное действие: задают оптимизационные свойства входного параметра эксперта.
bool ParameterSetRange(const string name, bool enable, long value, long start, long step, long stop)
bool ParameterSetRange(const string name, bool enable, double value, double start, double step, double stop)
Функция устанавливает правила модификации input-переменной с названием name при оптимизации: значение, шаг изменения, начальное и конечное значения.
Эта функция может вызываться только из обработчика OnTesterInit при запуске оптимизации в тестере стратегий.
Таким образом, с помощью функций ParameterGetRange и ParameterSetRange можно анализировать и задавать новые значения диапазона и шага, а также полностью исключать или наоборот включать те или иные параметры из оптимизации, несмотря на настройки в тестере стратегий. Это позволяет создавать собственные сценарии для управления пространством входных параметров при оптимизации.
Функция позволяет использовать в оптимизации даже переменные, объявленные с модификатором sinput (они недоступны для включения в оптимизацию пользователем).
Внимание! После вызова ParameterSetRange с изменением настроек конкретной входной переменной, последующие вызовы ParameterGetRange не "увидят" этих изменений и будут по-прежнему возвращать начальные настройки. Это делает невозможным использование функций совместно в сложных программных продуктах, где настройками могут заниматься разные классы и библиотеки от независимых разработчиков.
Усовершенствуем эксперт BandOsMA с использованием новых функций. Обновленная версия прилагается под именем BandOsMApro.mq5 ("pro" можно условно расшифровать как "parameter range optimization").
Итак, у нас появляется обработчик OnTesterInit, в котором мы считываем настройки для параметров FastOsMA и SlowOsMA и проверяем, включены ли они в оптимизацию. Если да, требуется их выключить, и предложить что-то взамен.
void OnTesterInit()
|
К сожалению, из-за добавления OnTesterInit компилятор требует также добавить OnTesterDeinit, хотя эта функция нам ни к чему. Но мы вынуждены согласиться и добавить пустой обработчик.
void OnTesterDeinit()
|
Наличие в коде функций OnTesterInit/OnTesterDeinit приведет к тому, что при старте оптимизации в терминале откроется дополнительный график с запущенной на нем копией нашего эксперта. Она работает в особом режиме, позволяющем принимать дополнительные данные "фреймы" от тестируемых копий на агентах, но мы изучим эту возможность позднее. Пока для нас важно отметить, что все операции с файлами, журналами, графиком, объектами работают в этой вспомогательной копии эксперта непосредственно в терминале, как обычно (а не на агенте). В частности, все сообщения об ошибках и вызовы Print будут отображаться в журнале на закладке Эксперты терминала.
Имея информацию о диапазонах изменения и шаге этих параметров, мы можем буквально пересчитать все правильные сочетания. Эта задача поручена отдельной функции Iterate, потому что аналогичную операцию должны будут воспроизвести и копии эксперта на агентах, в обработчике OnInit.
В функции Iterate мы пробегаем в двух вложенных циклах по периодам быстрой и медленной MA и подсчитываем количество допустимых сочетаний, т.е. когда период i меньше периода j. Необязательный параметр find потребуется нам при вызове Iterate из OnInit, чтобы по порядковому номеру сочетания вернуть пару i и j. И поскольку требуется возвращать 2 числа, мы объявили для них структуру PairOfPeriods.
struct PairOfPeriods
|
При вызове Iterate из OnTesterInit мы не используем параметр find и ведем подсчет до самого конца, а получившееся количество возвращаем в первом поле структуры. Это и будет диапазон значений некоего нового теневого параметра, для которого мы должны разрешить оптимизацию. Назовем его FastSlowCombo4Optimization и добавим в новую группу вспомогательных входных параметров. В одиночестве этот параметр тут будет оставаться недолго.
input group "A U X I L I A R Y"
|
А пока вернемся в OnTesterInit и организуем на MQL5 оптимизацию по параметру FastSlowCombo4Optimization в нужном диапазоне с помощью ParameterSetRange.
void OnTesterInit()
|
Обратите внимание, в журнале терминала должно вывестись получившееся количество итераций для нового параметра.
Во время теста на агенте по номеру в FastSlowCombo4Optimization следует получить пару периодов, вызвав вновь Iterate, на этот раз с заполненным параметром find. Но проблема в том, что для этой операции требуется знать изначальные диапазоны и шаг изменения параметров FastOsMA и SlowOsMA. А эта информация есть только в терминале. Значит, нам нужно как-то передать её на агент.
Сейчас мы применим пока единственное известное нам решение: добавим еще 3 теневых параметра оптимизации и установим для них некие значения. В будущем мы познакомимся с технологией передачи файлов на агенты (см. Директивы препроцессора для тестера). Тогда мы сможем записать в файл весь массив посчитанных функцией Iterate индексов и отправить его на агенты. Тогда мы избавимся от трех лишних теневых параметров оптимизации.
Итак, добавим 3 входных параметра:
sinput ulong FastShadow4Optimization = 0; // (reserved for optimization)
|
Мы используем тип ulong для экономии, чтобы в каждое значение упаковать по 2 целых int-числа. А вот как они заполняются в OnTesterInit.
void OnTesterInit()
|
Все 3 параметра — неоптимизируемые (false во втором аргументе).
На этом мы разобрались с функцией OnTesterInit и должны обратиться к приемной стороне — обработчику OnInit.
int OnInit()
|
Напоминаем, что мы можем с помощью функции MQLInfoInteger определить все режимы работы эксперта, включая и те, что связаны с тестером и оптимизацией. Задав в качестве параметра один из элементов перечисления ENUM_MQL_INFO_INTEGER, мы получим в результате логический признак (true/false):
- MQL_TESTER - программа работает в тестере;
- MQL_VISUAL_MODE - тестер запущен в визуальном режиме;
- MQL_OPTIMIZATION - тестовый проход выполняется в ходе оптимизации (а не отдельно);
- MQL_FORWARD - тестовый проход выполняется на форвард-периоде после оптимизации (если задано настройками оптимизации);
- MQL_FRAME_MODE - эксперт запущен в особом сервисном режиме на графике терминала (а не на агенте) для управления оптимизацией (об этом подробнее в следующем разделе).
Режимы работы MQL-программ, связанные с тестером
Все готово для запуска оптимизации. Сразу в момент её начала, при упоминавшихся настройках Presets/MQL5Book/BandOsMA.set, мы увидим сообщение в журнале Эксперты терминала:
Parameter FastSlowCombo4Optimization is enabled with maximum: 698 |
На этот раз в журнале оптимизации не должно быть ошибок, и все поколения генерируются без сбоев.
...
|
Это можно определить даже по увеличившемуся общему времени оптимизации: раньше часть проходов отбраковывалась на ранней стадии, а теперь они все обрабатываются целиком.
Но у нашего решения есть и один минус. Теперь в рабочих настройках эксперта фигурирует не пара периодов в параметрах FastOsMA и SlowOsMA, а порядковый номер их комбинации среди всех возможных (FastSlowCombo4Optimization). Единственное, что мы можем сделать, это выводить раскодированные периоды в функции OnInit, что и было продемонстрировано выше.
Таким образом, найдя с помощью оптимизации хорошие настройки, пользователь, как обычно, выполнит одиночный прогон, чтобы уточнить поведение торговой системы. И в начале журнала тестирования должна появиться надпись вида:
MA periods are restored from shadow: FastOsMA=27 SlowOsMA=175 |
Тогда можно ввести указанные периоды в одноименные параметры, а все теневые параметры обнулить.