English 中文 Deutsch 日本語
preview
Знакомство с языком MQL5 (Часть 13): Руководство для начинающих по созданию пользовательских индикаторов (II)

Знакомство с языком MQL5 (Часть 13): Руководство для начинающих по созданию пользовательских индикаторов (II)

MetaTrader 5Эксперты |
357 2
Israel Pelumi Abioye
Israel Pelumi Abioye

Введение

И еще раз добро пожаловать в нашу серию статей по языку MQL5! В Части 12 этой серии мы исследовали основы создания пользовательских индикаторов на языке MQL5. Мы создали индикатор Moving Average (скользящая средняя) с нуля, реализовав его логику вручную, вместо того чтобы полагаться на встроенные функции. Затем мы расширили эти знания, преобразовав их в Moving Average в формате свечи, продемонстрировав, как манипулировать графическими элементами в индикаторе.

Основываясь на этом фундаменте, эта статья представит более интересные концепции в разработке индикаторов. Мы, как обычно, будем использовать проектный подход, чтобы убедиться, что вы понимаете темы, применяя их на практике. Основными целями будут создание индикатора Heikin Ashi и расчет Moving Average на основе его данных. После того как эти индикаторы будут созданы, мы разработаем советник, который будет задействовать индикаторы Heikin Ashi и Moving Average. Даже новички в работе с языком MQL5 могут ознакомиться с материалом, потому что эта статья – для начинающих. Чтобы пояснить вам не только то, как работает реализация, но и почему необходим каждый из предложенных шагов, каждая строка кода будет подробно объяснена.

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

Heikin Ashi (HA) и HA Moving Average

Figure 1. Heikin Ashi and MA indicator

В этой статье вы узнаете:

  • Как создать пользовательский индикатор Heikin Ashi с нуля на языке MQL5.
  • Использование данных со свечей Heikin Ashi для расчета Heikin Ashi Moving Average.
  • Использование функции iCustom() для доступа к нестандартным индикаторам и интеграции их данных в торговые стратегии.
  • Определение условий входа с использованием индикатора Heikin Ashi и его пересечений с MA.
  • Эффективное управление рисками путем динамической установки уровней стоп-лосса и тейк-профита с использованием расчетов на основе Heikin Ashi.
  • Применение механизма трейлинг-стопа с использованием свечных паттернов Heikin Ashi для обеспечения прибыли по мере развития трендов.

1. Индикатор Heikin Ashi

1.1. Понимание индикатора Heikin Ashi

Индикатор Heikin Ashi (HA) облегчает выявление трендов: HA использует уникальную методику для определения новых значений на основе усредненных исторических ценовых данных, в отличие от обычных свечных графиков, которые отображают точные цены открытия, максимума, минимума и закрытия для каждого периода. Это помогает трейдерам разобраться в хаосе и сосредоточиться на важных вещах, создавая для себя более четкую и понятную картину рыночных движений.

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

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

Индикатор HA уникален тем, что он модифицирует традиционные расчеты свечей, используя метод усреднения. Он производит новые значения, которые обеспечивают более плавное и последовательное отображение ценового движения, а не просто отображают цены открытия, максимума, минимума и закрытия на рынке. Убирая "шум" от небольших колебаний цен, трейдеры способны лучше выявлять тренды и принимать более разумные решения.

Цена закрытия Heikin Ashi 

Среднее значение цен открытия, максимума, минимума закрытия текущего периода используется для определения цены закрытия Heikin Ashi (Heikin Ashi Close). Стандартные свечи, которые используют простую цену закрытия, показывают более сбалансированную перспективу изменения цены.

Формула такова:

Figure 2. H A_Close Formula

Цена Heikin Ashi Close сглаживает колебания цен, усредняя эти четыре значения, что делает паттерны более визуально очевидными.

Цена открытия Heikin Ashi

Для определения цены открытия Heikin Ashi (Heikin Ashi Open) используется предыдущая свеча Heikin Ashi, а не фактическая цена открытия рынка. Это значение определяется усреднением предыдущих цен открытия и закрытия Heikin Ashi:

Figure 3. H A_Open Formula

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

Цена максимума Heikin Ashi

Цена максимума Heikin Ashi (Heikin Ashi High) – это наивысшее значение, достигнутое за все время; однако она учитывает три значения: максимум текущего периода, Heikin Ashi Open и Heikin Ashi Close, а не только реальный максимум рынка. Из этих трех значений выбирается наибольшее:

Figure 4. H A_High Formula

Цена минимума Heikin Ashi

Аналогично, цена минимума Heikin Ashi (Heikin Ashi Low) рассчитывается путем выбора наименьшего значения среди Heikin Ashi Close, Heikin Ashi Open и фактического минимума за период:

Figure 5. H A_Low Formula

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

1.2. Преимущества использования Heikin Ashi

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

Последовательность из красных свечей указывает на снижение, в то время как серия зеленых свечей обычно указывает на сильный восходящий тренд. Благодаря этой ясности становится проще отличать реальные, долгосрочные изменения на рынке от краткосрочных отклонений.  Heikin Ashi помогает вам сократить количество ложных сигналов, избегая ненужных сделок, вызванных краткосрочными колебаниями цен. Используя исторические данные, он отфильтровывает рыночный шум, предлагая более надежное подтверждение тренда. Многие трейдеры комбинируют этот индикатор с такими инструментами, как RSI или Moving Average, чтобы улучшить свои стратегии. Давая более четкое представление о ценовом движении, индикатор Heikin Ashi упрощает решение о том, когда входить в сделки или выходить из них.

1.3. Реализация Heikin Ashi на языке MQL5

Реализация индикатора Heikin Ashi на языке MQL5 является следующим шагом после изучения его работы. Мы создадим свой собственный индикатор Heikin Ashi с нуля, потому что в MetaTrader 5 его нет. Для этого необходимо описать формулы Heikin Ashi в виде кода, применить их к ценовым данным и отобразить индикатор на графике.

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

Псевдокод:

НАСТРОЙКА ИНДИКАТОРА

  • Включите отображение индикатора в отдельном окне графика.
  • Настройте график для свечей Heikin Ashi.
  • Определите 4 буфера для хранения значений Heikin Ashi (Open, High, Low, Close).
ОПРЕДЕЛЕНИЕ БУФЕРОВ

