Статьи по MQL4
Перевод индикатора из MQL-2 в MQL-4

Перевод индикатора из MQL-2 в MQL-4


например, forex

Рассмотрим на примере несложного индикатора, написанного для терминала MetaTrader3, процесс переноса кода в MQL-4. Хотя сам язык MQL-2 является существенно более простым, но некоторые особенности и его ограничения наложили свой отпечаток на стиль написания сложных индикаторов. Первое отличие- в MQL-2 индикатор мог отрисовывать не более двух индексов, поэтому в случае необходимости приходилось писать несколько родственных индикаторов (вспомним из известных индикаторы Pivot, где кроме точки вращения нужно было рисовать и линии поддержки и сопротивления). В других случаях приходилось создавать индикатор, который строился на вызовах другого пользовательского индикатора, так как была потребность в дополнительных буферах, а использовать массивы не всегда было удобно.
Второе ограничение – из-за низкой скорости работы языка-интерпретатора работа индикатора (вычисления в теле индикатора или эксперта) принудительно завершалась через определенное время, приходилось использовать служебную переменную, в которой хранился индекс последнего рассчитанного бара, и при поступлении нового тика продолжать работу цикла с запомненного значения. В MQL-4 такой потребности нет, язык быстрый и для целей оптимизации была специально создана функция IndicatorsCounted().
Третье ограничение – малое число стилей отрисовки, в МТ3 была линия, гистограмма и стрелки. Сам код индикатора на MQL-2

 
 


Зеленым цветом прокомментирована интерфейсная часть, тут никаких сложностей нет. Далее в секции Inputs идут входные параметры , здесь нам необходимо только определиться каким типом их объявить в MQL-4. Переменные ppor(100),mpor(-100) используются для отрисовки второго буфера, а так индикаторные буфера в MQL-4 всегда имеют тип double, то для единообразия объявим их тем же типом. Переменная per является периодом индикатора CCI(), поэтому объявим ее типом int. Переменная t3_period(8) используется для вычисления значения типа double, хотя по смыслу должна означать некий целочисленный период, поэтому можно объявить ее и так и сяк, но я все же объявлю ее с типом double. С переменной b и так все понятно. Переменная x_prd нигде в коде не используется, ее просто выбрасываем. Все переменные (Variable), кроме shift, объявим типом double, это видно из логики вычислений. Все готово для написания индикатора. Начинаем стандартную процедуру:

 
 


Имя индикатора я поставил такое же, что было в МТ3, хотя в самом коде стоит имя RoundPrice.

 
 


Переменные можем скопировать из кода mql, поменяем Inputs на double, объявим их в интерфейсной части. Можно заметить, что эта часть кода бесполезно вычисляется каждый тик, хотя значения этих переменных не меняются:

 
 


Поэтому, мы можем эту часть вычислений поместить в ту часть индикатора, которая выполняется только один раз перед после запуска индикатора – в блок init().
Оператор if() требует минимальной правки.

 
 


Оператор SetLoopCount(0); просто игнорируем, он из прошлой жизни и в MQL-4 абсолютно не нужен никогда. Опять копируем код и приводим синтаксис к MQL-4. Открывающий оператор Begin и закрывающий оператор End заменяем фигурными скобками:

 
 


Нам осталось только перевести три выделенных блока, и работа, можно сказать, закончена. Операторы SetIndexValue() и SetIndexValue2() в MQL-2 заполняют индикаторные массивы №1 и №2. Поэтому запишем просто:

 
 


Технический индикатор iCCI() также переносится несложно, добавим только параметр инструмента и тайм-фрейма. В MQL-2 было два технических индикатора : iCCI() и iCCIEx(), разница между ними только в том, что первый строился только по ценам закрытия, а второму можно было задавать тип цен для расчетов. Можно посмотреть справку МТ3. Заодно отметим четвертое отличие МТ3 от МТ4 – подробная справочная система на русском языке. Делаем последнюю замену – индикатор готов.

 
 


Запускаем для сравнения индикатор в обоих терминалах, в МТ3

 
 


и в МТ4

 
 


Небольшая погрешность объясняется разным способом построения цены. При этом можно заметить, что индикатор в МТ3 рассчитывается заметно медленнее и на более слабых компьютерах временами даже может совсем пропадать. На моем Celeron-2000 после первого расчета окно индикатора несколько раз очищалось и приходилось запускать индикатор заново. Мы сделали, фактически, подстрочный перевод, и теперь можем немного проанализировать код индикатора, чтобы его улучшить. Улучшение будет заключаться в оптимизации механизма расчета индикатора. Первый вопрос возникает с не нужным ,вроде бы, циклом, в котором происходит обнуление обоих индикаторных массивов.

 
 


