- Генерация тиков в тестере
- Управление ходом времени в тестере: таймер, Sleep, GMT
- Визуализация тестирования: график, объекты, индикаторы
- Мультивалютное тестирование
- Критерии оптимизации
- Получение финансовых показателей теста: TesterStatistics
- Событие OnTester
- Авто-настройка: ParameterGetRange и ParameterSetRange
- Группа OnTester-событий для контроля оптимизации
- Отправка фреймов данных с агентов в терминал
- Получение фреймов данных в терминале
- Директивы препроцессора для тестера
- Управление видимостью индикаторов: TesterHideIndicators
- Эмуляция пополнения депозита и снятия средств
- Принудительная остановка тестирования: TesterStop
- Большой пример эксперта
- Математические вычисления
- Отладка и профилирование
- Ограничения работы функций в тестере
Получение финансовых показателей теста: TesterStatistics
Обычно мы оцениваем качество эксперта по торговому отчету, аналогом которого в тестере является отчет тестирования. В нем представлено большое количество показателей, характеризующих стиль торговли, стабильность и, разумеется, прибыльность. Все эти показатели, за некоторым исключением, доступны MQL-программе посредством специальной функции TesterStatistics. Таким образом, разработчик эксперта имеет возможность анализировать в коде отдельные показатели и конструировать из них собственные комбинированные критерии качества оптимизации.
double TesterStatistics(ENUM_STATISTICS statistic)
Функция TesterStatistics возвращает значение указанного статистического показателя, рассчитанного по результатам отдельного прогона эксперта в тестере. Функцию можно вызывать в обработчике OnDeinit или OnTester, о котором речь еще впереди.
Все доступные показатели сведены в перечисление ENUM_STATISTICS. Часть показателей представляет собой качественные характеристики, то есть вещественные числа (как правило, итоговые суммы прибыли, просадки, коэффициенты и так далее), а другая часть — количественные, то есть целые числа (например, количество сделок). Однако обе группы управляются одной и той же функцией, несмотря на её тип результат double.
В следующей таблице приведены показатели вещественные (денежные суммы и коэффициенты). Все денежные суммы выражаются в валюте депозита.
Идентификатор |
Описание |
---|---|
STAT_INITIAL_DEPOSIT |
Начальный депозит |
STAT_WITHDRAWAL |
Размер выведенных со счета средств |
STAT_PROFIT |
Чистая прибыль или убыток по окончании тестирования, сумма STAT_GROSS_PROFIT и STAT_GROSS_LOSS |
STAT_GROSS_PROFIT |
Общая прибыль, сумма всех прибыльных трейдов (больше или равно нулю) |
STAT_GROSS_LOSS |
Общий убыток, сумма всех убыточных трейдов (меньше или равно нулю) |
STAT_MAX_PROFITTRADE |
Максимальная прибыль — наибольшее значение среди всех прибыльных трейдов (больше или равно нулю) |
STAT_MAX_LOSSTRADE |
Максимальный убыток — наименьшее значение среди всех убыточных трейдов (меньше или равно нулю) |
STAT_CONPROFITMAX |
Общая максимальная прибыль в серии прибыльных трейдов (больше или равно нулю) |
STAT_MAX_CONWINS |
Общая прибыль в самой длинной серии прибыльных трейдов |
STAT_CONLOSSMAX |
Общий максимальный убыток в серии убыточных трейдов (меньше или равно нулю) |
STAT_MAX_CONLOSSES |
Общий убыток в самой длинной серии убыточных трейдов |
STAT_BALANCEMIN |
Минимальное значение баланса |
STAT_BALANCE_DD |
Максимальная просадка баланса в деньгах |
STAT_BALANCEDD_PERCENT |
Просадка баланса в процентах, которая была зафиксирована в момент максимальной просадки баланса в деньгах (STAT_BALANCE_DD) |
STAT_BALANCE_DDREL_PERCENT |
Максимальная просадка баланса в процентах |
STAT_BALANCE_DD_RELATIVE |
Просадка баланса в деньгах, которая была зафиксирована в момент максимальной просадки баланса в процентах (STAT_BALANCE_DDREL_PERCENT) |
STAT_EQUITYMIN |
Минимальное значение собственных средств |
STAT_EQUITY_DD |
Максимальная просадка средств в деньгах |
STAT_EQUITYDD_PERCENT |
Просадка средств в процентах, которая была зафиксирована в момент максимальной просадки средств в деньгах (STAT_EQUITY_DD) |
STAT_EQUITY_DDREL_PERCENT |
Максимальная просадка средств в процентах |
STAT_EQUITY_DD_RELATIVE |
Просадка средств в деньгах, которая была зафиксирована в момент максимальной просадки средств в процентах (STAT_EQUITY_DDREL_PERCENT) |
STAT_EXPECTED_PAYOFF |
Математическое ожидание выигрыша (среднее арифметические общей прибыли и количества сделок) |
STAT_PROFIT_FACTOR |
Прибыльность — отношение STAT_GROSS_PROFIT/STAT_GROSS_LOSS (если STAT_GROSS_LOSS = 0, прибыльность принимает значение DBL_MAX) |
STAT_RECOVERY_FACTOR |
Фактор восстановления — отношение STAT_PROFIT/STAT_BALANCE_DD |
STAT_SHARPE_RATIO |
Коэффициент Шарпа |
STAT_MIN_MARGINLEVEL |
Минимальное достигнутое значение уровня маржи |
STAT_CUSTOM_ONTESTER |
Значение пользовательского критерия оптимизации, возвращенного функцией OnTester |
В следующей таблице приведены показатели целочисленные (количества).
Идентификатор |
Описание |
---|---|
STAT_DEALS |
Общее количество совершенных сделок |
STAT_TRADES |
Количество трейдов (сделок выхода из рынка) |
STAT_PROFIT_TRADES |
Прибыльные трейды |
STAT_LOSS_TRADES |
Убыточные трейды |
STAT_SHORT_TRADES |
Короткие трейды |
STAT_LONG_TRADES |
Длинные трейды |
STAT_PROFIT_SHORTTRADES |
Короткие прибыльные трейды |
STAT_PROFIT_LONGTRADES |
Длинные прибыльные трейды |
STAT_PROFITTRADES_AVGCON |
Средняя длина прибыльной серии трейдов |
STAT_LOSSTRADES_AVGCON |
Средняя длина убыточной серии трейдов |
STAT_CONPROFITMAX_TRADES |
Количество трейдов, сформировавших STAT_CONPROFITMAX (максимальная прибыль в последовательности прибыльных трейдов) |
STAT_MAX_CONPROFIT_TRADES |
Количество трейдов в самой длинной серии прибыльных трейдов STAT_MAX_CONWINS |
STAT_CONLOSSMAX_TRADES |
Количество трейдов, сформировавших STAT_CONLOSSMAX (максимальный убыток в последовательности убыточных трейдов) |
STAT_MAX_CONLOSS_TRADES |
Количество трейдов в самой длинной серии убыточных трейдов STAT_MAX_CONLOSSES |
Попробуем воспользоваться представленными показателями, чтобы создать свой собственный комплексный критерий качества эксперта. Для этого нам нужен некий "подопытный" пример MQL-программы. Возьмем за отправную точку эксперт MultiMartingale.mq5, но упростим его: уберем мультивалютность, встроенную обработку ошибок и работу по расписанию. Более того, выберем для него сигнальную торговую стратегию с однократным расчетом на баре, то есть по ценам открытия. Это позволит ускорить оптимизацию и расширить поле для экспериментов.
Стратегия будет основываться на состояниях перекупленности и перепроданности, определяемых индикатором OsMA. Динамически находить границы избыточной волатильности, означающей торговые сигналы, поможет индикатор Bollinger Bands, наложенный на OsMA.
Когда OsMA будет возвращаться внутрь коридора, пересекая нижнюю границу снизу вверх, будем открывать покупку. Когда OsMA будет аналогичным образом пересекать сверху вниз верхнюю границу, будем продавать. Для выхода из позиций используем еще один индикатор — скользящую среднюю, также примененную к OsMA. Если OsMA продемонстрирует обратное движение (вниз для длинной позиции или вверх для короткой) и коснется MA, позиция будет закрыта. Данная стратегия иллюстрируется следующим скриншотом.
Торговая стратегия на индикаторах OsMA, BBands и MA
Синяя вертикальная линия соответствует бару, на котором открыта покупка, так как на двух предыдущих барах произошло пересечение нижней линии Боллинджера гистограммой OsMA снизу вверх (в подокне это место помечено полой синей стрелкой). Красная вертикальная линия — это место возникновения обратного сигнала, поэтому покупка была закрыта и открыта продажа. В подокне в этом месте (а точнее, на двух предыдущих барах, где стоит полая красная стрелка) гистограмма OsMA пересекает верхнюю линию Боллинджера сверху вниз. Наконец зеленая линия обозначает закрытие продажи, из-за того, что гистограмма стала подниматься выше красной MA.
Дадим эксперту говорящее имя BandOsMA.mq5. В общие настройки войдут магическое число, фиксированный лот и дистанция стоплосса в пунктах. Для стоплосса оставим сопровождение с помощью TrailingStop из прошлого примера. Тейкпрофит здесь не используется.
input group "C O M M O N S E T T I N G S"
|
Три группы настроек предназначены для индикаторов.
input group "O S M A S E T T I N G S"
|
В эксперте MultiMartingale.mq5 у нас фактически не было торговых сигналов: в какую сторону открываться, задавал пользователь. Здесь у нас появились торговые сигналы, и имеет смысл оформить их отдельным классом. Для начала опишем абстрактный интерфейс TradingSignal.
interface TradingSignal
|
Он такой же простой, как и другой наш интерфейс TradingStrategy. И это хорошо. Чем проще интерфейсы и объекты, тем вероятнее, что они отвечают за один единственный род деятельности, что является хорошим стилем программирования, поскольку минимизирует ошибки и делает более понятными крупные программные проекты. Благодаря абстракции в любой программе, использующий TradingSignal, можно будет заменить один сигнал на другой. Впрочем, и как одну стратегию — на другую. У нас сейчас стратегии отвечают за подготовку и отправку приказов, а сигналы их инициируют за счет анализа рынка.
В нашем случае конкретную реализацию TradingSignal упакуем в класс BandOsMaSignal. Разумеется, нам потребуются переменные для хранения дескрипторов 3-х индикаторов. Создание экземпляров индикаторов и их удаление производится, соответственно, в конструкторе и деструкторе. Все параметры будут передаваться из входных переменных. Обратите внимание, что iBands и iMA строятся на дескрипторе hOsMA.
class BandOsMaSignal: public TradingSignal
|
Направление текущего торгового сигнала находится в переменной direction: 0 — нет сигналов (неопределенная ситуация), +1 — покупка, -1 — продажа. Заполнение этой переменной произведем в методе signal. Его код повторяет на MQL5 приведенное выше словесное описание сигналов.
virtual int signal(void) override
|
Как легко заметить, значения индикаторов считываются для баров 1 и 2, поскольку мы будем работать по открытию бара, и 0-й бар не то что незавершенный, а он только что открылся, когда мы вызовем метод signal.
Новый класс, реализующий интерфейс TradingStrategy, назовем SimpleStrategy.
В нем мы найдем кое-что новое, но и кое-что старое. В частности, в нем остались автоуказатели для PositionState и TrailingStop, зато добавился автоуказатель на сигнал TradingSignal. Также, поскольку мы собираемся торговать только по открытию баров, потребовалась переменная lastBar, в которой будет храниться время последнего обработанного бара.
class SimpleStrategy: public TradingStrategy
|
В конструктор SimpleStrategy передаются глобальные параметры, а также указатель на объект TradingSignal — очевидно, что это в данном случае будет BandOsMaSignal, и его должен будет создать вызывающий код. Далее конструктор пытается найти среди существующих позиций те, что имеют нужные magic-число и символ, и в случае успеха подключает к ней сопровождение. Это пригодится в случае, если в работе эксперт возник по тем или иным причинам перерыв, а позиция уже была открыта.
public:
|
Реализация метода trade во многом похожа на пример с мартингейлом, но здесь отсутствуют умножения лотов и добавился вызов метода signal.
virtual bool trade() override
|
Вспомогательные методы openBuy, openSell и другие претерпели минимальные изменения, поэтому мы не станем их приводить (полный исходный код прилагается).
Поскольку в данном эксперте у нас всегда только одна стратегия, в отличие от мультивалютного мартингейла, где каждый символ требовал собственных настроек, исключим пул стратегий и будем управлять объектом стратегии напрямую.
AutoPtr<TradingStrategy> strategy;
|
Теперь, вооружившись экспертом как инструментом, перейдем вплотную к исследованию тестера. Для начала создадим вспомогательную структуру для запроса и хранения всех статистических данных TesterRecord.
struct TesterRecord
|
В данном случае строковое поле feature нужно только для информативного вывода в журнал. Для сохранения всех показателей (например, чтобы иметь возможность позднее сгенерировать собственную форму отчета) достаточно просто массива типа double соответствующей длины.
С помощью структуры проверим в обработчике OnDeinit, что MQL5 API возвращает нам те же значения, что и отчет тестера.
void OnDeinit(const int)
|
Например, при запуске на EURUSD,H1 с депозитом 10000 и без всяких оптимизаций (с настройками по умолчанию) получим за 2021 год примерно такие величины (фрагмент):
[feature] [value]
|
Зная все эти величины, мы можем изобретать собственную формулу комбинированного показателя качества эксперта и заодно целевую функцию оптимизации. Но значение этого показателя в любом случае нужно будет сообщать тестеру. И именно для этого служит функция OnTester.