English 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Способы вызова индикаторов в MQL5

Способы вызова индикаторов в MQL5

MetaTrader 5Примеры | 9 марта 2010, 11:11
15 848 9
KlimMalgin
KlimMalgin

Введение

В MQL5 существует несколько вариантов вызова индикаторов, и осуществляются они в основном при помощи функций IndicatorCreate() и iCustom(). Причем эти функции лишь возвращают хендл индикатора, и дальнейшая работа с индикаторами ведется именно через него. Так что же такое хендл? Как работать с функциями IndicatorCreate() и iCustom()? И как получить данные индикатора в вашем эксперте? Обо всем этом рассказывается в данной статье.

Создание исходного файла

Для того чтобы начать работу над экспертом, создадим его исходный файл. Делается это также как и в четвертой версии редактора: вызываем мастера создания экспертов MQL5 через меню Файл -> Создать. На первом шаге из списка выбираем Советник и переходим Далее.


На втором шаге необходимо ввести имя советника, контактные данные автора и входные параметры для будущего советника. Введем только Имя советника (обязательное поле) и Автора. Входные параметры при необходимости можно будет добавить позже, прямо в коде программы.


После нажатия кнопки Готово мастер создаст вот такой исходник:

//+------------------------------------------------------------------+
//|                                                   SampleMQL5.mq5 |
//|                                             Copyright KlimMalgin |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "KlimMalgin"
#property link      ""
#property version   "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+

Структура исходного файла

Кратко рассмотрим структуру исходного файла эксперта и пойдем дальше.

