English Deutsch 日本語
preview
Мастер-класс по созданию пользовательских индикаторов (Часть 2): Разработка практического советника Supertrend на MQL5

Мастер-класс по созданию пользовательских индикаторов (Часть 2): Разработка практического советника Supertrend на MQL5

MetaTrader 5Торговые системы |
60 0
Chacha Ian Maroa
Chacha Ian Maroa

Введение

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

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

Именно это и рассматривается в данной статье. Разрабатывается советник на языке MQL5, который отслеживает сигналы индикатора Supertrend и исполняет сделки сразу после подтвержденной смены тренда. Логика реализована явно и прозрачно. Каждое решение советника можно однозначно связать с четко определенным рыночным условием.

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


Логика сигналов Supertrend

Индикатор Supertrend всегда находится в одном из двух состояний: бычьем или медвежьем. В бычьем состоянии линия Supertrend строится ниже цены и служит динамическим уровнем поддержки. В медвежьем состоянии линия строится выше цены и служит динамическим уровнем сопротивления. Сигнал формируется только при переходе индикатора из одного состояния в другое.

Бычий сигнал возникает, когда последняя закрытая свеча закрывается выше верхней полосы индикатора Supertrend.

Bullish Signal

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

Медвежий сигнал формируется по той же логике в обратном направлении.

Bearish Signal

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

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

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


Торговые правила и проектные решения

После четкого определения логики сигналов Supertrend необходимо решить, как советник должен реагировать на них в реальных рыночных условиях. Цель этого проектного решения — не сложность, а контроль. Каждое торговое решение организовано так, чтобы обеспечить гибкость без ущерба для ясности и безопасности.

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

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

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

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

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

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

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


Подготовка основы советника

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

Предварительные требования и настройка среды

На данном этапе предполагается знание основ языка MQL5. Также предполагается уверенное владение платформой MetaTrader 5, включая подключение программ к графикам, настройку входных параметров и работу с основными модулями, такими как Тестер стратегий и Навигатор.

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

Этот советник использует индикатор Supertrend, разработанный в предыдущей статье. Для сохранения последовательности обучения полный исходный код индикатора снова приложен к этой статье в файле supertrend.mq5. Перед продолжением необходимо скачать этот файл и скомпилировать его локально.

Файл исходного кода индикатора следует разместить в каталоге по умолчанию: .../MQL5/Indicators. Настоятельно рекомендуется использовать структуру каталогов по умолчанию. Это позволяет избежать проблем с путями к файлам и гарантирует, что советник сможет правильно найти и загрузить индикатор во время выполнения программы.

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

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

Создание каркаса советника

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

//+------------------------------------------------------------------+
//|                                             supertrendExpert.mq5 |
//|          Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian |
//|                          https://www.mql5.com/ru/users/chachaian |
//+------------------------------------------------------------------+

#property copyright "Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian"
#property link      "https://www.mql5.com/ru/users/chachaian"
#property version   "1.00"

//+------------------------------------------------------------------+
//| Standard Libraries                                               |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>

//+------------------------------------------------------------------+
//| Custom Enumerations                                              |
//+------------------------------------------------------------------+
enum ENUM_TRADE_DIRECTION  
{ 
   ONLY_LONG, 
   ONLY_SHORT, 
   TRADE_BOTH 
};

enum ENUM_LOT_SIZE_INPUT_MODE 
{ 
   MODE_MANUAL, 
   MODE_AUTO 
};

enum ENUM_STOP_LOSS_MODE
{
   SL_MODE_NONE,
   SL_MODE_SWING_EXTREME,
   SL_MODE_SUPERTREND_VOLATILITY
};

//+------------------------------------------------------------------+
//| User input variables                                             |
//+------------------------------------------------------------------+
input group "Information"
input ulong magicNumber         = 254700680002;                 
input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT;

input group "Supertrend configuration parameters"
input int32_t atrPeriod         = 10;
input double  atrMultiplier     = 1.5;