Создайте буферы для хранения следующих рассчитанных значений:

  • Heikin Ashi Open
  • Heikin Ashi High
  • Heikin Ashi Low
  • Heikin Ashi Close

РАСЧЕТ ЗНАЧЕНИЙ HEIKIN ASHI 

Пройдите по историческим ценовым данным, чтобы вычислить значения Heikin Ashi, используя формулы:

  • HA Close = (Open + High + Low + Close) / 4
  • HA Open = (Предыдущее HA Open + Предыдущее HA Close) / 2
  • HA High = Максимальное значение среди (High, HA Open, HA Close)
  • HA Low = Минимальное значение среди (Low, HA Open, HA Close)

1.3.1. Создание и настройка Heikin Ashi

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

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

Пример:

// PROPERTY SETTINGS
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1

// PLOT SETTINGS FOR HEIKIN ASHI CANDLES
#property indicator_label1  "Heikin Ashi"
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrGreen, clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

Пояснение:

Настройки свойств
#property indicator_separate_window

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

Аналогия

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

Аналогичным образом, #property indicator_separate_window упрощает изучение трендов, не вмешиваясь в данные стандартных свечей благодаря перемещению индикатора Heikin Ashi в отдельное окно вместо наложения его на основной график цен.

#property indicator_buffers 5

Здесь указывается, сколько буферов будет использовать индикатор. В этом случае используется пять буферов: один для представления цвета и другие для хранения вычисленных значений Heikin Ashi (Open, High, Low, и Close).

Аналогия

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

Подобно этим лоткам, #property indicator_buffers 5 гарантирует, что различные данные Heikin Ashi будут храниться раздельно. Здесь у нас есть пять буферов: один для представления цвета и четыре для значений Heikin Ashi (Open, High, Low и Close). Эти буферы обеспечивают структурность при расчетах индикатора, что упрощает отображение правильных данных на графике, подобно тому, как лотки поддерживают порядок на вашем рабочем месте.

#property indicator_plots 1

Здесь указывается сколько графиков будет отображать индикатор. Нам нужно только одно графическое построение, потому что мы отображаем свечи Heikin Ashi как единое целое.

Аналогия

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

Аналогичным образом, терминал MetaTrader 5 получает информацию из строчки #property indicator_plots 1, что индикатор Heikin Ashi будет показан как один графически отображаемый элемент. Подобно вашей единственной диаграмме на доске для заметок, несколько буферов содержат различные данные (значения Open, High, Low, Close и цвет), но все они объединяются для создания единого набора свечей. Чтобы отобразить свечи Heikin Ashi, нам нужно только одно графическое построение, поскольку мы будем отображать только их.

Настройки графического построения

#property indicator_label1  "Heikin Ashi"
#property indicator_type1   DRAW_COLOR_CANDLES  
#property indicator_color1  clrGreen, clrRed    
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

Аналогия

После того как вы организовали свои материалы и рабочее место с доской для заметок, важно четко и понятно донести свои выводы. Чтобы сделать тренды более очевидными, вы решаете использовать цветные символы вместо написания простого текста или создания абстрактного дизайна. Вы четко указываете, что показывает ваша диаграмма, подписывая ее "Heikin Ashi" для всех, кто наблюдает за доской для заметок. Аналогичным образом, #property indicator_label1 "Heikin Ashi" задает индикатору имя и гарантирует, что он появится в списке индикаторов MetaTrader 5. Таким образом, трейдеры могут быстро находить его на своих графиках среди других индикаторов.

#property indicator_type1 DRAW_COLOR_CANDLES предприсывает терминалу MetaTrader 5 использовать цветные свечи вместо линий или гистограмм. Цвета определяются в строке #property indicator_color1 clrGreen, clrRed, где зеленый цвет представляет бычьи свечи, а красный – медвежьи свечи. Эта визуальная ясность позволяет легче замечать тренды с первого взгляда. Чтобы ваша доска для заметок оставалась аккуратной и читаемой, вы решаете использовать сплошную маркерную линию вместо пунктирных или точечных.

Аналогичным образом, #property indicator_style1 STYLE_SOLID гарантирует, что свечи Heikin Ashi будут заполнены сплошным цветом, что делает их визуально отличимыми. Наконец, так же как вы избегаете слишком толстых линий, чтобы не загромождать вашу диаграмму, указание #property indicator_width1 1 поддерживает разумную ширину контуров свечей для ясности, не перегружая график. Настраивая индикатор Heikin Ashi таким образом, мы создаем четкое, структурированное и интуитивно понятное представление рыночных трендов, так же как вы бы сделали это с вашим рабочим пространством, добавив к нему доску для заметок.

Теперь, когда мы настроили свойства индикатора и графического построения, следующим шагом является определение буферов, которые будут хранить цены свечей Heikin Ashi. Буферы выступают в качестве контейнеров для хранения рассчитанных значений индикатора, позволяя MetaTrader 5 отображать их на графике. В этом случае нам нужны буферы для хранения цен открытия, максимума, минимума и закрытия Heikin Ashi, а также дополнительный буфер для цветового представления. Мы также настроим соответствующие индексы буферов, чтобы гарантировать корректное соответствие каждого буфера и его данных.

Пример:

// PROPERTY SETTINGS
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1

// PLOT SETTINGS FOR HEIKIN ASHI CANDLES
#property indicator_label1  "Heikin Ashi"
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrGreen, clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

// INDICATOR BUFFERS
double HA_Open[];
double HA_High[];
double HA_Low[];
double HA_Close[];
double ColorBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
// SET BUFFERS
   SetIndexBuffer(0, HA_Open, INDICATOR_DATA);
   SetIndexBuffer(1, HA_High, INDICATOR_DATA);
   SetIndexBuffer(2, HA_Low, INDICATOR_DATA);
   SetIndexBuffer(3, HA_Close, INDICATOR_DATA);
   SetIndexBuffer(4, ColorBuffer, INDICATOR_COLOR_INDEX);

   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {

   return(rates_total);

  }

Пояснение:

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

double HA_Open[];
double HA_High[];
double HA_Low[];
double HA_Close[];
double ColorBuffer[];

