English 中文 Español Deutsch 日本語 Português
preview
Разработка пользовательского индикатора Heiken Ashi с помощью MQL5

Разработка пользовательского индикатора Heiken Ashi с помощью MQL5

MetaTrader 5Трейдинг | 29 сентября 2023, 13:47
936 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

Введение

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

В этой статье мы используем функцию iCustom и создадим пользовательский индикатор в соответствии с вашими условиями и на основе ваших предпочтений. Мы также создадим пользовательский технический индикатор Heiken Ashi и будем использовать его в торговых системах. Рассмотрены следующие темы:

Материал статьи можно использовать как образец для создания собственных пользовательских индикаторов. Мы будем использовать язык MQL5 (MetaQuotes Language), встроенный в торговую платформу MetaTrader 5, для написания кодов создаваемых индикаторов и советников. Если вы не знаете, как их скачать и использовать, почитайте раздел "Как написать MQL5-код в редакторе MetaEditor" в одной из предыдущих статьей.

Внимание! Все содержание настоящей статьи предоставляется "как есть", предназначено только для целей обучения и не является торговой рекомендацией. Статья не несет в себе каких-либо гарантий результатов. Все, что вы применяете на практике на основе этой статьи, вы делаете исключительно на свой страх и риск, автор не гарантирует никаких результатов.

Пользовательский индикатор и определение Heiken Ashi

Как я упоминал во введении в предыдущем разделе, пользовательский индикатор — это инструмент технического анализа, который может быть создан пользователем с помощью языка программирования MQL5. Его можно использовать в MetaTrader 5 для анализа и понимания движения рынка, а также помощи в принятии обоснованных инвестиционных решений. Существует много полезных встроенных технических индикаторов, но иногда нам необходимо проанализировать и понять, как действует рынок, основываясь на некоторых дополнительных математических, статистических или технических идеях, которые не охвачены существующими индикаторами. В таких случаях нам приходится создать такой индикатор самостоятельно — и это одна из особенностей платформы MetaTrader 5, поскольку она помогает нам создавать собственные аналитические или торговые инструменты, отвечающие нашим конкретным предпочтениям и целям.

Рассмотрим необходимые шаги для создания собственного индикатора:

Откройте MetaEditor и выберите папку Indicators в Навигаторе.

Папка Indicators

Нажмите кнопку "Создать" для создания новой программы, как показано на рисунке ниже

Новая кнопка

После этого откроется окно, в котором вам следует выбрать тип создаваемой программы. Выбираем "Пользовательский индикатор"

Выбор типа программы

После нажатия кнопки "Далее" откроется следующее окно с информацией об индикаторе. Укажите здесь имя пользовательского индикатора и нажмите "Далее".

Информация об индикаторе

В следующих окнах указываем более подробную информацию об индикаторе.

Информация об индикаторе 2

Информация об индикаторе 3

После завершения всех настроек и нажатия на кнопку "Готово", откроется окно редактора.

Мы рассмотрим, как разработать собственный индикатор на примере Heiken Ashi. Соответственно, нам нужно больше узнать о нем. Это метод построения графиков свечного типа, который можно использовать для представления и анализа движения рынка. Его можно использовать в сочетании с другими инструментами для получения подробной информации, на основе которой мы можем принимать обоснованные торговые решения.