input group "Trade and Risk Management"
input ENUM_TRADE_DIRECTION direction        = ONLY_LONG;
input ENUM_STOP_LOSS_MODE stopLossMode      = SL_MODE_SWING_EXTREME; 
input ENUM_LOT_SIZE_INPUT_MODE lotSizeMode  = MODE_AUTO;
input double riskPerTradePercent            = 1.0;
input double positionSize                   = 0.1;

//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
//--- Create a CTrade object to handle trading operations
CTrade Trade;

//--- Bid and Ask
double   askPrice;
double   bidPrice;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   //---  Assign a unique magic number to identify trades opened by this EA
   Trade.SetExpertMagicNumber(magicNumber);

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){

   //--- Notify why the program stopped running
   Print("Program terminated! Reason code: ", reason);
}

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

   //--- Retrieve current market prices for trade execution
   askPrice      = SymbolInfoDouble (_Symbol, SYMBOL_ASK);
   bidPrice      = SymbolInfoDouble (_Symbol, SYMBOL_BID);  
}

//--- UTILITY FUNCTIONS

//+------------------------------------------------------------------+

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

Заголовок файла и свойства

//+------------------------------------------------------------------+
//|                                             supertrendExpert.mq5 |
//|          Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian |
//|                          https://www.mql5.com/ru/users/chachaian |
//+------------------------------------------------------------------+

#property copyright "Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian"
#property link      "https://www.mql5.com/ru/users/chachaian"
#property version   "1.00"

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

Подключение стандартной библиотеки

//+------------------------------------------------------------------+
//| Standard Libraries                                               |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>

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

Пользовательские перечисления

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

//+------------------------------------------------------------------+
//| Custom Enumerations                                              |
//+------------------------------------------------------------------+
enum ENUM_TRADE_DIRECTION  
{ 
   ONLY_LONG, 
   ONLY_SHORT, 
   TRADE_BOTH 
};

enum ENUM_LOT_SIZE_INPUT_MODE 
{ 
   MODE_MANUAL, 
   MODE_AUTO 
};

enum ENUM_STOP_LOSS_MODE
{
   SL_MODE_NONE,
   SL_MODE_SWING_EXTREME,
   SL_MODE_SUPERTREND_VOLATILITY
};

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

Пользовательские входные переменные

Входные переменные предоставляют доступ ко всем настраиваемым аспектам работы советника через панель его настроек.

//+------------------------------------------------------------------+
//| User input variables                                             |
//+------------------------------------------------------------------+
input group "Information"
input ulong magicNumber         = 254700680002;                 
input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT;

input group "Supertrend configuration parameters"
input int32_t atrPeriod         = 10;
input double  atrMultiplier     = 1.5;

input group "Trade and Risk Management"
input ENUM_TRADE_DIRECTION direction        = ONLY_LONG;
input ENUM_STOP_LOSS_MODE stopLossMode      = SL_MODE_SWING_EXTREME; 
input ENUM_LOT_SIZE_INPUT_MODE lotSizeMode  = MODE_AUTO;
input double riskPerTradePercent            = 1.0;
input double positionSize                   = 0.1;

Информационная группа

magicNumber

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

timeframe

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

Параметры настройки индикатора Supertrend

atrPeriod

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

atrMultiplier

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

Управление торговлей и рисками

direction

Этот параметр определяет, сделки каких направлений разрешено открывать советнику. ONLY_LONG разрешает открытие только длинных позиций, ONLY_SHORT — только коротких позиций, а TRADE_BOTH — двунаправленную торговлю. Это полезно, когда субъективная оценка трейдера указывает на выраженную направленность рынка, позволяя советнику учитывать более широкий рыночный контекст.

stopLossMode

Этот параметр определяет, устанавливаются ли стоп-лоссы и каким образом. SL_MODE_NONE полностью отключает установку стоп-лосса. Позиции закрываются только при появлении противоположного сигнала Supertrend. SL_MODE_SWING_EXTREME устанавливает стоп-лосс на уровне максимума или минимума последней закрытой свечи с учетом недавней рыночной структуры. SL_MODE_SUPERTREND_VOLATILITY устанавливает стоп-лосс на уровне полосы Supertrend, динамически адаптируясь к волатильности.

