- Генерация тиков в тестере
- Управление ходом времени в тестере: таймер, Sleep, GMT
- Визуализация тестирования: график, объекты, индикаторы
- Мультивалютное тестирование
- Критерии оптимизации
- Получение финансовых показателей теста: TesterStatistics
- Событие OnTester
- Авто-настройка: ParameterGetRange и ParameterSetRange
- Группа OnTester-событий для контроля оптимизации
- Отправка фреймов данных с агентов в терминал
- Получение фреймов данных в терминале
- Директивы препроцессора для тестера
- Управление видимостью индикаторов: TesterHideIndicators
- Эмуляция пополнения депозита и снятия средств
- Принудительная остановка тестирования: TesterStop
- Большой пример эксперта
- Математические вычисления
- Отладка и профилирование
- Ограничения работы функций в тестере
Директивы препроцессора для тестера
В разделе об Общих свойствах программ мы впервые познакомились с директивами #property в MQL-программах. Затем нам встречались директивы, предназначенные для скриптов, сервисов и индикаторов. Есть своя группа директив и для тестера. Некоторые из них мы уже упоминали, в частности, tester_everytick_calculate влияет на расчет индикаторов.
В следующей таблице представлены все директивы тестера. Ниже приведены пояснения.
Директива |
Описание |
---|---|
tester_indicator "строка" |
Имя пользовательского индикатора в формате "имя_индикатора.ex5" |
tester_file "строка" |
Имя файла в формате "имя_файла.расширение" с исходными данными, необходимыми для теста программы |
tester_library "строка" |
Имя библиотеки с расширением, например, "библиотека.ex5" или "библиотека.dll" |
tester_set "строка" |
Имя файла в формате "имя_файла.set" с настройками значений и диапазонов оптимизации входных параметров программы |
tester_no_cache |
Отключение чтения имеющегося кэша предыдущих оптимизаций (opt-файлов) |
tester_everytick_calculate |
Отключение экономного режима расчета индикаторов в тестере |
Две последних директивы не имеют аргументов. Все остальные ожидают указания строки в двойных кавычках с названием файла того или иного типа. Из этого также следует, что директивы могут повторяться с разными файлами, то есть можно подключить несколько файлов настроек или несколько индикаторов.
Директива tester_indicator требуется для подключения к процессу тестирования тех индикаторов, которые не упомянуты в исходном коде тестируемой программы в виде константных строк (литералов). Как правило, необходимый индикатор может быть определен компилятором автоматически из вызова функций iCustom, если его имя в явном виде задано в соответствующем параметре, например, iCustom(symbol, period, "indicator_name",...). Однако так бывает не всегда.
Допустим, мы пишем универсальный эксперт, который способен использовать разные индикаторы скользящего среднего, а не только стандартные встроенные. Тогда мы можем завести входную переменную для указания имени индикатора пользователем. И вызов iCustom превратится в iCustom(symbol, period, CustomIndicatorName,...), где CustomIndicatorName — входная переменная эксперта, содержимое которой не известно в момент компиляции. Более того, разработчик в таком случае, скорее всего, применит IndicatorCreate вместо iCustom, так как количество и типы параметров индикатора должны также настраиваться. В подобных случаях, для отладки программы или её демонстрации с конкретным индикатором, тестеру нужно сообщить его имя с помощью директивы tester_indicator.
Необходимость сообщать имена индикаторов в исходном коде существенно ограничивает возможности тестирования подобных универсальных программ, способных подключать различные индикаторы онлайн.
Без директивы tester_indicator терминал не сможет отправить на агент индикатор, который явно не задекларирован в исходном коде, в результате чего зависимая программа утратит часть или весь функционал.
Директива tester_file позволяет указать файл, который будет передан на агенты и помещен в песочницу перед началом тестирования. Содержимое и тип файла не регламентирован. Например, это могут быть веса предварительно обученной нейронной сети, данные "стакана", собранные загодя онлайн (т.к. они не воспроизводятся самим тестером) и так далее.
Файл из директивы tester_file считывается только в том случае, если он существовал на момент компиляции. Если исходный код скомпилирован, когда не было соответствующего файла, то его появление в дальнейшем уже не поможет: откомпилированная программа отправится на агент без вспомогательного файла. Поэтому, например, если файл, указанный в tester_file, генерируется в OnTesterInit, следует убедиться, что файл с заданным именем уже был в момент компиляция, хотя бы и пустой. Мы продемонстрируем это ниже.
Обратите внимание, что компилятор не выдает предупреждений, если файла, указанного в директиве tester_file, не существует.
Подключаемые файлы должны находиться в "песочнице" терминала MQL5/Files/.
Директива tester_library сообщает тестеру о необходимости передать на агенты библиотеку — вспомогательную программу, способную работать только в контексте другой MQL-программы. О библиотеках мы подробно поговорим в отдельном разделе.
Необходимые для тестирования библиотеки определяются автоматически по директивам #import в исходном коде. Однако, если какая-либо библиотека используется внешним индикатором, то необходимо включить данное свойство. Библиотека может быть как с расширением dll, так и с расширением ex5.
Директива tester_set оперирует set-файлами с настройками MQL-программы. Указанный в директиве файл станет доступен из контекстного меню тестера и позволит пользователю быстро применить настройки.
Если имя указано без пути, set-файл должен лежать в том же каталоге, где эксперт. Это несколько неожиданно, т.к. по умолчанию каталог set-файлов другой — Presets, и именно туда они сохраняются по командам из интерфейса терминала. Чтобы подключить set-файл из данного каталога, нужно явно указать его в директиве и предварить косой чертой, которая обозначает абсолютный путь внутри папки MQL5.
#property tester_set "/Presets/xyz.set" |
Когда ведущей косой черты нет, путь считается относительно места размещения исходного текста.
Сразу после добавления файла и перекомпиляции программы нужно перевыбрать эксперт в тестере, потому что иначе файл не подхватится!
Если в названии set-файла указать имя эксперта и номер версии как "<expert_name>_<number>.set", то он автоматически добавится в меню загрузки версий параметров под номером версии <number>. Например, имя "MACD Sample_4.set" означает, что это set-файл для эксперта "MACD Sample.mq5" с номером версии равным 4.
Желающие могут изучить формат set-файлов: для этого достаточно вручную сохранить настройки тестирования/оптимизации в тестере стратегий и затем открыть созданный таким образом файл в текстовом редакторе.
Теперь обратимся к директиве tester_no_cache. Тестер стратегий при выполнении оптимизации сохраняет все результаты выполненных проходов в кэш оптимизации (файлы с расширением opt), в котором для каждого набора входных параметров сохраняется результат тестирования. Это позволяет при повторной оптимизации на тех же параметрах брать готовые результаты без повторного вычисления и затрат времени.
Но для некоторых задач — например, при математических вычислениях — может потребоваться проводить расчеты независимо от наличия готовых результатов в кэше оптимизации. В этом случае в исходном коде необходимо включить свойство tester_no_cache. При этом сами результаты тестирования все равно будут сохраняться в кэше, чтобы можно было в тестере стратегий посмотреть все данные по выполненным проходам.
Директива tester_everytick_calculate предназначена для включения режима расчета индикатора на каждом тике в тестере.
По умолчанию индикаторы рассчитываются в тестере только при обращении к ним за данными — то есть, когда запрашиваются значения индикаторных буферов. Это даёт существенное ускорение при тестировании и оптимизации, если не требуется получать значения индикатора на каждом тике.
Однако некоторые программы могут требовать пересчета индикаторов на каждом тике. Именно в таких случаях и пригодится свойство tester_everytick_calculate.
Индикаторы в тестере стратегий также принудительно считаются на каждом тике в следующих случаях:
- при тестировании в визуальном режиме;
- при наличии в индикаторе функций EventChartCustom, OnChartEvent, OnTimer;
Данное свойство касается только работы в тестере стратегий — в терминале индикаторы всегда считаются на каждом поступившем тике.
В эксперте FrameTransfer.mq5 уже была на самом деле использована директива:
#property tester_set "FrameTransfer.set" |
Просто мы не акцентировали на этом внимание. Файл "FrameTransfer.set" находится рядом с исходным кодом. В том же эксперте нам пригодилась и другая директива из вышеприведенной таблицы:
#property tester_no_cache |
В дополнение рассмотрим пример директивы tester_file. Ранее в разделе про автонастройку параметров экспертов при оптимизации мы представили эксперт BandOsMApro.mq5, в котором потребовалось ввести несколько теневых параметров для передачи диапазонов оптимизации в наш исходный код, выполняющийся на агентах.
Директива tester_file позволит нам избавиться от этих лишних параметров. Новую версию эксперта назовем BandOsMAprofile.mq5.
Поскольку мы теперь знакомы с директивой tester_set, добавим в новую версию уже упоминавшийся ранее файл /Presets/MQL5Book/BandOsMA.set.
#property tester_set "/Presets/MQL5Book/BandOsMA.set" |
Информацию о диапазоне и шаге изменения периодов FastOsMA и SlowOsMA будем сохранять в файл "BandOsMAprofile.csv" вместо трех дополнительных входных параметров FastShadow4Optimization, SlowShadow4Optimization, StepsShadow4Optimization.
#define SETTINGS_FILE "BandOsMAprofile.csv"
|
Теневой параметр FastSlowCombo4Optimization по-прежнему нужен для полного перебора разрешенных комбинаций периодов.
input group "A U X I L I A R Y"
|
Напомним, его диапазон для оптимизации мы находим в функции Iterate. Первый раз мы её вызываем в OnTesterInit с полным перебором сочетаний быстрого и медленного периодов.
В принципе, мы могли бы сохранить все допустимые сочетания в массив структур PairOfPeriods и записать его в двоичный файл для передачи на агенты. Тогда на агентах наш эксперт мог бы прочитать из файла готовый массив и по индексу FastSlowCombo4Optimization извлечь из массива соответствующую пару FastOsMA и SlowOsMA.
Вместо этого мы остановимся на минимальном изменении рабочей логики программы: будем по прежнему восстанавливать пару периодов за счет второго вызова Iterate в обработчике OnInit. Только на этот раз диапазон и шаг перебора значений периодов мы получим не из теневых параметров, а из CSV-файла.
Вот изменения в OnTesterInit.
int OnTesterInit()
|
Обратите внимание, мы сделали обработчик OnTesterInit с типом возврата int, что дает возможность отменить оптимизацию, если файл не существует. Однако в файл в любом случае записываются актуальные данные, так что если его не было, он создается, и последующий запуск оптимизации уже пройдет успешно.
Если вы хотите исключить этот шаг, можете заранее создать пустой файл MQL5/Files/BandOsMAprofile.csv.
Обработчик OnInit преобразился следующим образом.
int OnInit()
|
При запуске одиночных тестов после оптимизации мы увидим в журнале раскодированные значения периодов FastOsMA и SlowOsMA на основе оптимизированного значения FastSlowCombo4Optimization. В дальнейшем мы можем подставить эти значение в параметры-периоды, а csv-файл удалить. Также мы предусмотрели, что файл не будет учитываться, если в FastSlowCombo4Optimization поставить значение -1.