Буфер HA_Open[] содержит цену открытия Heikin Ashi каждой свечи, а буфер HA_High[] – максимальную цену свечи Heikin Ashi. Аналогичным образом, цена закрытия свечи Heikin Ashi хранится в HA_Close[], а минимальная цена фиксируется в HA_Low[]. Кроме того, мы используем ColorBuffer[] для определения цвета каждой свечи, чтобы различать бычьи (зеленые) и медвежьи (красные) свечи. График сможет сохранять и отображать обновленные свечи Heikin Ashi благодаря совместной работе этих буферов.

SetIndexBuffer(0, HA_Open, INDICATOR_DATA);
SetIndexBuffer(1, HA_High, INDICATOR_DATA);
SetIndexBuffer(2, HA_Low, INDICATOR_DATA);
SetIndexBuffer(3, HA_Close, INDICATOR_DATA);
SetIndexBuffer(4, ColorBuffer, INDICATOR_COLOR_INDEX);     

Функция SetIndexBuffer в MetaTrader 5 связывает определенные буферы с их соответствующими индексами, обеспечивая правильную обработку и отображение данных индикатора Heikin Ashi. Согласно структуре свечей в терминале, цена открытия Open всегда выделяется под индексом 0, а значения High, Low и Close соответствуют индексам 1, 2 и 3. В отсутствие надлежащей индексации MetaTrader 5 может не распознать данные как правильные свечи, что может привести к пропуску элементов графика или проблемам с отображением.

Строка SetIndexBuffer(4, ColorBuffer, INDICATOR_COLOR_INDEX) задает цвет каждой свечи, выделяя бычьи (зеленые) или медвежьи (красные) движения, позволяя визуально различать тренды. Индикатор Heikin Ashi гарантирует корректное представление цен и визуальное оформление, соотнося эти буферы с надлежащими индексами, что позволяет трейдерам быстро анализировать тренды и принимать обоснованные решения.

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

Пример:

// PROPERTY SETTINGS
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1

// PLOT SETTINGS FOR HEIKIN ASHI CANDLES
#property indicator_label1  "Heikin Ashi"
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrGreen, clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

// INDICATOR BUFFERS
double HA_Open[];
double HA_High[];
double HA_Low[];
double HA_Close[];
double ColorBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
// SET BUFFERS
   SetIndexBuffer(0, HA_Open, INDICATOR_DATA);
   SetIndexBuffer(1, HA_High, INDICATOR_DATA);
   SetIndexBuffer(2, HA_Low, INDICATOR_DATA);
   SetIndexBuffer(3, HA_Close, INDICATOR_DATA);
   SetIndexBuffer(4, ColorBuffer, INDICATOR_COLOR_INDEX);

   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {

   if(rates_total < 2)
      return 0; // ENSURE ENOUGH DATA

   for(int i = 1; i < rates_total; i++)  // START FROM SECOND BAR
     {
      // HEIKIN ASHI CLOSE FORMULA
      HA_Close[i] = (open[i] + high[i] + low[i] + close[i]) / 4.0;

      // HEIKIN ASHI OPEN FORMULA
      HA_Open[i] = (HA_Open[i - 1] + HA_Close[i - 1]) / 2.0;

      // HEIKIN ASHI HIGH FORMULA
      HA_High[i] = MathMax(high[i], MathMax(HA_Open[i], HA_Close[i]));

      // HEIKIN ASHI LOW FORMULA
      HA_Low[i] = MathMin(low[i], MathMin(HA_Open[i], HA_Close[i]));

      // SET COLOR: GREEN FOR BULLISH, RED FOR BEARISH
      ColorBuffer[i] = (HA_Close[i] >= HA_Open[i]) ? 0 : 1;
     }

   return(rates_total);

  }

Поскольку первая свеча не содержит никаких предыдущих данных, этот метод вычисляет значения Heikin Ashi, начиная со второй свечи. Чтобы сгладить колебания цен, цена закрытия представляет собой усредненное значение цен открытия, максимума, минимума и закрытия текущего бара. Цена открытия обеспечивает плавные переходы, усредняя цены открытия и закрытия Heikin Ashi предыдущей свечи. Максимумы/минимумы текущего бара и цены открытия/закрытия Heikin Ashi являются максимальными и минимальными значениями, на основе которых рассчитываются цены Heikin Ashi High и Heikin Ashi Low. Наконец, свеча окрашивается в красный (медвежий) цвет, если цена закрытия меньше или равна цене открытия, иначе она окрашивается в зеленый (бычий) цвет. Это позволяет трейдерам видеть тренды, уменьшая рыночный шум.

Figure 6. HA Indicator


2. Создание Moving Average на основе данных Heikin Ashi

Теперь, когда мы успешно сгенерировали свечи Heikin Ashi, следующим шагом является создание Moving Average (MA) на основе значений Heikin Ashi вместо стандартных ценовых данных.

Псевдокод:

ИЗМЕНЕНИЕ СВОЙСТВ ИНДИКАТОРА

  • Измените количество буферов с пяти на шесть, чтобы выделить место для Heikin Ashi Moving Average. 

  • Измените количество графических построений с 1 на 2, чтобы свечи и Heikin Ashi Moving Average отображались вместе.

ОПРЕДЕЛЕНИЕ БУФЕРА ДЛЯ HEIKIN ASHI MOVING AVERAGE

  • Создайте буфер для хранения значений Heikin Ashi Moving Average.
  • Определите входную переменную для периода Moving Average (например, 20).

НАСТРОЙКА БУФЕРА ДЛЯ HEIKIN ASHI MOVING AVERAGE

  • Свяжите буфер с индексом для хранения рассчитанных значений MA.
  • Задайте индекс графического построения, чтобы он начинался с периода Moving Average для обеспечения правильного отображения.

РАСЧЕТ HEIKIN ASHI MOVING AVERAGE

  • Начните цикл с (period - 1), чтобы обеспечить достаточное количество точек данных.
  • Вычислите сумму последних 'n' значений Heikin Ashi Close.
  • Разделите сумму на period и сохраните результат в буфере.

Пример:

// PROPERTY SETTINGS
#property indicator_separate_window
#property indicator_buffers 6
#property indicator_plots   2