lotSizeMode

Этот параметр определяет способ расчета размера позиции. В режиме MANUAL_MODE для всех сделок используется фиксированный размер лота. В режиме AUTO_MODE размер лота рассчитывается на основе баланса счета и процента риска. Это позволяет советнику автоматически изменять размер позиции по мере роста или уменьшения баланса счета.

riskPerTradePercent

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

positionSize

Это значение используется только при выборе ручного расчета размера лота. Советник будет открывать все позиции с этим фиксированным размером лота независимо от волатильности и расстояния до стоп-лосса.

Глобальные переменные

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

//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
//--- Create a CTrade object to handle trading operations
CTrade Trade;

//--- Bid and Ask
double   askPrice;
double   bidPrice;

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

Функции жизненного цикла программы

Функция OnInit вызывается один раз при загрузке советника.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   //---  Assign a unique magic number to identify trades opened by this EA
   Trade.SetExpertMagicNumber(magicNumber);

   return(INIT_SUCCEEDED);
}

Здесь торговому объекту присваивается магическое число. Эта строчка обеспечивает корректную принадлежность сделок советнику на протяжении всего времени его работы.

Функция OnDeinit срабатывает при удалении советника с графика или завершении работы терминала.

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){

   //--- Notify why the program stopped running
   Print("Program terminated! Reason code: ", reason);

}

Пока она только выводит причину завершения работы. Позднее она также будет выполнять очистку ресурсов.

Функция OnTick выполняется при поступлении новых ценовых данных.

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

   //--- Retrieve current market prices for trade execution
   askPrice      = SymbolInfoDouble (_Symbol, SYMBOL_ASK);
   bidPrice      = SymbolInfoDouble (_Symbol, SYMBOL_BID); 
   
}

На данном этапе функция только обновляет цены Bid и Ask. Это сделано намеренно. Торговая логика будет добавляться постепенно, чтобы поведение системы оставалось предсказуемым и легко поддавалось отладке.

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


Реализация логики обнаружения сигналов Supertrend

На данном этапе разработки внимание переключается с настройки и структуры на обнаружение сигналов. Поскольку этот советник предназначен для исполнения сделок непосредственно по сигналам индикатора Supertrend, сам индикатор должен стать ключевой частью алгоритма. Советник не пытается внутренне воспроизводить Supertrend. Вместо этого он считывает сигналы непосредственно из исходного индикатора и автоматически на них реагирует. Такой подход обеспечивает соответствие логики тому, что трейдеры видят на графике, и устраняет необходимость вручную исполнять сделки.

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

Первый шаг — встроить индикатор Supertrend в исполняемый файл советника с помощью директивы resource.

#resource "\\Indicators\\supertrend.ex5"

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

Объявление глобального хранилища данных индикатора

Для программной работы с индикатором Supertrend необходимо определить переменные для обращения к индикатору и хранения возвращаемых им данных.

//--- Supertrend values 
int    supertrendIndicatorHandle;
double upperBandValues[];
double lowerBandValues[];

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

Инициализация индикатора Supertrend

В функции инициализации индикатор Supertrend создается с помощью функции iCustom.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   ...

   // Initialize the Supertrend Indicator
   supertrendIndicatorHandle = iCustom(_Symbol, timeframe, "::Indicators\\supertrend.ex5", atrPeriod, atrMultiplier);
   if(supertrendIndicatorHandle == INVALID_HANDLE){
      Print("Error while initializing the Supertrend indicator", GetLastError());
      return(INIT_FAILED);
   }

   return(INIT_SUCCEEDED);
}

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

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

По умолчанию массивы MQL5 хранят данные в порядке возрастания: сначала идут более старые значения. Для торговой логики это неудобно, поскольку приходится часто обращаться к последним значениям.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   ...

   //--- Treat the following arrays as timeseries (index 0 becomes the most recent bar)
   ArraySetAsSeries(upperBandValues, true);
   ArraySetAsSeries(lowerBandValues, true);

   return(INIT_SUCCEEDED);
}

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

