2.0 Пишем первый Индикатор

написать индикатор

Доброго времени суток!

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

В этом уроке мы изучим из чего состоит программный код любого индикатора, какие свойства и функции в нем применяются.

Создаем свой первый индикатор

индикатор Mql

Индикатор это программа, которая используется как вспомогательный алгоритм для анализа рынка или результатов торговли. Индикатор может содержать в себе информацию о вашем счете, открытых или закрытых ордерах, или может совершать технический анализ и подавать сигналы для открытия ордеров. Т.е. он может делать все, что и Советник, кроме, непосредственно, торговли. Индикатор может отображаться как на графике, так и в отдельном окне (в подвале). Основное его отличие от скрипта в том, что он выполняет заданные действия каждый тик, пока он присутствует на графике, тогда как скрипт удаляется с графика, как только функция OnStart() закончит свою работу.

Ну что же, давайте создадим индикатор, для этого в меню «Файл» редактора Meta Editor необходимо нажать кнопку Создать, либо воспользоваться сочетанием клавиш Ctrl+N. Выбираем пункт «Пользовательский индикатор» и жмем далее. Общие параметры задаются также, как и в Скрипте — вы вводить имя вашего индикатора, имя автора, ссылку на сайт. Все индикаторы хранятся в корневой папке терминала Indicators, путь к которой выглядит так:

C:\Users\Admin\AppData\Roaming\MetaQuotes\Terminal\<Номер терминала>\MQL4\Indicators

Внешние параметры сейчас не нужно задавать, это можно по необходимости выполнить после. Задали имя, жмем далее. 

Нам предлагается выбрать необходимые функции обработки событий. По умолчанию нам всегда нужна функция OnCalculate, галочки на OnTimer и OnChartEvent ставить не нужно, мы изучим их в следующих уроках.

Жмем далее. 

Галочку «Индикатор в отдельном окне» ставить не нужно, она нужна для подвальных индикаторов, их мы обязательно разберем в будущем. Раздел Отрисовка нужен для создания буферов для индикаторов. Это массивы, которые содержат в себе информацию о линиях, ценах и значениях отдельного индикатора, т.е. нужны для более сложного кода. Найти их можно в «Окне Данных» (Ctrl+D). В нашем случае буферы не нужны, поэтому пропускаем эту графу. Жмем Готово.

Поздравляю вас, товарищи, наш первый индикатор создан! Теперь давайте пройдемся по его изначальному коду.

С 1 по 5 строчку идет закомментированный код, который служит подсказкой для программиста о созданной программе, а именно наименование созданного индикатора, кому принадлежат права и вебсайт. По желанию эти строчки можно удалить, для самого кода они не нужны.

Далее в строчках 6-10 идут свойства программы. Более подробно о них было рассказано в уроке Скрипт Hello World. 

Тут все просто, это изначальные данные, которые мы передаем всей программе, а именно:

  • copyright — кому принадлежит этот индикатор
  • link — ссылка на сайт автора
  • version — номер версии программы. Меняется по мере дополнения в программу новых возможностей.
  • strict — строгий режим проверки на ошибки при компиляции. Параметр введен разработчиками с 600 версией билда и является рекомендуемым в коде.
  • indicator_chart_window — свойство обозначает, что индикатор будет отображать свои данные на графике, а не в отдельном окне.

Функция OnInit

Обязательной функцией, которая должна быть в каждом коде индикатора является функция обработки событий OnInit. Данная функция запускается сразу после загрузки индикатора или советника. Под загрузкой подразумевается установка программы на график, изменение настроек программы, смена таймфрейма текущего графика, либо торгового символа. Т.е. при каждом изменении пользователем параметров графика или программы — данная функция будет автоматически выполнена и код переинициализирован.

Нужна эта функция, чтобы в ней один раз перед работой основного кода сделать необходимые расчеты и проверки, вот несколько примеров:

  • проверить, чтобы период графика был не выше D1, либо меньше M5;
  • чтобы была нажата кнопка автоторговли;
  • установить настройку буферов индикатора: тип, цвет, толщину линий и т.д.;
  • узнать какой тип счета сейчас: Демо или Реальный и если нужно, ограничить торговлю на реале;
  • подключиться к какому-либо вебсайту и скачать необходимые данные;
  • узнать сколько знаков после запятой у данного счета, выполнить преобразование параметров со старыми пунктами на новые;
  • предварительно удалить лишние графические объекты;
  • сохранить в переменной глобального уровня начальный баланс счета и количество уже открытых ордеров;
  • проверить настройки параметров относительно друг друга, и при необходимости поправить недочеты;
  • отключить часть параметров, если сейчас активирован режим тестирования или оптимизации советника.