// PLOT SETTINGS FOR HEIKIN ASHI CANDLES
#property indicator_label1  "Heikin Ashi"
#property indicator_type1   DRAW_COLOR_CANDLES  
#property indicator_color1  clrGreen, clrRed    
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//PROPERTIES OF THE Heikin MA
#property indicator_label2  "Heikin MA"   
#property indicator_type2   DRAW_LINE  
#property indicator_style2  STYLE_DASH 
#property indicator_width2  1          
#property indicator_color2  clrBrown   

// INDICATOR BUFFERS
double HA_Open[];
double HA_High[];
double HA_Low[];
double HA_Close[];
double ColorBuffer[]; 

double Heikin_MA_Buffer[];
int input  heikin_ma_period = 20;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
    // SET BUFFERS
    SetIndexBuffer(0, HA_Open, INDICATOR_DATA);
    SetIndexBuffer(1, HA_High, INDICATOR_DATA);
    SetIndexBuffer(2, HA_Low, INDICATOR_DATA);
    SetIndexBuffer(3, HA_Close, INDICATOR_DATA);
    SetIndexBuffer(4, ColorBuffer, INDICATOR_COLOR_INDEX);
    
    SetIndexBuffer(5, Heikin_MA_Buffer, INDICATOR_DATA);  
    PlotIndexSetInteger(5, PLOT_DRAW_BEGIN, heikin_ma_period);
     
    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
{
    if (rates_total < 2) return 0; // ENSURE ENOUGH DATA
      
    for (int i = 1; i < rates_total; i++) // START FROM SECOND BAR
    {
        // HEIKIN ASHI CLOSE FORMULA
        HA_Close[i] = (open[i] + high[i] + low[i] + close[i]) / 4.0;

        // HEIKIN ASHI OPEN FORMULA
        HA_Open[i] = (HA_Open[i - 1] + HA_Close[i - 1]) / 2.0;

        // HEIKIN ASHI HIGH FORMULA
        HA_High[i] = MathMax(high[i], MathMax(HA_Open[i], HA_Close[i]));

        // HEIKIN ASHI LOW FORMULA
        HA_Low[i] = MathMin(low[i], MathMin(HA_Open[i], HA_Close[i]));

        // SET COLOR: GREEN FOR BULLISH, RED FOR BEARISH
        ColorBuffer[i] = (HA_Close[i] >= HA_Open[i]) ? 0 : 1;
    }    
    
     for(int i = heikin_ma_period - 1; i < rates_total; i++)
     {

      double sum = 0.0;
      for(int j = 0; j < heikin_ma_period; j++)
        {
         sum += HA_Close[i - j];
        }

      Heikin_MA_Buffer[i] = sum / heikin_ma_period;

     }

    return rates_total;
}

Пояснение:

Сначала мы должны изменить настройки буфера и графического построения, чтобы включить Heikin Ashi Moving Average (HA MA) в индикатор. #property indicator_buffers 6 увеличивает количество буферов с 5 до 6, что гарантирует наличие запасного буфера для хранения данных HA MA. Свечи Heikin Ashi и HA MA можно отобразить на графике вместе, используя #property indicator_plots 2, чтобы изменить количество графических построений с 1 на 2. Это гарантирует, что индикатор сможет эффективно обрабатывать оба набора данных.

Затем настраиваются свойства графического построения HA MA. #property indicator_label2 – это метка. Давая Moving Average имя "Heikin MA", мы делаем ее заметной в списке индикаторов. Чтобы определить, что Moving Average будет отображаться в виде линии вместо свечей, мы устанавливаем тип с помощью #property indicator_type2 DRAW_LINE. Мы устанавливаем #property indicator_style2 STYLE_DASH, чтобы сделать линию пунктирной, и используем #property indicator_width2 1, чтобы определить ее ширину для повышения видимости. С помощью #property indicator_color2 clrBrown мы задаем коричневый цвет, что обеспечивает яркий контраст со свечами Heikin Ashi.

После установки свойств мы определяем входной параметр int input heikin_ma_period = 20; который позволяет пользователям изменять период, и объявляем массив double Heikin_MA_Buffer[]; для хранения данных Moving Average. SetIndexBuffer(5, Heikin_MA_Buffer, INDICATOR_DATA); используется для связывания буфера с индикатором, позволяя MetaTrader 5 корректно управлять значениями и отображать их. PlotIndexSetInteger(5, PLOT_DRAW_BEGIN, heikin_ma_period); также гарантирует, что Moving Average будет отображаться только после того, как будет доступно достаточное количество баров.

Последним шагом является расчет Heikin Ashi Moving Average. Чтобы гарантировать, что у нас достаточно данных для расчета, цикл начинается со значения heikin_ma_period -1. Moving Average рассчитывается в цикле путем сложения последних n значений Heikin Ashi Close и деления полученной суммы на период. Затем индикатор отображает Moving Average вместе со свечами Heikin Ashi после сохранения результата в Heikin_MA_Buffer[i], предоставляя трейдерам сглаженный трендовый инструмент.

Figure 7. HA Indicator and HA MA


3. Интеграция пользовательского индикатора в советник

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

В качестве торговой стратегии мы будем использовать простую стратегию пересечения, основанную на Heikin Ashi Moving Average (HA MA) и свечах Heikin Ashi (HA). Эта техника помогает выявить потенциальные развороты тренда и признаки его продолжения, анализируя взаимосвязь между ценой закрытия свечи Heikin Ashi и Heikin Ashi Moving Average. Признаком восходящего тренда и потенциальной возможности покупки является свеча Heikin Ashi, закрывающаяся выше Heikin Ashi Moving Average. И наоборот, закрытие свечи Heikin Ashi ниже Heikin Ashi Moving Average генерирует сигнал на продажу, что указывает на возможный разворот медвежьего тренда и возможность продажи.

Figure 8. Buy and Sell Logic

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

Первое, о чем следует подумать при интеграции пользовательского индикатора в советник, это то, как ввести данные индикатора в ваш советник. Советник не может принимать торговые решения на основании индикатора, если его значения недоступны. Например, четыре значения, которые составляют свечу Heikin Ashi, должны быть импортированы в нашу стратегию пересечения Heikin Ashi Moving Average:

  • Цена открытия HA
  • Цена максимума HA
  • Цена минимума HA
  • Цена закрытия HA

Наши торговые сигналы основаны на этих параметрах: они будут использоваться для оценки того, пересекла ли свеча Heikin Ashi уровень HA MA сверху или снизу.

Пример:

// Declare arrays to store Heikin Ashi data from the custom indicator
double heikin_open[];   // Stores Heikin Ashi Open prices
double heikin_close[];  // Stores Heikin Ashi Close prices
double heikin_low[];    // Stores Heikin Ashi Low prices
double heikin_high[];   // Stores Heikin Ashi High prices
double heikin_ma[];     // Stores Heikin Ashi Moving Average values

int heikin_handle;      // Handle for the custom Heikin Ashi indicator

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
// Ensure arrays store data in a time series format (most recent data first)
   ArraySetAsSeries(heikin_open, true);
   ArraySetAsSeries(heikin_close, true);
   ArraySetAsSeries(heikin_low, true);
   ArraySetAsSeries(heikin_high, true);
   ArraySetAsSeries(heikin_ma, true);

// Load the custom Heikin Ashi indicator and get its handle
   heikin_handle = iCustom(_Symbol, PERIOD_CURRENT, "Project7 Heikin Ashi Indicator.ex5");

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// Nothing to clean up in this case, but can be used for resource management if needed
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// Copy the latest 3 values of each buffer from the Heikin Ashi indicator
   CopyBuffer(heikin_handle, 0, 0, 3, heikin_open);  // Get HA Open values
   CopyBuffer(heikin_handle, 1, 0, 3, heikin_high);  // Get HA High values
   CopyBuffer(heikin_handle, 2, 0, 3, heikin_low);   // Get HA Low values
   CopyBuffer(heikin_handle, 3, 0, 3, heikin_close); // Get HA Close values
   CopyBuffer(heikin_handle, 5, 0, 3, heikin_ma);    // Get HA Moving Average values

// Print index 0 values to the terminal
   Print("HA Open: ", heikin_open[0],
         "\nHA High: ", heikin_high[0],
         "\nHA Low: ", heikin_low[0],
         "\nHA Close: ", heikin_close[0],
         "\nHA MA: ", heikin_ma[0]);
  }

Пояснение:

Объявление массивов для хранения данных Heikin Ashi

Объявление массивов для хранения данных, собранных с индикатора, является первым шагом для интеграции пользовательского индикатора в советник. В этом примере объявлено пять массивов для хранения различных компонентов индикатора Heikin Ashi:

  • heikin_open[] хранит цены Heikin Ashi Open;
  • heikin_close[] для цен Heikin Ashi Close;
  • heikin_low[] хранит цены Heikin Ashi Low;
  • heikin_high[] цены Heikin Ashi High;
  • heikin_ma[] хранит значения Heikin Ashi Moving Average.

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

Объявление хэндла индикатора

Хэндл настраиваемого индикатора Heikin Ashi хранится в переменной heikin_handle. Хэндл в языке MQL5 – это отдельная ссылка на экземпляр индикатора, работающий в фоновом режиме. Поскольку он позволяет советнику взаимодействовать с индикатором и запрашивать данные по мере необходимости, этот хэндл является необходимым. Без хэндла советник не имел бы доступа к значениям Heikin Ashi. Позже, когда будет выполнена функция iCustom(), хэндлу будет присвоено значение. Если хэндл недействителен (возвращает -1), значит индикатор не был загружен корректно, что мешает советнику получить необходимые данные.

Инициализация массива в формате временного ряда

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

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

 ArraySetAsSeries(heikin_open, true);
 ArraySetAsSeries(heikin_close, true);
 ArraySetAsSeries(heikin_low, true);
 ArraySetAsSeries(heikin_high, true);
 ArraySetAsSeries(heikin_ma, true);

Благодаря преобразованию этих массивов в формат временного ряда индекс 0 позволяет советнику всегда получать доступ к самым свежим данным Heikin Ashi. Это особенно полезно при практическом применении торговых техник, поскольку это гарантирует, что советник будет реагировать на текущие рыночные движения, а не на исторические данные.

Загрузка пользовательского индикатора Heikin Ashi с помощью iCustom()

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

heikin_handle = iCustom(_Symbol, PERIOD_CURRENT, "Project7 Heikin Ashi Indicator.ex5");

  • _Symbol дает функции указание применять индикатор к текущему торговому символу (например, EUR/USD, GBP/JPY и т.д.). Это гарантирует, что индикатор будет обрабатывать данные для того же актива, на котором работает советник.
  • PERIOD_CURRENT обеспечивает наложение индикатора на тот же таймфрейм, на котором работает советник. Если советник работает на графике H1, индикатор будет наложен также на H1.
  • "Project7 Heikin Ashi Indicator.ex5" обозначает имя файла пользовательского индикатора, который советник должен использовать. Расширение .ex5 указывает на то, что это скомпилированный файл индикатора на языке MQL5.

Крайне важно убедиться, что файл индикатора хранится в соответствующем каталоге MetaTrader 5. Индикатор должен находиться в папке Indicators директории MQL5. Полный путь к этой папке:

MQL5/Indicators/

Наконец, основной функцией, которая соединяет пользовательский индикатор с советником, является iCustom(). Она передает советнику хэндл, который позволяет динамически извлекать значения индикатора. Функция не будет работать должным образом, если индикатор не будет размещен надлежащим образом в папке Indicators (либо во вложенной в нее подпапке).

Копирование данных индикатора в массивы

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

CopyBuffer(heikin_handle, 0, 0, 3, heikin_open);  // Get HA Open values
CopyBuffer(heikin_handle, 1, 0, 3, heikin_high);  // Get HA High values
CopyBuffer(heikin_handle, 2, 0, 3, heikin_low);   // Get HA Low values
CopyBuffer(heikin_handle, 3, 0, 3, heikin_close); // Get HA Close values
CopyBuffer(heikin_handle, 5, 0, 3, heikin_ma);    // Get HA Moving Average values

Данные извлекаются из пользовательского индикатора с использованием одной и той же структуры для каждого вызова CopyBuffer(). Хэндл, полученный от функции iCustom(), является первым параметром – heikin_handle. Советник может получить доступ к данным пользовательского индикатора Heikin Ashi, используя этот хэндл в качестве ссылки. Советник не мог бы запросить значение индикатора без этого хэндла. Индексы буфера для различных компонентов индикатора Heikin Ashi представлены следующим набором параметров (0, 1, 2, 3, 5). В языке MQL5 индикаторы используют буферы для хранения своих данных, и каждому буферу присваивается уникальный индекс. Цена открытия Heikin Ashi (Heikin Ashi Open) в данном случае представлена буфером 0, цена максимума – буфером 1, цена минимума – буфером 2, цена закрытия – буфером 3, а Heikin Ashi Moving Average – буфером 5. Задавая эти индексы, мы обеспечиваем получение надлежащих данных от индикатора.