Считывание значений буферов индикатора

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

//--- UTILITY FUNCTIONS

//+------------------------------------------------------------------+
//| Fetches recent Supertrend upper and lower band values            |
//+------------------------------------------------------------------+
void UpdateSupertrendBandValues(){

   //--- Get a few Supertrend upper band values
   int copiedUpper = CopyBuffer(supertrendIndicatorHandle, 5, 0, 5, upperBandValues);
   if(copiedUpper == -1)
   {
      Print("Error while copying Supertrend upper band values: ", GetLastError());
      return;
   }

   //--- Get a few Supertrend lower band values
   int copiedLower = CopyBuffer(supertrendIndicatorHandle, 6, 0, 5, lowerBandValues);
   if(copiedLower == -1)
   {
      Print("Error while copying Supertrend lower band values: ", GetLastError());
      return;
   }
   
   if(copiedUpper < 5 || copiedLower < 5){
      Print("Insufficient Supertrend indicator data!");
      return;
   }   
}

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

Обнаружение событий нового бара

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

//+------------------------------------------------------------------+
//| Function to check if there's a new bar on a given chart timeframe|
//+------------------------------------------------------------------+
bool IsNewBar(string symbol, ENUM_TIMEFRAMES tf, datetime &lastTm){

   datetime currentTm = iTime(symbol, tf, 0);
   if(currentTm != lastTm){
      lastTm       = currentTm;
      return true;
   }  
   return false;
}

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

//--- To help track new bar open
datetime lastBarOpenTime;

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

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   ...

   //--- Initialize global variables
   lastBarOpenTime = 0;

   return(INIT_SUCCEEDED);
}

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

Определение бычьих и медвежьих сигналов Supertrend

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

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

//+--------------------------------------------------------------------------------+
//| Detects a bullish Supertrend signal when price confirms an upward trend change |
//+--------------------------------------------------------------------------------+
bool IsSupertrendBullishSignal(){

   if(lowerBandValues[1] != EMPTY_VALUE && upperBandValues[2] != EMPTY_VALUE){
      return true;
   }
   
   return false;
}

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

//+---------------------------------------------------------------------------------+
//| Detects a bearish Supertrend signal when price confirms a downward trend change |
//+---------------------------------------------------------------------------------+
bool IsSupertrendBearishSignal(){

   if(upperBandValues[1] != EMPTY_VALUE && lowerBandValues[2] != EMPTY_VALUE){
      return true;
   }
   
   return false;
}

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

Проверка логики на тестовом примере

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

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

   ...
   
   //--- Run this block only when a new bar is detected on the selected timeframe
   if(IsNewBar(_Symbol, timeframe, lastBarOpenTime)){
   
      UpdateSupertrendBandValues();
      
      if(IsSupertrendBullishSignal()){   
         Print("Bullish Signal");
      }
      
      if(IsSupertrendBearishSignal()){
         Print("Bearish Signal");
      }      
   }   
}

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

Тестовые записи журнала

Такое поведение подтверждает, что советник правильно интерпретирует смену направления Supertrend, а логика обнаружения работает как задумано.

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


Разработка торговой логики и управления позициями

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

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

Проверка наличия открытых позиций на покупку

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

//+------------------------------------------------------------------+
//| To verify whether this EA currently has an active buy position.  |                                 |
//+------------------------------------------------------------------+
bool IsThereAnActiveBuyPosition(ulong magic){
   
   for(int i = PositionsTotal() - 1; i >= 0; i--){
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0){
         Print("Error while fetching position ticket ", GetLastError());
         continue;
      }else{
         if(PositionGetInteger(POSITION_MAGIC) == magic && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){
            return true;
         }
      }
   }
   
   return false;
}

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

Проверка наличия открытых позиций на продажу

Далее определяется вторая функция для обнаружения активных позиций на продажу.