Код программы начинается с заголовка. Это комментарий с названием файла и именем автора. Сразу после заголовка идет область описания свойств(#property) эксперта. Здесь автоматически указывается версия программы, а так же имя автора и ссылка на вашу страницу, если вы их ввели. После описания свойств задаются входные параметры, которых у нас пока нет, и объявляются глобальные переменные.

Хочу заметить, что свойства необходимо задавать в главном mql5-файле. Все свойства, которые будут находиться во включаемых файлах - будут игнорироваться! 

Далее идут три функции обработки событий: 

  • OnInit() - выполняется один раз при запуске эксперта, смене символа или периода на котором установлен эксперт.
  • OnDeinit(const int reason) - так же выполняется один раз, когда эксперт заканчивает работу или происходит переинициализация. Параметр reason содержит код причины деинициализации.
  • OnTick() - запускается каждый раз, при поступлении нового тика на графике, где прикреплен эксперт.

Подключение индикаторов

Методы работы с индикаторами в MQL5 значительно изменились! Если в четвертой версии языка для получения значения индикатора на конкретном баре, функции iCustom передавался в качестве параметра индекс этого бара, то сейчас мы не получаем значение буфера индикатора, а получаем его хендл. И, уже используя этот хендл, можем получить значения индюка на заданном промежутке при помощи специальной функции CopyBuffer(). Итак, что такое хендл?

Хендл - это уникальный идентификатор, созданный для работы с нужным нам индикатором. Представляется в виде целого числа и хранится в переменной типа int. Для получения хендла индикатора в MQL5 существует 2 способа! Вот они:

  • Вызов функции IndicatorCreate(), которая в случае успеха вернет хендл индикатора, а в случае неудачи -1.
  • Вызов одной из функций технических индикаторов. Результат их выполнения аналогичен.

Оба способа равноправны, и какой из них в какой ситуации использовать - решать программисту. Рассмотрим оба способа подробнее.

Получение хендла индикатора с помощью IndicatorCreate()

Итак, в результате успешного выполнения IndicatorCreate() мы получим хендл индикатора, а в случае неудачи функция вернет значение INVALID_HANDLE равное -1. Если вызываемый индикатор имеет параметры, то перед вызовом функции необходимо заполнить массив параметров типа MqlParam. В этом массиве каждый элемент будет представлять собой структуру типа MqlParam, содержащую 4 поля. Первое поле этой структуры указывает на то, какое из оставшихся трех полей использовать в качестве параметра для индикатора.

Напишем код, который будет создавать хендлы индикаторов Moving Average и ParabolicSAR. Начнем с объявления глобальных переменных, в которых будут храниться хендлы, а также объявим массив типа MqlParam для задания параметров индикаторов:

int MA1 = 0,            // Объявляем переменную для хранения хендла быстрой MA
    MA2 = 0,            // Объявляем переменную для хранения хендла медленной MA
    SAR = 0;            // Объявляем переменную для хранения хендла SAR
    
MqlParam params[];      // Массив для хранения параметров индикаторов

Этот код необходимо разместить сразу после определения свойств эксперта.

Теперь, когда переменные объявлены, можно заполнять массив параметров и вызывать IndicatorCreate(). Делать это лучше всего в функции OnInit(), чтобы хендл создавался один раз в начале программы, а не на каждом тике!

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

int OnInit()
{
//---
   // устанавливаем размер params равный количеству параметров
   // вызываемого индикатора
   ArrayResize(params,4);

   // Задаем период быстрой MA
   params[0].type         =TYPE_INT;
   params[0].integer_value=5;
   // Смещение
   params[1].type         =TYPE_INT;
   params[1].integer_value=0;
   // Метод расчета: простое усреднение
   params[2].type         =TYPE_INT;
   params[2].integer_value=MODE_SMA;
   // Тип цен для рассчета: цены закрытия
   params[3].type         =TYPE_INT;
   params[3].integer_value=PRICE_CLOSE;
   
   MA1 = IndicatorCreate(Symbol(), // Символ, используемый для расчета индикатора
                         0,        // Таймфрейм. 0 означает текущий
                         IND_MA,   // Тип индикатора из перечисления ENUM_INDICATOR
                         4,        // Количество параметров, передаваемых в массиве params
                         params    // Массив параметров
                         );   
//---
return(0);
}

Так как массив params был объявлен как динамический, т.е. в скобках не был задан размер массива, то перед его использованием необходимо задать ему нужный размер. При помощи функции ArrayResize() зададим размер, равный количеству параметров, которое мы будем передавать в массиве. Для скользящей средней требуется четыре параметра.

Первый параметр - это период MA. Задается целым числом. Поэтому полю type первого параметра присваиваем значение TYPE_INT, тем самым даем понять функции IndicatorCreate(), что значение параметра нужно будет считать из поля integer_value. Так как все параметры для скользящей средней имеют тип int, то они будут заданы аналогично.

После того, как массив заполнен, можно вызывать функцию IndicatorCreate(). Результат ее выполнения будет сохранен в переменной MA1. С вызовом функции не должно возникнуть никаких затруднений, в нее нужно передать всего пять параметров:

  • Первый - это название рабочего инструмента. Symbol() вернет название текущего инструмента, на котором запущен эксперт.
  • Второй параметр указывает, на каком таймфрейме считать значения индикатора.
  • Третий параметр указывает тип индикатора, который будет вызван.
  • Четвертый параметр указывает количество параметров, которые будут переданы в массиве params.
  • И, наконец, пятый параметр - это массив входных параметров индикатора.

Все, хендл быстрой MA получен, осталось получить хендлы медленной MA и индикатора SAR. В результате функция OnInit() будет выглядеть следующим образом: 

int OnInit()
  {
//---

   // устанавливаем размер params равный количеству параметров
   // вызываемого индикатора
   ArrayResize(params,4);

//*    Вызов индикаторов    *
//***************************
   // Задаем период быстрой MA
   params[0].type         =TYPE_INT;
   params[0].integer_value=5;
   // Смещение
   params[1].type         =TYPE_INT;
   params[1].integer_value=0;
   // Метод расчета: простое усреднение
   params[2].type         =TYPE_INT;
   params[2].integer_value=MODE_SMA;
   // Тип цен для рассчета: цены закрытия
   params[3].type         =TYPE_INT;
   params[3].integer_value=PRICE_CLOSE;
   
   MA1 = IndicatorCreate(Symbol(), 0, IND_MA, 4, params);
   
   // Задаем период медленной MA
   params[0].type         =TYPE_INT;
   params[0].integer_value=21;
   // Смещение
   params[1].type         =TYPE_INT;
   params[1].integer_value=0;
   // Метод расчета: простое усреднение
   params[2].type         =TYPE_INT;
   params[2].integer_value=MODE_SMA;
   // Тип цен для рассчета: цены закрытия
   params[3].type         =TYPE_INT;
   params[3].integer_value=PRICE_CLOSE;
   
   MA2 = IndicatorCreate(Symbol(), 0, IND_MA, 4, params);
   
   
   // Изменяем размер массива для хранения параметров индикатора SAR
   ArrayResize(params,2);
   // Шаг
   params[0].type         =TYPE_DOUBLE;
   params[0].double_value = 0.02;
   // Максимум
   params[1].type         =TYPE_DOUBLE;
   params[1].double_value = 0.2;
   
   SAR = IndicatorCreate(Symbol(), 0, IND_SAR, 2, params);

   
//---
   return(0);
  }

Для получения хендла медленной MA достаточно лишь сменить период с 5 на 21. А при вызове ParabolicSAR в качестве параметров передаются числа с плавающей точкой(double). При заполнении массива это нужно учесть и в поле type поместить TYPE_DOUBLE, а сам параметр, соответственно в поле double_value. Также для SAR требуется лишь два параметра, поэтому размер массива при помощи ArrayResize() изменяется на 2.

На этом работа с IndicatorCreate() заканчивается. На мой взгляд, этот способ вызова индикаторов наиболее удобен при использовании объектно-ориентированного подхода, когда для работы с индикаторами создается библиотека классов, которая в дальнейшем упростит работу с масштабными проектами. А для написания и проверки скорописных экспертов лучше всего использовать следующий способ, который мы сейчас рассмотрим.

Получение хендла при помощи функций технических индикаторов

Второй способ, который позволяет получить хендл индикатора - это вызов одной из функций технических индикаторов. Каждая из этих функций предназначена для получения хендла одного из стандартных индикаторов входящих в комплект вместе с MetaTrader 5. Все они имеют определенный набор параметров, в зависимости от индикатора для которого предназначены. Например, для индикатора CCI вызывается функция iCCI() и выглядит это следующим образом:

   CCI = iCCI(
              Symbol(),            // имя символа
              PERIOD_CURRENT,      // период
              20,                  // период усреднения
              PRICE_CLOSE          // тип цены или handle
              );

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

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

int OnInit()
  {
//---

   MA1 = iCustom(NULL,0,"Examples\\Custom Moving Average",
                          5,          // Период
                          0,          // Смещение
                          MODE_SMA,   // Метод рассчета
                          PRICE_CLOSE // считаем по ценам закрытия
                 );

   MA2 = iCustom(NULL,0,"Examples\\Custom Moving Average",
                          21,         // Период
                          0,          // Смещение
                          MODE_SMA,   // Метод рассчета
                          PRICE_CLOSE // считаем по ценам закрытия
                 );

   SAR = iCustom(NULL,0,"Examples\\ParabolicSAR",
                          0.02,        // Шаг
                          0.2          // Максимум
                 );

//---
   return(0);
  }

Напомню, что хендл лучше всего получить один раз во время запуска эксперта, поэтому выполняем вызов в OnInit(). 

Функция iCustom содержит следующие параметры:

  1. Название рабочего инструмента, на данных которого будет вычисляться индикатор. NULL - означает текущий инструмент. Вместо NULL можно использовать Symbol(), особой разницы нет. Только в случае с Symbol() в iCustom() передается название инструмента, а в случае с NULL, iCustom() определяет финансовый инструмент самостоятельно.
  2. Период графика. Для указания периода можно использовать предопределенные периоды графиков, а так же 0 - для обозначения текущего таймфрейма.
  3. Название индикатора. Вызываемый индикатор должен быть скомпилирован и лежать в директории "MQL5/Indicators/", либо в какой-либо из ее поддиректорий. По умолчанию индикаторы должны лежать в "MQL5/Indicators/Examples/". Оттуда мы и будем их вызывать в нашем случае.
  4. Остальные параметры. Эти значения будут использоваться в качестве входных параметров для вызываемого индикатора, поэтому их тип и порядок следования должны соответствовать. Если они не указаны, то будут использоваться значения указанные по умолчанию.

Как уже было сказано - этот способ удобнее использовать для работы с индикаторами, если у вас под рукой нет библиотеки, с которой вы привыкли работать. Теперь, когда хендлы получены, можно приступить к работе со значениями индикаторов!

Получение данных индикатора

Вся прелесть работы с индикаторными данными в MQL5 в том, что нам предоставляется возможность получить данные только на том интервале, с которым нам нужно работать. Задать интервал можно разными способами:

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

Для считывания данных индикатора, служит функция CopyBuffer(). Каким из указанных способов будут получены данные, зависит от того, какие входные параметры будут переданы этой функции.

Напишем код, копирующий данные индикаторов, хендлы которых мы получили ранее, в массивы:

void OnTick()
  {
//---

// Динамические массивы для хранения значений индикаторов
double _ma1[],
       _ma2[],
       _sar[];

// Устанавливаем индексацию в массивах такую же, как в таймсериях, т.е. элемент массива с нулевым
// индексом будет хранить значения последнего бара, с первым - предпоследнего и т.д.
   ArraySetAsSeries(_ma1, true);
   ArraySetAsSeries(_ma2, true);
   ArraySetAsSeries(_sar, true);

// Используя хендлы индикаторов, копируем значения индикаторных 
// буферов в специально подготовленные для этого массивы
   if (CopyBuffer(MA1,0,0,20,_ma1) < 0){Print("CopyBufferMA1 error =",GetLastError());}
   if (CopyBuffer(MA2,0,0,20,_ma2) < 0){Print("CopyBufferMA2 error =",GetLastError());}
   if (CopyBuffer(SAR,0,0,20,_sar) < 0){Print("CopyBufferSAR error =",GetLastError());}


//---
  }

Теперь вся работа будет происходить в функции OnTick(), т.к. на каждом тике данные индикаторов изменяются и их нужно обновлять.

Для начала объявим динамические массивы для каждого буфера индикаторов. Работать с индикаторными данными, на мой взгляд, будет удобнее, если индексация массивов будет такой же, как в таймсериях, т.е. в элементе массива под номером 0 будут данные последнего бара, под номером 1 - предпоследнего и т.д. Для того чтобы установить способ индексации, используется функция ArraySetAsSeries()

Установили способ индексации, теперь можно приступать к заполнению массивов. Для расчета каждого индикатора вызовем CopyBuffer() со следующим набором параметров:

  1. Хендл индикатора, данные которого нужно получить;
  2. Номер индикаторного буфера. В индикаторах MA и SAR по одному буферу, поэтому указываем их как нулевые. Если буферов больше одного, то для второго будет номер 1, для третьего номер 2 и т.д.
  3. Начальный бар, с которого начинаем отсчет.
  4. Количество баров, которое нужно скопировать.
  5. Массив, в который копируются данные.

При успешном вызове функция CopyBuffer() вернет количество скопированных элементов, при неудачном -1. В случае неудачи ошибку необходимо отследить, поэтому, если возвращаемое значение меньше 0 - запишем ошибку в журнал экспертов, при помощи функции Print().

Заключение

На этом работа с индикаторами не заканчивается. В статье рассмотрены лишь базовые методы доступа к их данным. А для удобства работы лучше всего использовать объектно-ориентированный подход, который в MQL5 реализован на довольно хорошем уровне!

Прикрепленные файлы |
samplemql5.mq5 (5.15 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (9)
Andrew Petras
Andrew Petras | 27 июл. 2011 в 12:34

Значит, разные обеды могут быть только на подносе официанта. Ладно, поэкспериментирую.

А массивы смешанных типов не планируются, типа [int][double]?

Rashid Umarov
Rashid Umarov | 27 июл. 2011 в 12:38
Silent:

Значит, разные обеды могут быть только на подносе официанта. Ладно, поэкспериментирую.

А массивы смешанных типов не планируются, типа [int][double]?

Используйте структуры, смотрите пример в справке  - https://www.mql5.com/ru/docs/basis/types/casting#casting_structure:

Еще один пример показывает, как можно организовать собственную функцию для получения из типа color представления цвета в RGB (Red,Green,Blue). Для этого создаем две структуры, имеющие одинаковый размер, но разный внутренний состав. Для удобства, добавим в структуру функцию, возвращающую цвет в представлении RGB в виде строки.

#property script_show_inputs
input color          testColor=clrBlue;// задайте цвет для тестирования
//--- структура для представления цвета в RGB
struct RGB
  {
   uchar             blue;          // синяя составляющая цвета
   uchar             green;         // зеленая составляющая цвета
   uchar             red;           // красная составляющая цвета
   uchar             empty;         // этот байт не используется
   string            toString();    // функция для получения в виде строки
  };
//--- функция для вывода цвета в виде строки
string RGB::toString(void)
  {
   string out="("+(string)red+":"+(string)green+":"+(string)blue+")";
   return out;
  }
//--- структура для хранения встроенного типа color 
struct builtColor
  {
   color             c;
  };
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- переменная для хранения в RGB
   RGB colorRGB;
//--- переменная для хранения типа color
   builtColor test;
   test.c=testColor;
//--- приведение двух структур путем копирования содержимого
   colorRGB=test;
   Print("color ",test.c," = ",colorRGB.toString());
//---
  }

Andrew Petras
Andrew Petras | 27 июл. 2011 в 12:47
Rosh:

Используйте структуры, смотрите пример в справке  - https://www.mql5.com/ru/docs/basis/types/casting#casting_structure:

Со структурами боле-мене понятно, меня массивы интересуют.

Спасибо.

Rashid Umarov
Rashid Umarov | 27 июл. 2011 в 12:59
Silent:

Со структурами боле-мене понятно, меня массивы интересуют.

Спасибо.

Сделайте структуру  и наберите массив этого типа.
Alex Renko
Alex Renko | 23 июл. 2023 в 22:00
мда...проще свой индикатор придумать и в код робота вшить чемэти хендлы кодить каждый раз... жесть 
MQL5, обработка событий: Изменяем период мувинга "на лету" MQL5, обработка событий: Изменяем период мувинга "на лету"
Предположим, что на чарт наброшен индикатор простого мувинга с периодом 13. А мы хотим изменить период до 20, но нам не хочется лезть в диалог свойств индикатора и править число 13 на 20: надоело уже пальцы стирать об мышку и клавиатуру. И уж тем более не хочется открывать код индикатора и модифицировать его. Мы хотим сделать все это однократным нажатием одной клавиши - "стрелочки вверх", расположенной рядом с цифровой клавиатурой. В этой публикации мы расскажем, как это сделать.
MQL5 для "чайников": Получение значений технических индикаторов в своих экспертах MQL5 для "чайников": Получение значений технических индикаторов в своих экспертах
Для получения в торговом советнике значений встроенного или пользовательского индикатора, необходимо предварительно создать его хендл с помощью соответствующей функции. На примерах показано, как воспользоваться тем или иным техническим индикатором при разработке своих программ. Речь идёт о индикаторах, которые непосредственно встроены в язык MQL5. Статья предназначена для начинающих разработчиков торговых стратегий и предлагает простые и ясные способы работы с индикаторами с использованием приложенной библиотеки функций.
Знакомство с MQL5: написание простого советника и индикатора Знакомство с MQL5: написание простого советника и индикатора
В этой статье проведен краткий обзор языка MQL5, приведен пример написания советника и индикатора. Данная статья ориентирована как на читателей, знакомых с программированием на языке MQL4, так и на тех, кто только начинает знакомство с программированием торговых систем и индикаторов.
Пользовательские индикаторы в MQL5 для начинающих Пользовательские индикаторы в MQL5 для начинающих
Любой новый предмет для новичка с первого взгляда кажется сложным для понимания. Нам кажется простым и ясным то, что мы уже знаем. Но мы просто не помним, что всем нам когда-то приходилось изучать с нуля, даже родной язык, на котором мы разговариваем. Так и язык MQL5, таящий в себе огромные возможности для написания торговых стратегий, можно начать изучать с базовых понятий и примеров. В этой статье на примере пользовательского индикатора SMA рассматривается взаимодействие технического индикатора с клиентским терминалом MetaTrader 5.