Данные должны дублироваться, начиная с самой последней свечи (текущей свечи), в соответствии с третьим параметром (0). Это гарантирует, что советник будет всегда использовать самые последние рыночные данные, которые необходимы для принятия торговых решений в реальном времени. В соответствии с четвертым параметром (3) должны быть воспроизведены три точки данных. Извлечение нескольких значений позволяет советнику исследовать как исторические, так и текущие данные Heikin Ashi, что полезно для обнаружения паттернов или подтверждения трендов. 

Наконец, связанные массивы – heikin_open, heikin_high, heikin_low, heikin_close и heikin_ma – используются для хранения восстановленных данных. Извлеченные значения хранятся в этих массивах, чтобы советник мог обрабатывать и использовать их в своей торговой логике. Для того чтобы советник принимал обоснованные торговые решения на основе ценовых трендов, крайне важно, чтобы у него была актуальная информация по индикатору Heikin Ashi.

3.2. Использование данных индикаторов в нашей торговой стратегии

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

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

3.2.1. Отслеживание открытых покупок и продаж в советнике

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

Пример:

int totalPositions = 0;
int position_type_buy = 0;
int position_type_sell = 0;

for(int i = 0; i < PositionsTotal(); i++)
  {
   ulong ticket = PositionGetTicket(i);

   if(PositionSelectByTicket(ticket))
     {
      if(PositionGetInteger(POSITION_MAGIC) == MagicNumber && PositionGetString(POSITION_SYMBOL) == ChartSymbol(ChartID())
     {
      totalPositions++;
      if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
           {
            position_type_buy++;
           }
         if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
           {
            position_type_sell++;
           }
        }
     }
  }

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

3.2.2. Отслеживание ежедневных лимитов торговли в советнике

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

Пример:

input int daily_trades = 6; // Total Daily Trades

// Start and end time for
string start = "00:00";
string end = "23:50";

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

   datetime start_time = StringToTime(start);
   datetime end_time = StringToTime(end);
   bool success = HistorySelect(start_time, end_time);

// Getting total trades
   int totalDeal = 0;
   int deal_type_buy = 0;
   int deal_type_sell = 0;
   if(success)
     {
      for(int i = 0; i < HistoryDealsTotal(); i++)
        {
         ulong ticket = HistoryDealGetTicket(i);

         if(HistoryDealGetInteger(ticket, DEAL_MAGIC) == MagicNumber && HistoryDealGetString(ticket,DEAL_SYMBOL) == ChartSymbol(chart_id))
           {
            if(HistoryDealGetInteger(ticket, DEAL_ENTRY) == DEAL_ENTRY_IN)
              {
               totalDeal++;
               if(HistoryDealGetInteger(ticket, DEAL_TYPE) == DEAL_TYPE_BUY)
                 {

                  deal_type_buy++;

                 }
               if(HistoryDealGetInteger(ticket, DEAL_TYPE) == DEAL_TYPE_SELL)
                 {

                  deal_type_sell++;

                 }
              }
           }
        }
     }
  }

Пояснение:

Советник изначально переводит указанное время начала и окончания в формат datetime, чтобы отслеживать общее количество сделок, совершенных в течение данной торговой сессии. Функция HistorySelect() затем используется для выбора торговой истории, которая попадает в этот временной интервал. В советнике объявляются счетчики для записи общего количества выполненных сделок, а также количества покупок и продаж независимо от того, успешна ли выборка.

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

3.2.3. Предотвращение повторных сделок в пределах одной свечи

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

Пример:

// Declare an array to store time data
datetime time[];

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
// Ensure the time array is structured as a time series (most recent data first)
   ArraySetAsSeries(time, true);

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// Retrieve the latest three time values from the current symbol and timeframe
   CopyTime(_Symbol, PERIOD_CURRENT, 0, 3, time);

// Select trading history from the earliest recorded time to the current time
   bool trade_control = HistorySelect(time[0], TimeCurrent());

// Variable to count the number of closed trades
   int total_deals_out = 0;

// If the trading history selection is successful, process the data
   if(trade_control)
     {
      // Loop through all closed trades in the history
      for(int i = 0; i < HistoryDealsTotal(); i++)
        {
         // Get the ticket number of the historical trade
         ulong ticket = HistoryDealGetTicket(i);

         // Check if the trade matches the current EA's Magic Number and symbol
         if(HistoryDealGetInteger(ticket, DEAL_MAGIC) == MagicNumber && HistoryDealGetString(ticket, DEAL_SYMBOL) == ChartSymbol(chart_id))
           {
            // If the trade was an exit trade, increment the counter
            if(HistoryDealGetInteger(ticket, DEAL_ENTRY) == DEAL_ENTRY_OUT)
              {
               total_deals_out++;
              }
           }
        }
     }
  }

Пояснение:

Эта функция предотвращает открытие советником сделки в рамках одной и той же свечи после закрытия предыдущей сделки. С помощью функции CopyTime(), которая возвращает временные метки самых последних баров, мы сначала извлекаем из графика самые последние значения времени. Затем от первого зафиксированного времени бара (time[0]) до текущего рыночного времени (TimeCurrent()) советник собирает историю сделок в рамках таймфрейма.

Чтобы найти закрытые сделки, которые соответствуют магическому числу и символу советника, он проходится по торговой истории. Счетчик total_deals_out увеличивается, если обнаружена закрытая сделка – в частности, закрывающая сделка (DEAL_ENTRY_OUT). Если в пределах одной свечи была недавно закрыта сделка, этот счетчик может помочь вам это выяснить. Чтобы гарантировать исполнение сделок только в начале новой свечи и избежать немедленного повторного открытия, советник будет воздерживаться от открытия новой сделки до начала новой свечи.

3.2.4. Реализация управления рисками и исполнения сделок с помощью Heikin Ashi