//+------------------------------------------------------------------+
//| To verify whether this EA currently has an active sell position. |                                 |
//+------------------------------------------------------------------+
bool IsThereAnActiveSellPosition(ulong magic){
   
   for(int i = PositionsTotal() - 1; i >= 0; i--){
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0){
         Print("Error while fetching position ticket ", GetLastError());
         continue;
      }else{
         if(PositionGetInteger(POSITION_MAGIC) == magic && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL){
            return true;
         }
      }
   }
   
   return false;
}

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

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

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

//+------------------------------------------------------------------+
//| To close all position with a specified magic number              |   
//+------------------------------------------------------------------+
void ClosePositionsByMagic(ulong magic) {
    
    for (int i = PositionsTotal() - 1; i >= 0; i--) {
        ulong ticket = PositionGetTicket(i);
        if (PositionSelectByTicket(ticket)) {
            if (PositionGetInteger(POSITION_MAGIC) == magic) {
                ulong positionType = PositionGetInteger(POSITION_TYPE);
                double volume = PositionGetDouble(POSITION_VOLUME);
                if (positionType == POSITION_TYPE_BUY) {
                    Trade.PositionClose(ticket);
                } else if (positionType == POSITION_TYPE_SELL) {
                    Trade.PositionClose(ticket);
                }
            }
        }
    }    
}

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

Расчет размера позиции по проценту риска

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

//+------------------------------------------------------------------+
//| Calculates position size based on a fixed percentage risk of the account balance |
//+------------------------------------------------------------------+
double CalculatePositionSizeByRisk(double stopDistance){
   double amountAtRisk = (riskPerTradePercent / 100.0) * AccountInfoDouble(ACCOUNT_BALANCE);
   double contractSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_CONTRACT_SIZE);
   double volume       = amountAtRisk / (contractSize * stopDistance);
   return NormalizeDouble(volume, 2);
}

Расчет начинается с определения суммы, которой можно рисковать в одной сделке. Эта сумма определяется на основе баланса счета и заданного пользователем процента риска. Затем функция учитывает размер контракта торгуемого символа и расстояние до стоп-лосса. Это гарантирует, что рассчитанный объем отражает фактический уровень риска, а не фиксированные допущения. Наконец, объем нормализуется до допустимой точности торгового объема. Возвращаемое значение представляет размер позиции, согласующий уровень риска с рыночной волатильностью. Эта функция позволяет советнику автоматически адаптироваться к различным символам, размерам счетов и расстояниям до стоп-лосса без ручной перенастройки.

Расчет адаптивных уровней стоп-лосса

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

//+-----------------------------------------------------------------------------------------------+
//| Calculates the appropriate stop loss price based on position type and selected stop loss mode |
//+-----------------------------------------------------------------------------------------------+
double CalculateAdaptiveStopLossPrice(ENUM_POSITION_TYPE positionType){
   
   double stopLossPrice = 0.000000;
   
   if(positionType == POSITION_TYPE_BUY){
   
      if(stopLossMode == SL_MODE_SWING_EXTREME){
         stopLossPrice = NormalizeDouble(iLow(_Symbol, timeframe, 1), Digits());
      }
      
      if(stopLossMode == SL_MODE_SUPERTREND_VOLATILITY){
         stopLossPrice = NormalizeDouble(lowerBandValues[1], Digits());
      }
      
      if(stopLossMode == SL_MODE_NONE){
         stopLossPrice = NormalizeDouble(lowerBandValues[1], Digits());
      }      
   }
   
   if(positionType == POSITION_TYPE_SELL){
   
      if(stopLossMode == SL_MODE_SWING_EXTREME){
         stopLossPrice = NormalizeDouble(iHigh(_Symbol, timeframe, 1), Digits());
      }
      
      if(stopLossMode == SL_MODE_SUPERTREND_VOLATILITY){
         stopLossPrice = NormalizeDouble(upperBandValues[1], Digits());
      }
      
      if(stopLossMode == SL_MODE_NONE){
         stopLossPrice = NormalizeDouble(upperBandValues[1], Digits());
      }   
   }   
   return stopLossPrice;  
}