Как видно, много чего можно сделать сразу после инициализации кода. К примеру, вам нужно проверить на какой символ установлен индикатор, и если эта пара не входит в ваш перечень, то запретить торговлю. Согласитесь, делать эту проверку каждый тик не целесообразно, это только нагрузит оперативную память компьютера. Функция OnInit же только один раз выполнит нужное действие и станет неактивной.

Тип данных этой функции по умолчанию является int, т.е. целое число. Это значит, что после завершения она должна возвращать (return) какое-то значение. Существует три предопределенных значения, которые эта функция может вернуть:

  • INIT_SUCCEEDED — значение по умолчанию у данной функции. Оно обозначает, что инициализация прошла успешна, работа кода будет продолжена.
  • INIT_FAILED — инициализация завершилась неудачней, дальнейшее продолжение работы невозможно.
  • INIT_PARAMETERS_INCORRECT — нужна для обозначения программистом неверных входных параметров, дальнейшее продолжение работы невозможно.

Если задать функции OnInit тип void, то оператор return прописывать не нужно, по умолчанию инициализация пройдет успешно.

Теперь попробуем на практике запустить эту функцию, запишем несколько принтов в строчку:

Смотрим журнал, все наши 4 сообщения отобразились и после них появилась строка с текстом initialized, которая обозначает, что индикатор запущен в работу.

Теперь попробуем завершить инициализацию неудачей. Для этого введем проверку через условный оператор if, в котором осуществим поиск слова «EURUSD» в наименовании текущей валютной пары. Т.е. если данный индикатор будет установлен на график с парой EURUSD, то ему будет разрешено работать, иначе он снимется с графика. Подставьте этот код в ваш индикатор.

Подобную проверку можно сделать на необходимый таймфрейм, тип счета, на разрешение автоторговли, на номер аккаунта и т.д.

Также стоит заметить, что функцию OnInit можно вызывать вручную через пользовательские функции, если необходимо выполнить повторно инициализацию программного кода.

Функция OnCalculate

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

Тип данных функции является int, вернуть она должна целое число. По умолчанию она возвращает значение rates_total. У функции 10 формальных переменных, все они являются константами, т.е. пользователь не имеет возможности изменить их значения, да этого и не нужно.

  • rates_total — параметр содержит в себе количество баров на графике, которые доступны индикатору для расчета.
  • prev_calculated — равняется значению, которое вернула функция OnCalculate на прошлом тике. Для лучшего понимая можно вывести эти данные в принт.

Т.е. при возврате количества баров rates_total и сравнению этого значения с prev_calculated мы всегда можем знать, когда открылась новая свеча или подгрузились новые свечи и тем самым сможем выполнять действия с пересчетом данных только 1 раз за свечу. prev_calculated всегда будет меньше или равен rates_total. Такой способ используется во всех стандартных индикаторах MT4, например возьмем любой осциллятор. После инициализации индикатор рассчитывает значения для каждой доступной свечи в истории, а уже на следующих тиках расчет идет только для текущего, еще открытого бара и можно видеть, как значение линии индикатора перерисовывается каждый тик, пока свеча не закроется, тогда как остальные линии значений остаются неизменными. Этот метод экономит память программы, не нужно совершать каждый раз лишний пересчет данных на истории.

  • time[] — параметр содержит в себе массив значений времени открытия всех свечей на графике;
  • open[] — массив цены открытия всех свечей на графике;
  • high[] — массив цены High всех свечей на графике;
  • low[] — массив цены Low всех свечей на графике;
  • close[] — массив цены закрытия всех свечей на графике;
  • tick_volume[] — массив содержат историю тикового объема всех свечей на графике. Работает не у всех брокеров;
  • volume[] — массив содержат историю торгового объема всех свечей на графике. Работает не у всех брокеров;
  • spread[] — массив, содержащий историю спреда всех свечей на графике. Я им не пользуюсь, не видел, чтобы он корректно работал.

Направление массивов идет от текущей открытой свечи в сторону самого раннего бара на графике, справа налево. Т.е. если вы хотите узнать значение цены открытия первой закрытой свечи, тогда в квадратных скобках массива нужно указать цифру 1.

Функция OnDeinit