Чтобы гарантировать исполнение сделок на покупку и продажу в соответствии с сигналами Heikin Ashi, в этом разделе мы укажем требования к исполнению сделок. Кроме того, мы интегрируем управление рисками посредством определения размера лота в соответствии с заранее установленным долларовым риском на сделку и соотношением риска к вознаграждению (risk-to-reward ratio, RRR). Эта стратегия избегает чрезмерной подверженности риску, поддерживая контролируемую торговлю.

Пример:

input  double dollar_risk = 12.0; // How Many Dollars($) Per Trade?
input double RRR = 3;

double ask_price;
double lot_size;
double point_risk;
double take_profit;

// Variable to store the time of the last executed trade
datetime lastTradeBarTime = 0;

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

// Get the opening time of the current bar
   datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);

// Check conditions for opening a buy position
// Ensures Heikin Ashi candle crosses above the moving average
// Limits trades per day and prevents multiple trades in the same candlestick
   if(heikin_open[1] < heikin_ma[1] && heikin_close[1] > heikin_ma[1] &&
      deal_type_buy < (daily_trades / 2) && total_deals_out < 1 &&
      totalPositions < 1 && currentBarTime != lastTradeBarTime)
     {
      // Calculate risk in points (distance from entry to stop loss)
      point_risk = ask_price - heikin_low[1];

      // Calculate take profit based on risk-to-reward ratio (RRR)
      take_profit = ((ask_price - heikin_low[1]) * RRR) + ask_price;

      // Determine lot size based on the dollar risk per trade
      lot_size = CalculateLotSize(_Symbol, dollar_risk, point_risk);

      // Execute a buy trade
      trade.Buy(lot_size, _Symbol, ask_price, heikin_low[1], take_profit);

      // Store the current bar time to prevent multiple trades in the same candle
      lastTradeBarTime = currentBarTime;
     }

// Check conditions for opening a sell position
// Ensures Heikin Ashi candle crosses below the moving average
// Limits trades per day and prevents multiple trades in the same candlestick
   if(heikin_open[1] > heikin_ma[1] && heikin_close[1] < heikin_ma[1] &&
      deal_type_sell < (daily_trades / 2) && total_deals_out < 1 &&
      totalPositions < 1 && currentBarTime != lastTradeBarTime)
     {
      // Calculate risk in points (distance from entry to stop loss)
      point_risk = heikin_high[1] - ask_price;

      // Calculate take profit based on risk-to-reward ratio (RRR)
      take_profit = MathAbs(((heikin_high[1] - ask_price) * RRR) - ask_price);

      // Determine lot size based on the dollar risk per trade
      lot_size = CalculateLotSize(_Symbol, dollar_risk, point_risk);

      // Execute a sell trade
      trade.Sell(lot_size, _Symbol, ask_price, heikin_high[1], take_profit);

      // Store the current bar time to prevent multiple trades in the same candle
      lastTradeBarTime = currentBarTime;
     }
  }

//+------------------------------------------------------------------+
//| Function to calculate the lot size based on risk amount and stop loss
//+------------------------------------------------------------------+
double CalculateLotSize(string symbol, double riskAmount, double stopLossPips)
  {
// Get symbol information
   double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
   double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);

// Calculate pip value per lot
   double pipValuePerLot = tickValue / point;

// Calculate the stop loss value in currency
   double stopLossValue = stopLossPips * pipValuePerLot;

// Calculate the lot size
   double lotSize = riskAmount / stopLossValue;

// Round the lot size to the nearest acceptable lot step
   double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
   lotSize = MathFloor(lotSize / lotStep) * lotStep;

   return lotSize;
  }

Пояснение:

Для подтверждения трендов логика исполнения сделок зависит от пересечения свечей Heikin Ashi с Moving Average (MA). На бычий разворот указывает то, что цена открытия ниже MA, а цена закрытия выше, а когда верно обратное – это сигнал на продажу. Система ограничивает сумму сделок за день, следит за отсутствием открытых позиций и проводит сделки только на свежих свечах, чтобы предотвратить чрезмерную торговлю. Стоп-лоссы на предыдущих максимумах или минимумах Heikin Ashi, фиксация прибыли на основе соотношения риска к прибыли (RRR) и динамический размер лота – все это компоненты управления рисками.

3.2.5. Использование свечей Heikin Ashi для установки трейлинг-стопа

Реализация механизма трейлинг-стопа с использованием свечей Heikin Ashi является основной целью данного раздела. Это обеспечит динамическую корректировку уровней стоп-лосса в ответ на изменения цен Heikin Ashi.

Пример:

input bool    allow_trailing  = false; // Do you Allow Trailing Stop?

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

   // Check if trailing stop is enabled
   if(allow_trailing == true)
     {
      // Variables to store trade-related information
      double positionProfit = 0;
      double positionopen = 0;
      double positionTP = 0;
      double positionSL = 0;

      // Loop through all open positions
      for(int i = 0; i < PositionsTotal(); i++)
        {
         // Get the ticket number of the position
         ulong ticket = PositionGetTicket(i);

         // Select the position using its ticket number
         if(PositionSelectByTicket(ticket))
           {
            // Check if the position belongs to the EA by verifying the magic number and symbol
            if(PositionGetInteger(POSITION_MAGIC) == MagicNumber && PositionGetString(POSITION_SYMBOL) == ChartSymbol(chart_id))
              {
               // Retrieve trade details: open price, take profit, profit, and stop loss
               positionopen = PositionGetDouble(POSITION_PRICE_OPEN);
               positionTP = PositionGetDouble(POSITION_TP);
               positionProfit = PositionGetDouble(POSITION_PROFIT);
               positionSL = PositionGetDouble(POSITION_SL);

               // Apply trailing stop logic for buy positions
               if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
                 {
                  // Adjust stop loss if Heikin Ashi low is above the entry price and the candle is bullish
                  if(heikin_low[1] > positionopen && heikin_close[1] > heikin_open[1])
                    {
                     trade.PositionModify(ticket, heikin_low[1], positionTP);
                    }
                 }

               // Apply trailing stop logic for sell positions
               if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
                 {
                  // Adjust stop loss if Heikin Ashi high is below the entry price and the candle is bearish
                  if(heikin_high[1] < positionopen && heikin_close[1] < heikin_open[1])
                    {
                     trade.PositionModify(ticket, heikin_high[1], positionTP);
                    }
                 }
              }
           }
        }
     }
  }