Функция получает тип предполагаемой позиции и выбирает цену стоп-лосса в соответствии с выбранным режимом стоп-лосса. Для позиций на покупку в режиме экстремумов свинга используется минимум предшествующей свечи, а в логике на основе волатильности — значение нижней полосы Supertrend на предшествующей свече. Для позиций на продажу применяется обратная логика: используется максимум предшествующей свечи или значение верхней полосы Supertrend на предшествующей свече. Если выбран режим без стоп-лосса, функция все равно возвращает уровень на основе Supertrend. Это сделано намеренно. Автоматический расчет размера позиции опирается на расстояние риска, а волатильность служит наиболее стабильным ориентиром.

Открытие позиций на покупку

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

//+------------------------------------------------------------------+
//| Function to open a market buy position                           |
//+------------------------------------------------------------------+
bool OpenBuy(double entryPrice, double stopLoss, double lotSize){
   
   if(lotSizeMode == MODE_AUTO){
      lotSize = CalculatePositionSizeByRisk(entryPrice - stopLoss);
   }
   
   if(stopLossMode == SL_MODE_NONE){
      if(!Trade.Buy(lotSize, _Symbol, entryPrice, 0.000000, 0.000000)){
         Print("Error while executing a market buy order: ", GetLastError());
         Print(Trade.ResultRetcode());
         Print(Trade.ResultComment());
         return false;
      }
   }else{
      if(!Trade.Buy(lotSize, _Symbol, entryPrice, stopLoss, 0.000000)){
         Print("Error while executing a market buy order: ", GetLastError());
         Print(Trade.ResultRetcode());
         Print(Trade.ResultComment());
         return false;
      }
   }
   return true;
}

Функция начинается с проверки, включен ли автоматический расчет размера лота. В этом случае она рассчитывает размер лота на основе разницы между ценой входа и уровнем стоп-лосса. Далее функция определяет, следует ли передавать стоп-лосс брокеру. Если режим стоп-лосса отключен, сделка открывается без стоп-лосса. В противном случае рассчитанный уровень стоп-лосса включается в торговый запрос. Все операции исполнения сделок выполняются объектом CTrade. Если исполнение ордера завершается ошибкой, в журнал выводится подробная информация для диагностики проблемы. При успешном исполнении возвращается true, подтверждая, что сделка корректно размещена.

Открытие позиций на продажу

Функция исполнения сделок на продажу добавляется непосредственно после функции исполнения сделок на покупку.

//+------------------------------------------------------------------+
//| Function to open a market sell position                          |
//+------------------------------------------------------------------+
bool OpenSel(double entryPrice, double stopLoss , double lotSize){
   
   if(lotSizeMode == MODE_AUTO){
      lotSize = CalculatePositionSizeByRisk(stopLoss - entryPrice);
   }
   
   if(stopLossMode == SL_MODE_NONE){
      if(!Trade.Sell(lotSize, _Symbol, entryPrice, 0.000000, 0.000000)){
         Print("Error while executing a market sell order: ", GetLastError());
         Print(Trade.ResultRetcode());
         Print(Trade.ResultComment());
         return false;
      }
   }else{
      if(!Trade.Sell(lotSize, _Symbol, entryPrice, stopLoss, 0.000000)){
         Print("Error while executing a market sell order: ", GetLastError());
         Print(Trade.ResultRetcode());
         Print(Trade.ResultComment());
         return false;
      }
   }
   
   return true;
}

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

Объединение всей логики в OnTick

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

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

   //--- Retrieve current market prices for trade execution
   askPrice      = SymbolInfoDouble (_Symbol, SYMBOL_ASK);
   bidPrice      = SymbolInfoDouble (_Symbol, SYMBOL_BID); 
   
   //--- Run this block only when a new bar is detected on the selected timeframe
   if(IsNewBar(_Symbol, timeframe, lastBarOpenTime)){
   
      UpdateSupertrendBandValues();
      
      if(IsSupertrendBullishSignal()){   
         if(IsThereAnActiveSellPosition(magicNumber)){
            ClosePositionsByMagic(magicNumber);
            Sleep(50);
         }
         if(direction == TRADE_BOTH || direction == ONLY_LONG){
            OpenBuy(askPrice, CalculateAdaptiveStopLossPrice(POSITION_TYPE_BUY), positionSize);
         }
      }
      
      if(IsSupertrendBearishSignal()){
         if(IsThereAnActiveBuyPosition(magicNumber)){
            ClosePositionsByMagic(magicNumber);
            Sleep(50);
         }
         if(direction == TRADE_BOTH || direction == ONLY_SHORT){
            OpenSel(bidPrice, CalculateAdaptiveStopLossPrice(POSITION_TYPE_SELL), positionSize);
         }
      }      
   }   
}