Графики Heiken Ashi похожи на обычные свечные графики, но методы расчета свечей отличаются. Как мы знаем, обычный график свечей рассчитывает цены на основе фактических цен открытия, максимума, минимума и закрытия за определенный период, но Heiken Ashi учитывает цены предыдущих аналогичных цен (открытия, максимума, минимума и закрытия при расчете своих свечей.

Вот как рассчитываются значения Heiken Ashi:

  • Open = (открытие предыдущей свечи + закрытие предыдущей свечи) / 2
  • Close = (открытие + закрытие + максимум + минимум текущей свечи) / 4
  • High = самое высокое значение от максимума, открытия или закрытия текущего периода
  • Low = самое низкое значение от минимума, открытия или закрытия текущего периода

На основе расчета индикатор строит бычьи и медвежьи свечи, цвета этих свечей указывают на соответствующее направление рынка: бычье или медвежье. Для сравнения ниже приведены традиционные японские свечи и Heiken Ashi.

 Heiken Ashi

В верхней части показаны традиционные свечи, а в нижней — индикатор Heiken Ashi, который отображается в виде синих и красных свечей, которые определяют направление рынка. Цель индикатора — фильтровать и устранять часть шума в движении рынка путем сглаживания данных, чтобы избежать ложных сигналов.


Простой индикатор Heiken Ashi

Создадим простой индикатор Heiken Ashi для использования в MetaTrader 5. Индикатор должен постоянно проверять цены (открытие, максимум, минимум и закрытие) и выполнять вычисления для генерации значений haOpen, haHigh, haLow и haClose. На основе расчетов индикатор должен отображать значения на графике в виде свечей разного цвета: синего при бычьем движении и красного - при медвежьем. Свечи должны отображаться в отдельном окне под традиционным графиком в качестве подокна.

Рассмотрим все шаги, которые нам необходимо выполнить для создания этого пользовательского индикатора.

Определим настройки индикатора путем указания дополнительных параметров через значения #property и идентификатора:

  • (indicator_separate_window) - показывать индикатор в отдельном окне.
  • (indicator_buffers) - количество буферов расчета индикатора.
  • (indicator_plots) - количество графических серий в индикаторе. Графические серии — это стили рисования, которые можно использовать при создании пользовательского индикатора.
  • (indicator_typeN) - тип графического построения в соответствии со значениями (ENUM_DRAW_TYPE). N - количество графических серий, которое мы определили в последнем параметре. Начинается с 1.
  • (indicator_colorN) - цвет N. N - это также количество графических серий, которое мы определили ранее. Начинается с 1.
  • (indicator_widthN) - толщина N, или графической серии.
  • (indicator_labelN) - установить метку N определенной графической серии.
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrBlue, clrRed
#property indicator_width1  2
#property indicator_label1  "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"

Создадим пять массивов для пяти буферов индикатора (haOpen, haHigh, haLow, haClose, haColor) типа double.

double haOpen[];
double haHigh[];
double haLow[];
double haClose[];
double haColor[];

Внутри OnInit() эта функция используется для инициализации работающего индикатора.

int OnInit()

Отсортируем индикаторные буферы с помощью одномерного динамического массива типа double с помощью функции (SetIndexBuffer). Параметры такие:

  • index - номер индикаторного буфера, начиная с 0. Число должно быть меньше значения, объявленного в параметре (indicator_buffers).
  • buffer[] - массив, объявленный в пользовательском индикаторе.
  • data_type - тип данных, который нам нужно сохранить в массиве индикаторов.
   SetIndexBuffer(0,haOpen,INDICATOR_DATA);
   SetIndexBuffer(1,haHigh,INDICATOR_DATA);
   SetIndexBuffer(2,haLow,INDICATOR_DATA);
   SetIndexBuffer(3,haClose,INDICATOR_DATA);
   SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);

Установим значение соответствующего свойства индикатора с помощью функции (IndicatorSetInteger) с вариантом вызова, в котором мы указываем идентификатор свойства. Параметры такие:

  • prop_id - идентификатор свойства, который может быть одним из (ENUM_CUSTOMIND_PROPERTY_INTEGER). Укажем (INDICATOR_DIGITS).
  • prop_value - значение свойства. Укажем (_Digits).
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);

Установим значение соответствующего свойства строкового типа с вариантом вызова, в котором мы также указываем идентификатор свойства. Параметры такие:

  • prop_id - идентификатор свойства, который может быть одним из (ENUM_CUSTOMIND_PROPERTY_STRING). Укажем (INDICATOR_SHORTNAME), чтобы использовать короткое имя для индикатора.
  • prop_value - значение свойства. Укажем ("Simple Heiken Ashi").
   IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");