Пояснение:

Чтобы обезопасить прибыль и динамически настраивать уровни стоп-лосса, в данном разделе свечи Heikin Ashi используются для реализации системы трейлинг-стопов. Входная переменная allow_trailing управляет тем, включена ли функция трейлинг-стопов; если значение переменной true, система проходит по всем открытым позициям, извлекает информацию о них и проверяет, относятся ли они советнику, проверяя магическое число и символ. Чтобы упростить логику трейлинг-стопа, извлекается ключевая информация о сделке, включая цену открытия, тейк-профит, прибыль и стоп-лосс.

Проверяя, что предыдущий минимум Heikin Ashi выше цены входа, а цена закрытия Heikin Ashi выше цены открытия, система подтверждает открытые позиции и бычий тренд. Чтобы защитить прибыль, допуская при этом дальнейшее движение вверх, уровень стоп-лосса устанавливается на цену минимума Heikin Ashi, если эти условия выполнены. Проверяя, что предыдущий максимум Heikin Ashi ниже цены входа, а цена закрытия Heikin Ashi ниже цены открытия, система подтверждает нисходящий тренд для сделок на продажу. Чтобы защитить сделку и поймать больше рыночных колебаний, уровень стоп-лосса устанавливается на максимум Heikin Ashi, если эти условия выполнены.


Заключение

В этой статье мы с нуля создали индикатор Heikin Ashi, интегрировали его с Moving Average, использующей данные свечей Heikin Ashi, и узнали как встроить пользовательский индикатор в советник, обеспечивая безупречную интеграцию для автоматической торговли. Мы такие внедрили методы управления рисками, как установка лимита на сумму сделок в течение дня, предотвращение нескольких сделок в пределах одной свечи и динамическое вычисление размеров лота. Кроме того, мы внедрили механизм трейлинг-стопа на основе свечей Heikin Ashi для корректировки уровней стоп-лосса. Эти примеры обеспечивают надежную основу для создания и совершенствования автоматизированных торговых стратегий на языке MQL5.

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

Прикрепленные файлы |
Последние комментарии | Перейти к обсуждению на форуме трейдеров (2)
dhermanus
dhermanus | 31 мая 2025 в 11:08

Привет, Исреаль,

Спасибо за блог, время и усилия.


Я хотел бы спросить вас о вашем коде пользовательского индикатора Heikin Ashi.

О формуле Heikin Ashi Open :

// HEIKIN ASHI OPEN FORMULA
HA_Open[i] = (HA_Open[i - 1] + HA_Close[i - 1]) / 2.0;

Поскольку вы не вычислили HA_Open[i - 1]. Разве это не будет 0?


Мое предложение :


if (i == 1){

HA_Open[i] = (open[i - 1] + close[i - 1])/2.0; // На первом баре HA просто используйте обычные данные open/close

}

else{

// ФОРМУЛА ОТКРЫТИЯ HEIKIN ASHI

HA_Open[i] = (HA_Open[i - 1] + HA_Close[i - 1]) / 2.0;


}

Israel Pelumi Abioye
Israel Pelumi Abioye | 31 мая 2025 в 12:28
dhermanus пользовательского индикатора Heikin Ashi.

О формуле Heikin Ashi Open :

// HEIKIN ASHI OPEN FORMULA
HA_Open[i] = (HA_Open[i - 1] + HA_Close[i - 1]) / 2.0;

Поскольку вы не вычислили HA_Open[i - 1]. Разве это не будет 0?


Мое предположение:


if (i == 1){

HA_Open[i] = (open[i - 1] + close[i - 1])/2.0; // На первом баре HA просто используйте обычные данные open/close

}

else{

// ФОРМУЛА ОТКРЫТИЯ HEIKIN ASHI

HA_Open[i] = (HA_Open[i - 1] + HA_Close[i - 1]) / 2.0;


}

Спасибо. Я изучу этот вопрос
Моделирование рынка (Часть 15): Сокеты (IX) Моделирование рынка (Часть 15): Сокеты (IX)
В этой статье мы расскажем об одном из возможных решений того, что мы пытались показать, то есть как позволить пользователю Excel выполнить действие в MetaTrader 5 без отправки ордеров, открытия или закрытия позиции. Идея заключается в том, что пользователь использует Excel для проведения фундаментального анализа какого-то символа. И что при использовании только Excel, можно указать советнику, работающему в MetaTrader 5, открыть или закрыть определенную позицию.
Трейдинг с экономическим календарем MQL5 (Часть 6): Автоматизация входа в сделку с анализом новостей и таймерами обратного отсчета Трейдинг с экономическим календарем MQL5 (Часть 6): Автоматизация входа в сделку с анализом новостей и таймерами обратного отсчета
В этой статье мы реализуем автоматизированный вход в торговлю с использованием экономического календаря MQL5, применив настраиваемые фильтры и временные смещения для поиска новостей. Мы сравниваем прогнозные и предыдущие значения, чтобы определить, следует ли открывать сделку на покупку или продажу. Динамические таймеры обратного отсчета отображают оставшееся время до выхода новостей и автоматически сбрасываются после совершения сделки.
Нейросети в трейдинге: Спайковая архитектура пространственно-временного анализа рынка (Окончание) Нейросети в трейдинге: Спайковая архитектура пространственно-временного анализа рынка (Окончание)
Фреймворк SDformerFlow превращает сложные события финансовых рядов в структурированные представления, позволяя модели видеть одновременно локальные колебания и глобальные тенденции. Многоуровневая U-структура обеспечивает согласованность прямого и обратного проходов, синхронизацию градиентов и устойчивость вычислений. В итоге SDformerFlow проявляет себя как мощный и гибкий инструмент для построения современных торговых систем.
Моделирование рынка (Часть 14): Сокеты (VIII) Моделирование рынка (Часть 14): Сокеты (VIII)
Многие программисты могут предположить, что нам следует отказаться от использования Excel и перейти непосредственно на Python, используя некоторые пакеты, позволяющие Python создавать Excel-файл, чтобы потом проанализировать результаты. Но, как уже говорилось в предыдущей статье, хотя это решение и является наиболее простым для многих программистов, оно не будет воспринято некоторыми пользователями. И в данном вопросе пользователь всегда прав. Мы, как программисты, должны найти способ заставить всё работать.