К тому же мы не использовали функцию InditarorCounted(). Закомментируем цикл и введем ограничитель расчета.

 
 


Возникает два вопроса, первый – почему при первом расчете, когда counted_bars еще равен нулю, мы устанавливаем limit равным Bars-per? Смотрим ниже по коду и видим, что в расчетах используется вызов технического индикатора iCCI() с периодом per. Набрасываем его на график и видим, что рисоваться индикатор CCI(14) начинает только с 15-го бара с конца, а до этого момента его значения не определены.

 
 


А если расчет уже проводился (counted_bars больше нуля) , то выражение Bars-counted_bars обычно равно единице (в каких случаях это не так - вы можете проверить сами). А так как для оптимизации расчетов мы будем стараться считать минимальное количество баров, то уменьшая limit на единицу, мы удовлетворяем для обоих случаев в первом случае в итоге limit=Bars-per-1, а во втором случае limit=0. На этом оптимизацию можно считать законченной, если не одно НО. Если мы повесим наш последний вариант индикатора на 15 минутки и подождем полчаса (чтобы появилось два новых бара), а затем набросим на график еще один такой же индикатор с такими же параметрами, но с другими цветами (чтобы их различать), то увидим существенную разницу.

 
 


Оказывается, наш индикатор меняет свои показания с течением времени, в таких случаях еще говорят, что индикатор перерисовывает себя. Но в данном случае это не так, просто у нас плывут значения переменных, служащих для расчета индикатора на нулевом баре. Для этого добавим вывод в лог значений этих переменных. Сохраняем наш новый индикатор под именем SmCCI-2.mq4 и начинаем его модифицировать.

 
 


Видим, что «плывут» все переменные. Теперь становится понятно для чего был необходим цикл, в котором обнулялись значения индикатора на каждом тике. Таким образом автор индикатора боролся с этим неприятным эффектом. Из-за этого очищающего цикла у меня пропадал индикатор в терминале МТ3, так как времени, отводимого индикатору в MQL-2 на каждый тик, хватало только на очистку двух буферов и не хватало на повторный полный расчет индикатора.

 
 


Нам необходимо зафиксировать (стабилизировать) переменные e1,e2… e6 и наши проблемы будут решены. Расчет каждой из этих переменных для текущего бара зависит от значения этой переменной на предыдущем баре. Это напоминает в какой-то степени алгоритм расчета экспоненциальной скользящей средней, и мы можем применить такой же способ для хранения этих переменных в индикаторных буферах. Для этого объявим e1Buffer[],e2Buffer[]…e6Buffer[].

 
 


Массивы объявлены, теперь заменим переменные соответствующими массивами. На рисунке отмечены два момента, нарушение которых ведет к неправильной работе индикатора. Это две наиболее распространенные ошибки в тех случаях, когда индикатор использует больше индикаторных буферов, чем выводится на экран. Если их допустить, то можно долго и безуспешно искать ошибку в логике индикатора.

 
 


Запускаем два варианта индикатора на графике, спустя два бара вешаем еще один, первый вариант (который «плывет») и видим, что второй вариант не меняет свои показания со временем, в отличие от первого.

 
 


Конечно, в какой-то степени рассматриваемый индикатор оказался простым, и нам повезло, что восьми индикаторных буферов оказалось достаточно для решения проблемы с данным индикатором, но на самом деле, если бы потребовалось не 8, а 9 и более индикаторных буферов (индикатор может иметь на данный момент не более восьми встроенных буферов) – то и в этом случае мы смогли бы решить эту проблему. Мы могли бы ввести дополнительные переменные, в которых хранили бы значения на предыдущем баре (что-то вроде prev_e1, prev_e2… prev_e6) или объявить просто массивы. Мне пока не приходилось встречаться с ситуациями, когда нельзя было бы написать индикатор в MQL-4. На этом перенос кода из MQL-2 в MQL-4 можно считать законченным, остальная доводка индикатора принципиально алгоритм уже не меняет. Сами индикаторы можно взять здесь .

Перейти к статье «Знакомство с OrderSend()».
 
+7 (495) 710-76-76
8 (800) 200-01-31
по России бесплатно

закрыть

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

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

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

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

 
Rambler's Top100