Установим значение соответствующего свойства типа double соответствующего индикатора с помощью функции (PlotIndexSetDouble). Параметры следующие:

  • plot_index - индекс графического построения. Укажем 0.
  • prop_id - одно из значений (ENUM_PLOT_PROPERTY_DOUBLE). (PLOT_EMPTY_VALUE) - без отображения.
  • prop_value - значение свойства.
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);

Затем вернем (INIT_SUCCEEDED) как часть функции OnInit(), чтобы завершить ее, вернув успешную инициализацию.

   return(INIT_SUCCEEDED);

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

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])

Создадим целочисленную переменную start. Значение будет присвоено ей позже:

int start;

Используем оператор if для возврата значений индексов (низкий, высокий, открытый и закрытый) и start=1, если prev_calculated равен 0, или возврата начального значения, присвоенного (prev_calculated-1):

   if(prev_calculated==0)
     {
      haLow[0]=low[0];
      haHigh[0]=high[0];
      haOpen[0]=open[0];
      haClose[0]=close[0];
      start=1;
     }
   else
      start=prev_calculated-1;

Функция for используется в основном цикле вычислений. Оператор for состоит из трех выражений и исполняемых операторов.

Три выражения:

  • i=start - стартовая позиция.
  • i<rates_total && !IsStopped() - условия завершения цикла. IsStopped() проверяет принудительную остановку индикатора.
  • i++ - добавить 1, чтобы получить новый i.

Операции, которые нам нужно выполнять каждый раз во время цикла:

Расчет для четырех переменных типа double

  • haOpenVal - значение открытия Heiken Ashi.
  • haCloseVal - значение закрытия Heiken Ashi.
  • haHighVal - максимум Heiken Ashi.
  • haLowVal - минимум Heiken Ashi.

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

  • haLow[i]=haLowVal
  • haHigh[i]=haHighVal
  • haOpen[i]=haOpenVal
  • haClose[i]=haCloseVal

Проверяем, ниже ли значение открытия Heiken Ashi, чем значение закрытия. Если да, индикатор должен рисовать свечу синего цвета, а если нет - красного.

   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
      double haCloseVal=(open[i]+high[i]+low[i]+close[i])/4;
      double haHighVal =MathMax(high[i],MathMax(haOpenVal,haCloseVal));
      double haLowVal  =MathMin(low[i],MathMin(haOpenVal,haCloseVal));

      haLow[i]=haLowVal;
      haHigh[i]=haHighVal;
      haOpen[i]=haOpenVal;
      haClose[i]=haCloseVal;

      //--- set candle color
      if(haOpenVal<haCloseVal)
         haColor[i]=0.0;
      else
         haColor[i]=1.0;
     }

Завершим функцию, вернув (rates_total) как prev_calculated для следующего вызова.

return(rates_total);

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

//+------------------------------------------------------------------+
//|                                             simpleHeikenAshi.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrBlue, clrRed
#property indicator_width1  2
#property indicator_label1  "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"
double haOpen[];
double haHigh[];
double haLow[];
double haClose[];
double haColor[];
int OnInit()
  {
   SetIndexBuffer(0,haOpen,INDICATOR_DATA);
   SetIndexBuffer(1,haHigh,INDICATOR_DATA);
   SetIndexBuffer(2,haLow,INDICATOR_DATA);
   SetIndexBuffer(3,haClose,INDICATOR_DATA);
   SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
   IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
   return(INIT_SUCCEEDED);
  }
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   int start;
   if(prev_calculated==0)
     {
      haLow[0]=low[0];
      haHigh[0]=high[0];
      haOpen[0]=open[0];
      haClose[0]=close[0];
      start=1;
     }
   else
      start=prev_calculated-1;
   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
      double haCloseVal=(open[i]+high[i]+low[i]+close[i])/4;
      double haHighVal =MathMax(high[i],MathMax(haOpenVal,haCloseVal));
      double haLowVal  =MathMin(low[i],MathMin(haOpenVal,haCloseVal));

      haLow[i]=haLowVal;
      haHigh[i]=haHighVal;
      haOpen[i]=haOpenVal;
      haClose[i]=haCloseVal;
      if(haOpenVal<haCloseVal)
         haColor[i]=0.0;
      else
         haColor[i]=1.0;
     }
   return(rates_total);
  }