После того, как пользователем подан запрос на завершение работы индикатора, рекомендуется вначале выполнить деинициализацию советника. Функция обработки событий OnDeinit схожа с OnInit, выполняет свое действие один раз при переинициализации или перед удалением программы с графика. Переинициализация может произойти из-за разрыва связи с сервером брокера, смены символа или таймфрейма, изменением входных параметров. Почему-то по умолчанию при создании индикатора она не появляется в коде, но не проблема, мы добавим ее сами.

Тип данных функции void, она не возвращает никакого значения, хотя бы потому, что его некуда возвращать, это последнее действие, которое производит индикатор или советник перед завершением работы. Функция имеет один формальный параметр — константу reason — характеризующий причину деинициализации. Например, когда вы удаляете программу с графика вручную, то можете видеть сообщение: uninit reason 1. Это значит, что причина удаления имеет номер один, что значит «Программа удалена с графика». Посмотрим все причины удаления программы:

REASON_PROGRAM 0 Эксперт прекратил свою работу, вызвав функцию ExpertRemove()
REASON_REMOVE 1 Программа удалена с графика
REASON_RECOMPILE 2 Программа перекомпилирована
REASON_CHARTCHANGE 3 Символ или период графика был изменен
REASON_CHARTCLOSE 4 График закрыт
REASON_PARAMETERS 5 Входные параметры были изменены пользователем
REASON_ACCOUNT 6 Активирован другой счет либо произошло переподключение к торговому серверу вследствие изменения настроек счета
REASON_TEMPLATE 7 Применен другой шаблон графика
REASON_INITFAILED 8 Признак того, что обработчик OnInit() вернул ненулевое значение
REASON_CLOSE 9 Терминал был закрыт

В индикаторах отображаются не все эти причины, этот полный список скорее для Советников, но лишним он точно не будет сейчас. Теперь вы будете замечать и понимать код деинициализации вашего советника или индикатора в журнале «Эксперты». Если будет желание, можете с помощью справки MQL4 написать небольшой код, который бы переводил эти цифры в текст, чтобы более четко видеть причину вызова функции OnDeinit.

Я использую эту функцию в основном, чтобы:

  • очистить график от объектов, которые создал мой программный код (ведь убирать за собой есть одна из обязанностей программиста);
  • чтобы выдать сообщение о том, что работа завершена;
  • подчистить комментарий Comment
  • выдать финальный расчет, будь то количество ордеров, максимальное количество колен у сетки, текущий спред.

Функцию OnDeinit можно также вызвать в любом месте программного кода вручную, только такой метод не удалит индикатор с графика, а только выполнит код, который содержится в ее теле. Для удаления индикатора программно нужно воспользоваться функцией ChartIndicatorDelete, а для удаления советника — функцией ExpertRemove().

Пишем первый индикатор

Это будет очень простой код, который мы усовершенствуем в следующей статье.

Для начала прописываем в функции OnInit какой-либо текст для практики, чтобы увидеть, что она активируется:

Далее в функции OnCalculate мы введем комментарий (ссылка на статью о Comment), который будет отображаться в верхнем левом углу графика и будет выдавать нам значение текущего спреда, обновляя данные каждый тик:

Так как спред рассчитывается в новых пунктах для счетов с 3 или 5 знаками, то мы введем переменную глобального уровня PipsDivided и добавим проверку в функцию OnInit, где PipsDivided будет равняться единице, если счет в старых пунктах и 10, если в новых, чтобы на это значение поделить полученный спред и отображать его по классике с запятой.

Изменяем расчет переменной spr в теле функции OnCalculate и округляем значение до одного знака после запятой через функцию NormalizeDouble:

Чтобы индикатор содержал чуть больше информации, мы введем внешнюю переменную Max_Spread типа double, которые будет нам сигнализировать текстом о том, что спред находится на допустимом уровне (Normal), либо же завышен (Too High) и в рынок сейчас входить не рекомендуется.

Условий оператор if по желанию можно заменить на оператор ? для сокращения количества строчек программного кода:

Так как значение комментария Comment не очищается само собой после удаления индикатора с графика, то мы вручную очистим его в пригодившейся функции обработки событий OnDeinit, оставив в его значении пустые кавычки:

Готовый программный код будет иметь следующий вид:

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

Подписывайтесь на наши уведомления, чтобы не пропустить новые уроки! Во вложении как всегда код .mq4 

0. Начало работы

Скачать примеры

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Заполните поле
Заполните поле
Пожалуйста, введите корректный адрес email.
Вы должны согласиться с условиями для продолжения

Меню