На каждом новом баре советник обновляет значения Supertrend и определяет направление тренда. При обнаружении бычьего сигнала сначала закрываются все активные позиции на продажу. Только после этого советник рассматривает возможность открытия сделки на покупку, если это допускает выбранное направление торговли. Для медвежьих сигналов применяется тот же процесс в обратном порядке. Такая структура обеспечивает строгую дисциплину направления торговли. Советник никогда не удерживает позиции противоположных направлений и не торгует против выявленного тренда.

Настройка внешнего вида графика

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

//+------------------------------------------------------------------+
//| This function configures the chart's appearance.                 |
//+------------------------------------------------------------------+
bool ConfigureChartAppearance()
{
   if(!ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrWhite)){
      Print("Error while setting chart background, ", GetLastError());
      return false;
   }
   
   if(!ChartSetInteger(0, CHART_SHOW_GRID, false)){
      Print("Error while setting chart grid, ", GetLastError());
      return false;
   }
   
   if(!ChartSetInteger(0, CHART_MODE, CHART_CANDLES)){
      Print("Error while setting chart mode, ", GetLastError());
      return false;
   }

   if(!ChartSetInteger(0, CHART_COLOR_FOREGROUND, clrBlack)){
      Print("Error while setting chart foreground, ", GetLastError());
      return false;
   }

   if(!ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, clrSeaGreen)){
      Print("Error while setting bullish candles color, ", GetLastError());
      return false;
   }
      
   if(!ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, clrBlack)){
      Print("Error while setting bearish candles color, ", GetLastError());
      return false;
   }
   
   if(!ChartSetInteger(0, CHART_COLOR_CHART_UP, clrSeaGreen)){
      Print("Error while setting bearish candles color, ", GetLastError());
      return false;
   }
   
   if(!ChartSetInteger(0, CHART_COLOR_CHART_DOWN, clrBlack)){
      Print("Error while setting bearish candles color, ", GetLastError());
      return false;
   }
   
   return true;
}

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

Наконец, логика настройки графика активируется в функции OnInit.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   ...
   
   //--- To configure the chart's appearance
   if(!ConfigureChartAppearance()){
      Print("Error while configuring chart appearance", GetLastError());
      return INIT_FAILED;
   }

   return(INIT_SUCCEEDED);
}

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


Тестирование и оценка результатов

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

Тестирование проводилось по золоту с использованием символа XAUUSD. В тесте использовался часовой таймфрейм H1, а период тестирования охватывал один год — с 1 января по 31 декабря 2025 года. Этот период обеспечивает сбалансированную выборку различных рыночных условий, включая трендовые фазы и фазы консолидации.

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

Для полной воспроизводимости теста приложены два вспомогательных файла. Первый файл, configurations.ini, содержит конфигурацию среды Тестера стратегий, а второй, parameters.set, — точные входные параметры, использованные при тестировании. Вместе эти файлы позволяют воссоздать те же условия без ручного подбора параметров.

Результаты тестирования заслуживают внимания.

Отчет о тестировании

При начальном балансе 10 000 долларов США система получила чистую прибыль 21 380,79 доллара США. Это соответствует доходности более 200% за период тестирования продолжительностью один год. Несмотря на относительно низкую долю прибыльных сделок — 34,92%, кривая эквити оставалась плавной и стабильной на протяжении всего теста.

Equity Curve

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

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

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


Заключение

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