После успешной компиляции индикатор становится доступным в папке "Индикаторы" в окне "Навигатор", как показано ниже.

simpleHA nav

Запустим его. Откроется стандартное окно настроек:

 simpleHA win

На вкладке "Цвета" показаны настройки по умолчанию: синий цвет для восходящего движения, красный - для нисходящего. Значения можно изменить.

 simpleHA win2

После нажатия ОК индикатор прикрепляется к графику и выглядит так:

simpleHA запущен

Как видим, индикатор работает в отдельном подокне. Синие и красные свечи указывают направление цены (бычье и медвежье). Теперь у нас есть собственный индикатор, который мы создали в MetaTrader 5. Мы можем использовать его в любой торговой системе. Именно этим мы сейчас и займемся.


Советник на основе пользовательского индикатора Heiken Ashi

В этом разделе мы научимся использовать пользовательские индикаторы в советнике. Мы создадим простую систему Heiken Ashi, которая сможет показывать нам цены индикатора (открытие, максимум, минимум и закрытие), поскольку мы уже знаем, что они отличаются от фактических цен согласно расчету индикатора.

Создадим советник. Полный код:

//+------------------------------------------------------------------+
//|                                             heikenAshiSystem.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
int heikenAshi;
int OnInit()
  {
   heikenAshi=iCustom(_Symbol,_Period,"My Files\\Heiken Ashi\\simpleHeikenAshi");
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("Heiken Ashi System Removed");
  }
