Статьи по MQL4
Знакомство с тестером

Знакомство с тестером


например, forex

… очевидный феномен, который я наблюдал много раз на протяжении многих лет, но для которого у меня нет
неопровержимых доказательств: большинство людей торгуют хуже, чем трейдер, полагающийся исключительно
на случайный выбор.
Уильям Экхардт (Джек Д. Швагер «Новые маги рынка»)

Мы знаем основные торговые функции(кроме OrderModify()), у нас имеются некоторые соображения о простейшей торговой системе на EURUSD, основанной на приращении цены в модели нормального процесса , осталось только проверить. Для этого мы напишем советника (Random Trade.mq4), который будет открывать сделки случайным образом в случайном направлении с жестко заданными параметрами StopLoss и TakeProfit.

Зададим внешний параметр int StDev, который будет означать подразумевать стандартное отклонение в пунктах. Наш StopLoss будет равен этому параметру с неким коэффициентом, который мы будем менять, назовем его SL_K. Соответственно, TakeProfit также будет вычислять как SL_K *StDev . Поэтому параметры SL_K и TP_K также будут внешними (изменяемыми на усмотрение пользователя).

Для моделирования случайной величины в MQL-4 служит функция MathRand(). Чтобы получить случайную величину в интервале от 0 до 1, нам придется разделить ее значение на 32767. Если результат больше 0.5 – мы покупаем по рыночным ценам, если меньше 0.5 – продаем. В принципе, советник уже готов.

Начинаем процесс создания советника с помощью «Мастера создания советника»

 
 


Пишем простую функцию GetOrder(), и советник готов. Обратите внимание, что уровни StopLoss(SL) и TakePofit(TP) для открываемого ордера предварительно нормализуется. Так как коэффициенты для вычисления этих уровней необязательно будут целыми, а значит и сами вычисляемые уровни также могут содержат количество знаков после запятой больше, чем Digits, то лучше нам самим округлить эти цены до нужного значения, иначе торговый сервер может просто отвергнуть приказ на открытие ордера. Нормализация всегда необходима, когда уровни цен вычисляются, и желательна, даже когда мы просто берем цены с графика. Также в ордере стоит ненулевой параметр Slippage , для тестирования он влияния не окажет, но при торговле в реальном времени лучше его задавать, чтобы на изменяющемся рынке при открытиях или закрытиях по рынку не получать отказ сервера из-за устаревания цены.

 
 


Ну и, конечно, никогда не забываем, что покупки совершаются по цене Ask, а продажи по цене Bid. В качестве комментария мы записываем случайное число Random, на основании которого было принято решение о направлении торговли. Отчасти это сделано для примера, отчасти для контроля правильности алгоритма. Компилируем советника, открываем в терминале панель тестера (Ctrl+R), выбираем нашего советника, нужный символ и нужный тайм-фрейм. Модель тестирования ставим «По ценам открытия(быстрый метод на сформировавшихся барах)». Может сложиться ситуация, что в разворачивающимся списке символов не окажется нужного нам. Тогда необходимо схватить мышкой нужный символ и бросить на панель тестера (модель “Drag & Drop”).

 
 


Правда, есть в нем некоторая искусственность, неправильность, если присмотреться. Если ордер открыт, то новый ордер не откроется, пока не произойдет закрытие с прибылью или с убытком, но как только ордер закрылся – тут же открывается новый случайный ордер. Жмем кнопку «Старт», после окончания тестирования открываем закладку «Результаты» и видим подтверждение:

 
 


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

Значит нам необходимо как то получать информацию о времени закрытия последнего ордера. Для этого введем две новые переменные: lastTicket (номер тикета последнего ордера) и lastCloseTime (время последнего закрытия). Чтобы не терять эти значения в перерывах между вызовами функции start(), объявим их на глобальном уровне. Также добавим внешний параметр periodTrade, его значение будет нам гарантировать максимальное время между двумя ордерами. Наш советник RandomTrade-2 выглядит теперь так:

 
 


В советнике специально добавлено множество закомментированных выводов в лог (Print()), при необходимости для лучшего понимания их можно раскомментировать. Теперь при удачном открытии ордера запоминается его тикет. Позже в функции GetOrder() промежуток времени между последним закрытием и текущим временем сравнивается с заданным периодом в барах periodTrade. Выражение (CurTime()-lastCloseTime)/( periodTrade*Period()*60.0) поначалу будет малым, но с каждым новым баром в тестере будет расти, и случайное число в интервале от 0 до 1 сначала будет иметь минимальную вероятность оказаться меньше этого выражения , но после periodTrade баров вероятность открытия нового ордера станет 100%.
Запускаем новый вариант советника, и видим, что ситуация исправилась. Теперь появилась пауза между сделками.

 
 


Но если мы изменим модель «По ценам открытия» на модель «Все тики» или «Контрольные точки», то картина изменится , вот «Результаты» по «Контрольным точкам»

 
 


и вот по «Всем тикам»

 
 


Вы можете провести тестирования на своем компьютере, количество и порядок сделок у вас будут отличаться от моих, но общий вывод будет такой же – чем более подробное моделирование мы проводим, тем больше получается сделок. Мы получили наглядное доказательство неправильного строительства этого простого советника – от изменения режима моделирования результаты теста очень сильно меняются. Если ваш советник, написанный по какой-то стратегии (а не как у меня на случайности) будет себя вести также – значит у вас имеется серьезный изъян в алгоритме советника. Чтобы получать результаты, не сильно зависящие от режима моделирования, вам необходимо:
  1. закачать как можно более подробную историю за тестируемый период начиная с минуток, и
  2. в явном виде разделить события EveryBar и EveryTick, как в советнике BlackBox.mq4.