Полностью автоматизированная торговая система на основе Supertrend была разработана поэтапно: от интерпретации сигналов до исполнения сделок, управления рисками и тестирования. Результатом становится бесплатный настраиваемый советник, который можно использовать без изменений или доработать для реализации новых идей. Его гибкость позволяет использовать различные модели стоп-лосса, подходы к расчету размера позиции и фильтры направлений торговли без изменения исходного кода. Благодаря этому он подходит не только для торговых экспериментов, но и для структурированного исследования стратегий.

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

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

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



Имя файла Описание
1 supertrend.mq5 Исходный файл индикатора Supertrend используется для расчета направления тренда и ценовых полос на основе волатильности. Советник напрямую считывает его значения для формирования торговых сигналов.
2 supertrendExpert.mq5 Исходный файл советника, автоматизирующий исполнение торговых операций на основе сигналов Supertrend, правил управления рисками и заданных пользователем входных параметров.
3 configurations.ini Файл конфигурации Тестера стратегий определяет среду тестирования. Он позволяет точно воспроизвести условия тестирования на исторических данных, использованные в статье.
4 parameters.set Файл набора входных параметров, содержащий все настройки советника, применявшиеся при тестировании на исторических данных, включая параметры риска, направление торговли и режим работы стоп-лосса.

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

Прикрепленные файлы |
supertrend.mq5 (17.92 KB)
configurations.ini (1.38 KB)
parameters.set (1.26 KB)
Использование Экономического календаря MQL5 для фильтрации новостей (Часть 1): Реализация временных окон до и после новостей в MQL5 Использование Экономического календаря MQL5 для фильтрации новостей (Часть 1): Реализация временных окон до и после новостей в MQL5
Мы разработаем новостной фильтр на основе календаря на языке MQL5 без веб-запросов и внешних DLL. В части 1 рассматриваются загрузка и кэширование событий, сопоставление символов с валютами, фильтрация по уровню важности, определение окон до и после новостей, блокировка открытия новых сделок во время активного новостного периода и опциональное закрытие позиций перед новостью. В результате получается настраиваемый защитный механизм, совместимый с требованиями проп-фирм, который сокращает число ошибочных пауз в торговле и защищает входы в сделки в периоды волатильности.
Интеграция внешних приложений с использованием OAuth MQL5 Community Интеграция внешних приложений с использованием OAuth MQL5 Community
Узнайте, как добавить функцию "Войти с помощью MQL5" в ваше Android-приложение с помощью процесса для кода авторизации OAuth 2.0. В этом руководстве рассматриваются регистрация приложения, эндпоинты, URI перенаправления, Custom Tabs, обработка диплинков, а также бэкенд на PHP, который обменивает код на токен доступа по HTTPS. Вы реализуете аутентификацию реальных пользователей MQL5 и получите доступ к данным их профиля, таким как ранг и репутация.
Нейросети в трейдинге: Управление риском через распределение результатов (AC-SRM) Нейросети в трейдинге: Управление риском через распределение результатов (AC-SRM)
Средняя доходность не показывает, как распределены возможные прибыли и убытки, а значит, скрывает часть риска торговой стратегии. AC-SRM переносит этот риск в сам процесс обучения: политика оценивается по распределению результатов через спектральную меру риска, а не только по среднему значению. Практическую реализацию начинаем с OpenCL-кернела FQF_DistributionTargetGradient, который выбирает ближайшего к цели представителя распределения и формирует градиенты его значения и вероятности, подготавливая распределительный Критик для дальнейшей риск-ориентированной оптимизации.
Отслеживание динамики счета: Визуализация баланса, средств счета и плавающей прибыли/убытка в MQL5 Отслеживание динамики счета: Визуализация баланса, средств счета и плавающей прибыли/убытка в MQL5
Создайте пользовательский индикатор для MT5, который обрабатывает всю историю сделок и отрисовывает начальный баланс, текущий баланс, средства счета и плавающую прибыль/убыток в виде непрерывных кривых. Он обновляется на каждом баре, агрегирует позиции по всем символам и исключает внешние зависимости за счет локального кэширования. Используйте его для анализа расхождений между средствами счета и балансом, сопоставления реализованных и нереализованных результатов, анализа того, когда именно вы принимали на себя риск.