void OnTick()
  {
   double heikenAshiOpen[], heikenAshiHigh[], heikenAshiLow[], heikenAshiClose[];
   CopyBuffer(heikenAshi,0,0,1,heikenAshiOpen);
   CopyBuffer(heikenAshi,1,0,1,heikenAshiHigh);
   CopyBuffer(heikenAshi,2,0,1,heikenAshiLow);
   CopyBuffer(heikenAshi,3,0,1,heikenAshiClose);
   Comment("heikenAshiOpen ",DoubleToString(heikenAshiOpen[0],_Digits),
           "\n heikenAshiHigh ",DoubleToString(heikenAshiHigh[0],_Digits),
           "\n heikenAshiLow ",DoubleToString(heikenAshiLow[0],_Digits),
           "\n heikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
  }

Отличия в этом коде:

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

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

За пределами предыдущих функций и перед ними мы создали целочисленную переменную (heikenAshi)

int heikenAshi;

Внутри области действия OnInit() мы присвоили значение функции iCustom переменной heikenAshi. Функция iCustom возвращает хэндл пользовательского индикатора, которым здесь будет Simple Heiken Ashi, но вы можете использовать любой пользовательский индикатор в папке "Индикаторы". Параметры:

  • symbol - имя символа, мы использовали (_Symbol) для текущего символа.
  • period - таймфрейм, мы использовали (_Period) для текущего таймфрейма.
  • name - имя пользовательского индикатора с указанием пути к нему в папке "Индикаторы". Здесь мы использовали My Files\\Heiken Ashi\\simpleHeikenAshi.

Затем мы завершили функцию, вернув (INIT_SUCCEEDED) для успешной инициализации.

int OnInit()
  {
   heikenAshi=iCustom(_Symbol,_Period,"My Files\\Heiken Ashi\\simpleHeikenAshi");
   return(INIT_SUCCEEDED);
  }

Внутри функции OnDeinit() мы использовали функцию print, чтобы сообщить, что советник удален.

void OnDeinit(const int reason)
  {
   Print("Heiken Ashi System Removed");
  }

Внутри функции OnTick() для завершения нашего кода мы сделали следующее:

Создали четыре переменные двойного типа для цен Heiken Ashi (Open, High, Low и Close).

   double heikenAshiOpen[], heikenAshiHigh[], heikenAshiLow[], heikenAshiClose[];

Получили данные буферов пользовательского индикатора с помощью функции CopyBuffer. Параметры:

  • indicator_handle - хэндл индикатора, мы использовали (heikenAshi).
  • buffer_num - номер индикаторного буфера, мы использовали (0 для открытия, 1 для максимума, 2 для минимума и 3 для закрытия).
  • start_pos - первая позиция копируемого элемента, мы использовали 0 для текущего элемента.
  • count - объем данных для копирования, мы использовали 1. Здесь этого достаточно.
  • buffer[] - использованный массив для копирования. Мы использовали (heikenAshiOpen для открытия, heikenAshiHigh для максимума, heikenAshiLow для минимума и heikenAshiClose для закрытия).

Получили комментарий к графику с текущими ценами Heiken Ashi (Open, High, Low и Close) с помощью функции comment:

   Comment("heikenAshiOpen ",DoubleToString(heikenAshiOpen[0],_Digits),
           "\n heikenAshiHigh ",DoubleToString(heikenAshiHigh[0],_Digits),
           "\n heikenAshiLow ",DoubleToString(heikenAshiLow[0],_Digits),
           "\n heikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));

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

 haSystem

Как видим, цены индикатора отображаются в виде комментария в верхнем левом углу графика.


Heiken Ashi - Система EMA

В этой разделе мы добавим еще один технический инструмент, чтобы посмотреть, будет ли результат лучше или нет. Идея заключается в фильтрации сигналов пользовательского индикатора с использованием экспоненциальной скользящей средней с ценами. Есть много способов сделать это: мы можем создать еще один пользовательский индикатор для EMA, если мы хотим добавить к EMA больше функций. Тогда мы можем использовать его в советнике как iCustom так же, как мы это делали для получения желаемых сигналов. Мы также можем создать сглаженный индикатор, сгладив значения индикатора и затем использовав наши сигналы. Мы можем использовать встроенную функцию iMA в нашем советнике, чтобы получать от него сигналы. Будем использовать этот метод здесь для простоты.

Нам нужно позволить советнику постоянно проверять значения текущих двух EMA (быстрой и медленной), предыдущей быстрой EMA и цены закрытия Heiken Ash, чтобы определить позиции каждого значения. Если предыдущее значение heikenAshiClose больше предыдущего массива fastEMA, а текущее значение fastEMA больше текущего значения SlowEMA, советник должен вернуть сигнал на покупку и эти значения должны отобразиться на графике. Если предыдущий heikenAshiClose ниже предыдущего массива fastEMA, а текущая fastEMA ниже текущего значения SlowEMA, советник должен вернуть сигнал продажи и эти значения должны отобразиться на графике.

Полный код для создания советника:

//+------------------------------------------------------------------+
//|                                          heikenAsh-EMASystem.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
input int fastEMASmoothing=9; // Fast EMA Period
input int slowEMASmoothing=18; // Slow EMA Period
int heikenAshi;
double fastEMAarray[], slowEMAarray[];
int OnInit()
  {
   heikenAshi=iCustom(_Symbol,_Period,"My Files\\Heiken Ashi\\simpleHeikenAshi");
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("Heiken Ashi-EMA System Removed");
  }
void OnTick()
  {
   double heikenAshiOpen[], heikenAshiHigh[], heikenAshiLow[], heikenAshiClose[];
   CopyBuffer(heikenAshi,0,0,3,heikenAshiOpen);
   CopyBuffer(heikenAshi,1,0,3,heikenAshiHigh);
   CopyBuffer(heikenAshi,2,0,3,heikenAshiLow);
   CopyBuffer(heikenAshi,3,0,3,heikenAshiClose);
   int fastEMA = iMA(_Symbol,_Period,fastEMASmoothing,0,MODE_SMA,PRICE_CLOSE);
   int slowEMA = iMA(_Symbol,_Period,slowEMASmoothing,0,MODE_SMA,PRICE_CLOSE);
   ArraySetAsSeries(fastEMAarray,true);
   ArraySetAsSeries(slowEMAarray,true);
   CopyBuffer(fastEMA,0,0,3,fastEMAarray);
   CopyBuffer(slowEMA,0,0,3,slowEMAarray);
   if(heikenAshiClose[1]>fastEMAarray[1])
     {
      if(fastEMAarray[0]>slowEMAarray[0])
        {
         Comment("Buy Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nprevHeikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }
     }
   if(heikenAshiClose[1]<fastEMAarray[1])
     {
      if(fastEMAarray[0]<slowEMAarray[0])
        {
         Comment("Sell Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nheikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }
     }
  }

Что изменилось в коде по сравнению с предыдущим:

Создадим пользовательские входные данные для установки периода быстрой EMA и периода медленной EMA в соответствии с предпочтениями пользователя.

input int fastEMASmoothing=9; // Fast EMA Period
input int slowEMASmoothing=18; // Slow EMA Period

Создадим два массива для fastEMA и slowEMA.

double fastEMAarray[], slowEMAarray[];

Установим количества данных для копирования на 3 в CopyBuffer, чтобы получить предыдущие значения закрытия индикатора Heiken Ashi.

   CopyBuffer(heikenAshi,0,0,3,heikenAshiOpen);
   CopyBuffer(heikenAshi,1,0,3,heikenAshiHigh);
   CopyBuffer(heikenAshi,2,0,3,heikenAshiLow);
   CopyBuffer(heikenAshi,3,0,3,heikenAshiClose);

Определим быструю и медленную EMA с помощью встроенной функции iMA, которая возвращает хэндл индикатора скользящей средней. Параметры:

  • symbol - имя символа, мы использовали (_Symbol) для текущего символа.
  • period - время, мы использовали (_Period) для текущего времени.
  • ma_period - период для сглаживания среднего значения, мы использовали (fastEMASmoothing и slowEMASmoothing).
  • ma_shift - сдвиг индикатора, мы использовали 0.
  • ma_method - тип скользящей средней, мы использовали MODE_SMA для простой скользящей средней.
  • applied_price - необходимый тип цены для расчетов, мы использовали PRICE_CLOSE.
   int fastEMA = iMA(_Symbol,_Period,fastEMASmoothing,0,MODE_SMA,PRICE_CLOSE);
   int slowEMA = iMA(_Symbol,_Period,slowEMASmoothing,0,MODE_SMA,PRICE_CLOSE);

Используем функцию ArraySetAsSeries для установки флага AS_SERIES. Параметры:

  • array[] - массив, мы использовали (fastEMAarray и slowEMA).
  • flag - направление индексации массива, мы использовали true.
   ArraySetAsSeries(fastEMAarray,true);
   ArraySetAsSeries(slowEMAarray,true);

Получим данные буфера индикатора EMA с помощью функции CopyBuffer.

   CopyBuffer(fastEMA,0,0,3,fastEMAarray);
   CopyBuffer(slowEMA,0,0,3,slowEMAarray);

Условия возврата сигналов с помощью оператора if:

В случае сигнала на покупку

Если предыдущий heikenAshiClose > предыдущий массив fastEMA и текущий массив fastEMA > текущий массив slowEMA, советник должен вернуть сигнал на покупку и следующие значения:

  • fastEMA
  • slowEMA
  • prevFastEMA
  • prevHeikenAshiClose
   if(heikenAshiClose[1]>fastEMAarray[1])
     {
      if(fastEMAarray[0]>slowEMAarray[0])
        {
         Comment("Buy Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nprevHeikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }

В случае сигнала на продажу

Если предыдущий heikenAshiClose < предыдущий массив fastEMA и текущий массив fastEMA < текущий массив slowEMA, советник должен вернуть сигнал на продажу и значения цены:

  • fastEMA
  • slowEMA
  • prevFastEMA
  • prevHeikenAshiClose
   if(heikenAshiClose[1]<fastEMAarray[1])
     {
      if(fastEMAarray[0]<slowEMAarray[0])
        {
         Comment("Sell Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nheikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }
     }

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

В случае сигнала на покупку:

HA с 2EMA - сигнал на покупку

Как мы видим на предыдущем графике, в верхнем левом углу в качестве комментария мы имеем следующий сигнал:

  • Сигнал на покупку
  • fastEMA
  • prevFastEMA
  • prevHeikenAshiClose

В случае сигнала на продажу:

HA с 2EMA - сигнал на продажу

В качестве сигнала на графике мы имеем следующие значения:

  • Сигнал на продажу
  • fastEMA
  • prevFastEMA
  • prevHeikenAshiClose

Заключение

Если вы поняли все, что мы обсуждали в этой статье, вы можете создать свой собственный индикатор Heiken Ashi или даже добавить некоторые дополнительные функции в соответствии с вашими предпочтениями. Это упростит чтение графиков и принятие эффективных решений. Кроме того, вы сможете использовать созданный индикатор в своих торговых системах в составе советников, поскольку мы упоминали и использовали его в двух торговых системах в качестве примеров.

  • Система Heiken Ashi
  • Система Heiken Ashi-EMA

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

В моем профиле можно найти ссылки на другие мои статьи. Надеюсь, они тоже принесут вам пользу.

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/12510

Прикрепленные файлы |
Популяционные алгоритмы оптимизации: Алгоритм эволюции разума (Mind Evolutionary Computation, MEC) Популяционные алгоритмы оптимизации: Алгоритм эволюции разума (Mind Evolutionary Computation, MEC)
В данной статье рассматривается алгоритм семейства MEC, называемый простым алгоритмом эволюции разума (Simple MEC, SMEC). Алгоритм отличается красотой заложенной идеи и простотой реализации.
Разработка системы репликации - Моделирование рынка (Часть 14): Появление СИМУЛЯТОРА (IV) Разработка системы репликации - Моделирование рынка (Часть 14): Появление СИМУЛЯТОРА (IV)
В этой статье мы продолжим этап разработки симулятора. Однако сейчас мы увидим, как эффективно создать движение типа «СЛУЧАЙНОЕ БЛУЖДАНИЕ». Этот тип движения весьма интригующий, поскольку служит основой всего, что происходит на рынке капитала. Кроме того, мы начнем понимать некоторые концепции, основополагающие для тех, кто проводит анализ рынка.
Разработка системы репликации - Моделирование рынка (Часть 15): Появление СИМУЛЯТОРА (V) - СЛУЧАЙНОЕ БЛУЖДАНИЕ Разработка системы репликации - Моделирование рынка (Часть 15): Появление СИМУЛЯТОРА (V) - СЛУЧАЙНОЕ БЛУЖДАНИЕ
В этой статье мы завершим разработку симулятора для нашей системы. Основной целью здесь будет настройка алгоритма, рассмотренного в предыдущей статье. Этот алгоритм направлен на создание движения СЛУЧАЙНОГО БЛУЖДАНИЯ. Поэтому, для понимания сегодняшнего материала, необходимо понять содержание предыдущих статей. Если вы не следили за развитием симулятора, советую посмотреть эту последовательность с самого начала. В противном случае вы можете запутаться в том, что будет здесь объяснено.
Готовые шаблоны для подключения индикаторов в экспертах (Часть 3): Трендовые индикаторы Готовые шаблоны для подключения индикаторов в экспертах (Часть 3): Трендовые индикаторы
В этой справочной статье рассмотрим стандартные индикаторы из категории "Трендовые индикаторы". Создадим готовые к применению шаблоны использования этих индикаторов в советниках — объявление и установка параметров, инициализация и деинициализация индикаторов и получение данных и сигналов из индикаторных буферов в советниках.