Пусть эти события(функции) будут у вас называться и определены иначе, чем у меня, но вы должны их четко различать.

Тут можно возразить- «Конечно, количество сделок на разных моделях будет различаться, так как у нас случайные сделки, и повторятся они не обязаны». На самом деле у нашего советника есть последний недостаток – он не является на самом деле случайным, хотя мы и использовали функцию MathRand(). Каждый раз при каждом прогоне в тестере генерируется одна и та же последовательность псевдослучайных чисел, и поэтому на каждом режиме моделировании мы получаем одну и ту же последовательность сделок. Проверьте сами.

Чтобы получать новую последовательность случайных чисел, необходимо генератор случайных чисел инициализировать с помощью функции MathSrand(). Если мы используем MathSrand(1), то последовательность случайных чисел будет одна, если MathSrand(2) – то другая. Но ведь нам необходимо, чтобы при каждом новом тестировании получать новый ряд сделок, последовательности сделок должны быть разными. Самый простой выход – использовать конструкцию MathSrand(GetTickCount()). Поместим ее в блок init() и задача решена, так как функция GetTickCount() при каждом новом вызове будет возвращать новое значение. Окончательный вариант мы назовем RandomTrade-3.mq4.

Теперь мы можем провести оптимизацию нашего советника, то есть поиск наилучших параметров для получения прибыли, или другими словами – подтверждается ли гипотеза, что при соотношении TP/SL=3 мы не только получим прибыль, но и эта прибыль будет максимальна. Нажимаем кнопку «Свойства эксперта» , выбираем закладку «Входные параметры» и отмечаем как на рисунке.

 
 


Не забудем убедиться, что на закладке «Тестирование» чек-бокс «Генетические алгоритмы» не отмечен – он нам сейчас не нужен. Начальный депозит оставим как есть - $10000 , разрешены покупки и продажи (Позиции: Long&Short).

 
 


Отмечаем на панели тестера чек-бокс «Оптимизация», модель «По ценам открытия» и получаем что-то подобное.

 
 


Прогоняем еще раз – получаем новый график оптимизации результатов.

 
 


Хорошо видно, что на одних и тех же параметрах каждый раз получается новая серия случайных сделок, то есть мы добились все таки случайности. Но возникает новый вопрос – как же нам определить – являются ли какие-то параметры более оптимальными, чем другие. Оптимизация советника нам в данном случае не дает однозначного ответа, как быть? Если бы провели при каждом параметре по 100 прогонов советника в тестере, то мы бы смогли как-нибудь сравнить между собой результаты тестирования, полученные при разных параметрах. Мы бы могли усреднять прибыль за 100 прогонов, или количество сделок, или прибыльность.

 
 


Результаты оптимизации легко сортируются по возрастанию или убыванию при нажатии на имя столбца. Если мы два раза кликнем на строку с нужными нам параметрами советника, то попадем опять на закладку «Настройки», при этом эти параметры будут использоваться при тестировании советника.

 
 


Прогоняем советник с этими параметрами, получаем график.

 
 


Видим, что при тестировании кривая Баланса испытывала и подъемы и спады, но прибыль в $3963.66 не обнаружена. Количество сделок и прочие характеристики тестирования тоже не сходятся.

 
 


Мы стремились получить случайные сделки – мы их получили. Но наша гипотеза о возможности зарабатывания на случайных входах при определенном соотношении TP/SL так и не проверена. У нас есть последний способ это сделать - добавим пустую переменную (я ее назвал Balk), от которой ничего в алгоритме советника не зависит и сделаем оптимизацию. Эту новую внешнюю переменную я поместил самой первой в секции внешних параметров, чтобы прогон в оптимизаторе начинался с перебора ее значений. Назовем этот вариант советника RandomTrade-4, скомпилируем и зададим параметры оптимизации.

 
 


Параметр SL_K я исключил для ускорения процесса (все-таки потребуется 3000 проходов). При тестировании на часовках у меня это заняло 13 минут.

 
 


Видим, что при малом значении StDev (а значит и StopLoss) наблюдается сильная и устойчивая убыточность советника, которая практически не зависит от величины TakeProfit. График оптимизации можно еще посмотреть в виде двумерной плоскости, для этого жмем правую кнопку мыши и задаем этот режим.

 
 


Задаем значения для оси X

 
 


и для Y

<#IMG21>

Таким образом, можно очень удобно визуально оценивать влияние параметров советника на результаты тестирования. На этом знакомство с тестером можно считать состоявшимся. Возможно, что результаты тестирования этого советника дадут вам новый взгляд на эпиграф к этой статье. Файлы экспертов находятся здесь .
Перейти к статье «Своя статистика (команда #include)».
 
+7 (495) 710-76-76
8 (800) 200-01-31
по России бесплатно

закрыть

Вход в личный кабинет

Для счета alpari.classic введите номер счета (буква и 4 цифры) и пароль в ЛК.

Для счетов alpari.micro и alpari.partner введите логин и пароль в МТ.

Зарегистрироваться!Забыли пароль?

 
Rambler's Top100