Знакомство с языком MQL5 (Часть 13): Руководство для начинающих по созданию пользовательских индикаторов (II)
Введение
И еще раз добро пожаловать в нашу серию статей по языку MQL5! В Части 12 этой серии мы исследовали основы создания пользовательских индикаторов на языке MQL5. Мы создали индикатор Moving Average (скользящая средняя) с нуля, реализовав его логику вручную, вместо того чтобы полагаться на встроенные функции. Затем мы расширили эти знания, преобразовав их в Moving Average в формате свечи, продемонстрировав, как манипулировать графическими элементами в индикаторе.
Основываясь на этом фундаменте, эта статья представит более интересные концепции в разработке индикаторов. Мы, как обычно, будем использовать проектный подход, чтобы убедиться, что вы понимаете темы, применяя их на практике. Основными целями будут создание индикатора Heikin Ashi и расчет Moving Average на основе его данных. После того как эти индикаторы будут созданы, мы разработаем советник, который будет задействовать индикаторы Heikin Ashi и Moving Average. Даже новички в работе с языком MQL5 могут ознакомиться с материалом, потому что эта статья – для начинающих. Чтобы пояснить вам не только то, как работает реализация, но и почему необходим каждый из предложенных шагов, каждая строка кода будет подробно объяснена.
Эта статья будет посвящена стратегии, которая предназначена исключительно для образовательных целей. Она не предназначена к использованию в качестве торговой стратегии, не гарантирует успех и не является финансовым советом. Перед использованием стратегии в реальной торговле всегда тестируйте их в безрисковой среде.
Heikin Ashi (HA) и HA Moving Average

В этой статье вы узнаете:
- Как создать пользовательский индикатор 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). Стандартные свечи, которые используют простую цену закрытия, показывают более сбалансированную перспективу изменения цены.Формула такова:

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

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

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

Этот подход поддерживает согласованность с методами сглаживания, гарантируя, что значение 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. Наконец, свеча окрашивается в красный (медвежий) цвет, если цена закрытия меньше или равна цене открытия, иначе она окрашивается в зеленый (бычий) цвет. Это позволяет трейдерам видеть тренды, уменьшая рыночный шум.

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], предоставляя трейдерам сглаженный трендовый инструмент.

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 генерирует сигнал на продажу, что указывает на возможный разворот медвежьего тренда и возможность продажи.

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
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Моделирование рынка (Часть 15): Сокеты (IX)
Трейдинг с экономическим календарем MQL5 (Часть 6): Автоматизация входа в сделку с анализом новостей и таймерами обратного отсчета
Нейросети в трейдинге: Спайковая архитектура пространственно-временного анализа рынка (Окончание)
Моделирование рынка (Часть 14): Сокеты (VIII)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Привет, Исреаль,
Спасибо за блог, время и усилия.
Я хотел бы спросить вас о вашем коде пользовательского индикатора 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;
}
О формуле 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;
}