Мастер-класс по созданию пользовательских индикаторов (Часть 1): Разработка индикатора Supertrend на MQL5
Введение
Представьте: начало 2022 года. Криптозима в разгаре, а Bitcoin только что опустился ниже $20,000. Паника повсюду: форумы заполнены отчаянием, портфели в глубоком минусе, а большинство трейдеров либо парализованы страхом, либо в панике продают на минимуме.
Однако на спокойном графике одна толстая линия меняет цвет с красного на зеленый и проходит под ценой, словно сообщая: "Спокойно, нисходящий тренд только что закончился". Это была линия индикатора Supertrend.
Пока большинство трейдеров гадало, индикатор давал ясный и однозначный сигнал: тренд изменился. Более того, те, кто доверял индикатору, не просто пережили рыночный шум – они поймали все последующее движение.
Несмотря на простоту и давнюю популярность, Supertrend остается одним из наиболее неправильно понимаемых и плохо реализованных индикаторов на платформах для розничных трейдеров. Многие версии перерисовываются, непоследовательно ведут себя на реальном рынке или скрывают внутреннюю логику за непрозрачными вычислениями. Для разработчиков это создает хроническую проблему: трейдеры продолжают запрашивать инструменты на основе Supertrend, однако надежные, расширяемые и хорошо документированные реализации встречаются редко.
Эта статья призвана решить эту проблему. Вместо того чтобы рассматривать Supertrend как черный ящик, разработаем индикатор Supertrend без перерисовки на языке MQL5 с нуля, уделяя внимание ясности, корректности и профессиональной структуре. Индикатор будет предоставлять внутренние буферы в документированном виде, удобном для разработчиков. Это делает его подходящим не только для визуального анализа, но и для коммерческих советников, стратегий и дальнейшего расширения.
В то же время студенты и будущие разработчики MQL5 получат практические знания о чистой архитектуре индикатора, правильном управлении буферами и безопасных методах расчета для реального рынка. Эти навыки выходят далеко за рамки самого Supertrend.
Добро пожаловать в первый выпуск серии "Мастер-класс по созданию пользовательских индикаторов", где мы перестаем быть пассивными потребителями готовых инструментов и становимся создателями. Мы возьмем популярные индикаторы, разберем их, соберем заново и сделаем по-настоящему своими – без компромиссов с чужими фиксированными параметрами и неудобной визуализацией. Создавая их самостоятельно на языке MQL5, мы получаем полный контроль и гораздо более глубокое понимание принципов их работы.
Начнем наш мастер-класс с объяснения того, что представляет собой Supertrend и почему важно корректно его реализовать.
Что на самом деле представляет собой индикатор Supertrend
Прежде чем написать хотя бы одну строку кода MQL5, необходимо понять, что представляет собой индикатор Supertrend и чего он не делает.
Индикатор Supertrend впервые был представлен Оливье Себаном, который первоначально реализовал и опубликовал его на платформе графического анализа TradingView. С тех пор он стал одним из наиболее широко используемых трендовых инструментов на платформах для розничных трейдеров, особенно на рынках криптовалют, Forex и индексов.
По своей сути Supertrend представляет собой трендовый индикатор, основанный на волатильности. Он не предсказывает направление цены, не прогнозирует развороты и не пытается определить максимумы и минимумы. Вместо этого он отвечает на гораздо более простой и практичный вопрос: "Учитывая текущую волатильность, рынок сейчас находится в восходящем или нисходящем тренде?" Это достигается сочетанием следующих показателей:
- среднего истинного диапазона ATR для измерения волатильности;
- опорной точки середины ценового диапазона;
- динамической трейлинг-полосы, меняющей сторону при изменении тренда.
Когда цена остается выше трейлинг-полосы, индикатор предполагает наличие бычьего тренда и строит линию ниже цены. Когда цена закрывается ниже полосы, состояние тренда меняется, а линия перемещается выше цены, сигнализируя о медвежьем тренде.
Именно этот единственный переход линии выше или ниже цены делает сигналы Supertrend однозначными. Никаких осцилляций, конфликтующих сигналов и мучительных попыток интерпретации. Одна линия. Одно направление. Одно состояние. Благодаря этой простоте Supertrend стал особенно популярным в трендовых стратегиях, системах с трейлинг-стопами и при алгоритмическом принятии решений. Тем не менее многие интернет-обсуждения в основном посвящены торговым стратегиям, оптимизации параметров и сравнению эффективности. Эти темы хорошо освещены в других источниках и не рассматриваются в мастер-классе.
Для читателей, заинтересованных в более глубоком концептуальном объяснении, Investopedia предлагает надежный нейтральный обзор теории, лежащей в основе индикатора, и его применения.
Как будет выглядеть и работать наш индикатор Supertrend
Прежде чем приступать к коду, важно четко понимать, что именно создается и как индикатор должен работать на графике. Индикатор Supertrend полностью полагается на ATR для определения положения трендовой линии. Вместо создания собственного расчета используется высокооптимизированный индикатор ATR, уже встроенный в MetaTrader 5. Пользовательский индикатор Supertrend использует хэндл индикатора для получения значений ATR. Это позволяет сосредоточиться на логике тренда и визуализации, а не на расчетах волатильности.
Этот индикатор будет реализован как пользовательский индикатор MQL5 и отображен непосредственно в основном окне графика. В рабочей области (канвасе) графика будет использоваться белый фон для повышения контрастности и лучшей читаемости. В любой момент времени индикатор поддерживает одно внутреннее состояние, описывающее текущую рыночную среду. Эта среда может находиться только в одном из двух состояний: бычьем или медвежьем.
В бычьей среде под ценой строится тонкая линия цвета SeaGreen. Эта линия рассчитывается как средняя точка свечи минус значение ATR, умноженное на заданный пользователем множитель. Это позволяет линии динамически следовать за ценой по мере изменения волатильности. В то же время все свечи на графике окрашиваются в цвет SeaGreen. Это сразу визуально подтверждает восходящий тренд рынка.
В медвежьей среде все происходит зеркально. Тонкая черная линия строится над ценой, пока тренд не изменится. Все свечи также окрашиваются в черный цвет. Когда цена пробивает трейлинг-полосу в противоположном направлении, состояние тренда меняется, а индикатор обновляется соответственно.
Теперь взгляните на скриншот ниже. На нем показан окончательный вид индикатора на реальном графике. Иными словами, состояние тренда передается без дополнительных индикаторов и сложной интерпретации. Одна линия. Один цвет. Одно направление.

По умолчанию индикатор рассчитывается и отображается на таймфрейме графика. На этом этапе логика нескольких таймфреймов еще не вводится, чтобы сохранить предсказуемость и прозрачность поведения.
Для управления чувствительностью Supertrend доступны два входных параметра:
- atrPeriod, определяющий период анализа ATR;
- atrMultiplier, определяющий, насколько близко линия Supertrend следует за ценой.
Наконец, и это особенно важно, данная реализация не будет перерисовываться. После закрытия бара и принятия решения о тренде это решение не изменяется задним числом. Это делает индикатор подходящим не только для ручного анализа, но и для использования в советниках, генераторах сигналов и коммерческих торговых системах.
Реализация Supertrend на MQL5
Теперь пора перейти к практической работе. В этом разделе концепция Supertrend реализуется в виде работающего пользовательского индикатора на языке MQL5.
Перед продолжением необходимо выполнить несколько основных требований. Необходимо уже иметь базовое представление о программировании на языке MQL5. Также необходимо уверенно ориентироваться в десктопном терминале MetaTrader 5, включая прикрепление индикаторов к графикам. Наконец, необходимо быть знакомым с MetaEditor и уметь создавать новые файлы, компилировать код, проверять ошибки и проводить отладку при необходимости. Если эти требования выполнены, можно продолжать.
Полный исходный код готового индикатора прилагается к этой статье. Для достижения наилучших результатов настоятельно рекомендуется писать код одновременно с чтением статьи. Самостоятельное написание кода и сравнение его с приложенным исходным кодом – один из наиболее эффективных способов изучения разработки индикаторов. Если по ходу работы возникают ошибки, результат всегда можно сверить с приложенной реализацией.
Создание начальной структуры индикатора
Откройте MetaEditor и создайте новый пустой файл пользовательского индикатора. Назовите его supertrend.mq5, затем вставьте в него следующий исходный код.
//+------------------------------------------------------------------+ //| supertrend.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" //+------------------------------------------------------------------+ //| User input variables | //+------------------------------------------------------------------+ input group "Information" input int32_t atrPeriod = 10; input double atrMultiplier = 1.5; //+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT; //+------------------------------------------------------------------+ //| Indicator buffers | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Custom indicator 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; } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int32_t rates_total, const int32_t 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 int32_t &spread[]) { //--- This block is executed when the indicator is initially attached to a chart if(prev_calculated == 0){ } //--- This block is executed on every new bar open if(prev_calculated != rates_total && prev_calculated != 0){ } return rates_total; } //+------------------------------------------------------------------+ //| Deinitiatialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason){ //--- } //--- CUSTOM UTILITY FUNCTIONS //+------------------------------------------------------------------+ //| 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_LINE)){ 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, clrWhite)){ Print("Error while setting bullish candles color, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, clrWhite)){ 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; } //+------------------------------------------------------------------+
Этот файл служит основой для полного индикатора Supertrend. На первый взгляд файл может показаться большим, но он специально структурирован так, чтобы код оставался упорядоченным, читаемым и легко расширяемым. Давайте разберем его по разделам.
Свойства файла и метаданные
В самом начале определяются метаданные индикатора.
//+------------------------------------------------------------------+ //| supertrend.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 и помогают пользователям идентифицировать индикатор, его автора и происхождение. Хотя этот раздел не влияет на логику, он соответствует хорошей профессиональной практике, особенно для индикаторов, которые впоследствии могут публично распространяться или продаваться на коммерческой основе.
Пользовательские входные параметры
Далее определяются пользовательские входные параметры. Это значения, которые трейдер может изменять непосредственно в окне настроек индикатора.
//+------------------------------------------------------------------+ //| User input variables | //+------------------------------------------------------------------+ input group "Information" input int32_t atrPeriod = 10; input double atrMultiplier = 1.5;
Здесь задаются два входных параметра. Период ATR определяет, как измеряется волатильность. Множитель ATR определяет чувствительность линии Supertrend к движению цены. Вместе эти параметры позволяют пользователю точно настроить индикатор без изменения кода. По мере развития индикатора в этот раздел будут добавлены все настраиваемые пользователем параметры.
Глобальные переменные
В разделе глобальных переменных задаются значения, используемые несколькими функциями. Пока определяется только переменная таймфрейма, которая по умолчанию равна таймфрейму текущего графика.
//+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT;По мере развития этот раздел будет дополнен хэндлами индикаторов, переменными для отслеживания состояния тренда и другими общими величинами, необходимыми для расчетов.
Буферы индикатора
//+------------------------------------------------------------------+ //| Indicator buffers | //+------------------------------------------------------------------+
Этот раздел пока намеренно оставлен пустым. Позже в статье будут объявлены и привязаны все буферы, используемые для хранения свечных данных, полос Supertrend и состояний тренда. Размещение объявлений буферов в этом разделе упрощает структуру и предотвращает загромождение других частей кода.
Функция OnInit
//+------------------------------------------------------------------+ //| Custom indicator 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; }
Функция OnInit выполняется один раз при подключении индикатора к графику. Ее основная роль – инициализация и настройка.
В данном случае сначала настраивается внешний вид графика вызовом вспомогательной функции ConfigureChartAppearance. Если эту настройку по какой-либо причине не удается выполнить, инициализация индикатора корректно прерывается.
Настройка внешнего вида графика
Функция ConfigureChartAppearance подготавливает канвас графика для индикатора 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_LINE)){ 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, clrWhite)){ Print("Error while setting bullish candles color, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, clrWhite)){ 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; }
Функция задает белый фон, удаляет сетку, настраивает цвета свечей и обеспечивает визуальное различие бычьих и медвежьих движений. Это создает чистую высококонтрастную среду, в которой линия Supertrend и цветные свечи четко выделяются.
Каждая настройка применяется с проверкой результата ее выполнения. Если изменение графика не выполняется, функция сообщает об ошибке и прекращает работу. Это облегчает отладку и предотвращает скрытые сбои.
Функция OnCalculate
В функции OnCalculate выполняются все расчеты индикатора. Она вызывается при поступлении новых ценовых данных.
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int32_t rates_total, const int32_t 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 int32_t &spread[]) { //--- This block is executed when the indicator is initially attached to a chart if(prev_calculated == 0){ } //--- This block is executed on every new bar open if(prev_calculated != rates_total && prev_calculated != 0){ } return rates_total; }
Пока выделяются два логических сценария. Первый сценарий возникает при первом подключении индикатора к графику.
//--- This block is executed when the indicator is initially attached to a chart if(prev_calculated == 0){ }
Второй сценарий возникает при формировании новых баров.
//--- This block is executed on every new bar open if(prev_calculated != rates_total && prev_calculated != 0){ }
Эта структура позволяет четко отделить логику инициализации от текущих расчетов, что особенно важно для индикаторов без перерисовки, таких как Supertrend.
Функция OnDeinit
//+------------------------------------------------------------------+ //| Deinitiatialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason){ //--- }
Функция OnDeinit вызывается при удалении индикатора с графика. Сейчас функция пуста, но она предусмотрена для корректной очистки, если она потребуется позже. По мере добавления хэндлов индикаторов и динамических объектов эта функция будет использоваться для освобождения ресурсов.
Раздел вспомогательных функций
Наконец, все вспомогательные и служебные функции группируются внизу файла.
//--- CUSTOM UTILITY FUNCTIONS
---
Это сохраняет читаемость основной логики индикатора и размещает повторно используемый функционал в одном месте. По мере развития индикатора сюда будут добавляться дополнительные служебные функции без загромождения основной логики.
Инициализация индикатора ATR
Как упоминалось ранее, индикатор Supertrend основан на среднем истинном диапазоне (ATR). Поскольку MetaTrader 5 уже предоставляет надежный, хорошо проверенный индикатор ATR, создавать его с нуля не требуется. Вместо этого значения ATR считываются непосредственно из терминала и интегрируются в логику индикатора.
Для этого сначала требуются две глобальные переменные. Первая переменная – хэндл индикатора. Этот хэндл представляет собой активное соединение между пользовательским индикатором и встроенным индикатором ATR, работающим внутри терминала. Вторая переменная – динамический массив для хранения значений ATR, вычисленных MetaTrader.
Они объявляются в глобальной области видимости следующим образом:
int atrHandle; double atrValues [];
atrHandle содержит ссылку на индикатор ATR, а atrValues[] хранит значения ATR, возвращаемые терминалом. Глобальное объявление позволяет обращаться к значениям ATR в любом месте логики индикатора, как при инициализации, так и во время расчетов.
Создание хэндла индикатора ATR
После объявления переменных индикатор ATR инициализируется в функции OnInit.
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... //--- Initialize the ATR indicator atrHandle = iATR(_Symbol, timeframe, atrPeriod); if(atrHandle == INVALID_HANDLE){ Print("Error while initializing the ATR indicator ", GetLastError()); return(INIT_FAILED); } return INIT_SUCCEEDED; }
Для этого используется функция iATR. Функция указывает MetaTrader, какой символ использовать, какой таймфрейм читать и какой период применять при расчете ATR. В данном случае мы используем текущий символ, текущий таймфрейм и заданный пользователем период ATR.
При успешном вызове iATR возвращает действительный хэндл. При ошибке возвращается недействительный хэндл. Поэтому возвращаемое значение проверяется сразу. Если хэндл недействителен, выводится сообщение об ошибке, а загрузка индикатора прекращается. Это предотвращает выполнение логики без действительных данных ATR, которое впоследствии привело бы к неправильным результатам.
На этом этапе индикатор ATR работает в фоновом режиме, а MetaTrader готов предоставить значения ATR по запросу.
Освобождение индикатора ATR
Каждый созданный хэндл индикатора необходимо освободить при удалении индикатора с графика. Это выполняется в функции OnDeinit.
//+------------------------------------------------------------------+ //| Deinitiatialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason){ //--- Release ATR if(atrHandle != INVALID_HANDLE){ IndicatorRelease(atrHandle); } }
Здесь проверяется, действителен ли хэндл ATR. Если хэндл действителен, он освобождается с помощью IndicatorRelease. Этот шаг важен для управления памятью. Это гарантирует, что MetaTrader освободит ресурсы, используемые индикатором ATR, когда индикатор Supertrend больше не потребуется. Хотя MetaTrader хорошо управляет ресурсами, явное освобождение хэндлов считается хорошей практикой и помогает поддерживать код чистым и профессиональным.
Устранение предупреждений компиляции
На этом этапе компиляция индикатора вызывает несколько предупреждений. Эти предупреждения ожидаемы и указывают на то, что некоторые необходимые свойства еще не определены. Первое предупреждение сообщает, что свойство окна индикатора не указано. В MetaTrader индикаторы должны явно указывать, где они будут отображаться.
Существует два распространенных типа отображения. Некоторые индикаторы отображаются непосредственно на ценовом графике, например скользящие средние и полосы Боллинджера. Другие отображаются в отдельном подокне ниже графика, например RSI и ATR.
Поскольку Supertrend – индикатор, накладываемый поверх графика, который следует за ценой, он должен отображаться непосредственно в основном окне графика. Это объявляется добавлением следующей директивы:
#property indicator_chart_window
После добавления директивы первое предупреждение исчезает.
Знакомство с графическими построениями
Второе предупреждение сообщает, что графическое построение индикатора не определено. Графическое построение – это визуальный элемент, который MetaTrader отображает на графике, используя данные из буферов индикатора. Каждое графическое построение представляет один визуальный элемент, например линию, гистограмму или цветные свечи. MQL5 поддерживает до 18 различных типов графических построений, предоставляя разработчикам гибкость в визуализации данных индикатора. Каждое графическое построение должно быть явно объявлено, чтобы терминал знал, сколько визуальных элементов требуется подготовить.
В индикаторе Supertrend планируется использовать три графических построения. Одно графическое построение будет использоваться для свечей с пользовательской окраской, а два – для линий Supertrend. Для этого добавляется следующая директива:
#property indicator_plots 3
После добавления этой директивы второе предупреждение исчезает.
Буферы индикаторов и их назначение
После объявления количества графических построений MetaTrader выводит еще одно предупреждение о недостаточном размере буфера индикатора. Буферы индикатора – это специальные массивы для хранения данных, которые затем отображаются на графике. Каждый буфер содержит один поток данных, например цены открытия, значения линий или индексы цветов. MetaTrader автоматически считывает данные из этих буферов и использует их содержимое для отрисовки соответствующих графических построений.
Поскольку индикатор Supertrend использует несколько потоков данных, включая значения свечей, цвета тренда, значения полос и внутренние состояния тренда, необходимо заранее зарезервировать достаточно буферов. Для этого объявляется общее число используемых буферов:
#property indicator_buffers 8
Это указывает MetaTrader выделить до 8 буферов индикатора. После добавления этой директивы все предупреждения компиляции исчезают.
Объявление массивов буферов индикатора
После задания числа буферов можно объявить массивы, которые будут использоваться как буферы индикатора. Эти массивы должны иметь тип double и быть объявлены в глобальной области видимости. Они объявляются как динамические массивы, поскольку MetaTrader автоматически изменяет их размер в зависимости от количества доступных баров на графике. Объявляются буферы для пользовательских свечных данных, полос Supertrend и внутреннего состояния тренда.
//+------------------------------------------------------------------+ //| Indicator buffers | //+------------------------------------------------------------------+ double bufCandleOpen[]; double bufCandleHigh[]; double bufCandleLow[]; double bufCandleClose[]; double bufCandleTrendColor[]; double bufSupertrendUpperBand[]; double bufSupertrendLowerBand[]; double bufTrendState[];
На этом этапе объявляются только массивы. Однако одного лишь объявления массивов недостаточно. На следующем шаге каждый массив привязывается к конкретному индексу буфера внутри функции OnInit, чтобы MetaTrader распознал его как буфер индикатора.
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... //--- Bind arrays to indicator buffers SetIndexBuffer(0, bufCandleOpen, INDICATOR_DATA); SetIndexBuffer(1, bufCandleHigh, INDICATOR_DATA); SetIndexBuffer(2, bufCandleLow, INDICATOR_DATA); SetIndexBuffer(3, bufCandleClose, INDICATOR_DATA); SetIndexBuffer(4, bufCandleTrendColor, INDICATOR_COLOR_INDEX); SetIndexBuffer(5, bufSupertrendUpperBand, INDICATOR_DATA); SetIndexBuffer(6, bufSupertrendLowerBand, INDICATOR_DATA); SetIndexBuffer(7, bufTrendState, INDICATOR_DATA); return INIT_SUCCEEDED; }
На этом этапе все буферы индикатора уже объявлены и корректно связаны. Эти буферы служат хранилищами для свечей, полос Supertrend и состояний тренда. Однако на данный момент они не содержат значимых данных. Пока они не будут заполнены структурированным образом, на графике ничего не отрисовывается.
Для заполнения этих буферов реализуется алгоритм Supertrend. Как и у большинства индикаторов MQL5, основная логика расчетов находится внутри функции OnCalculate. Эта функция выполняется всякий раз, когда в терминале становятся доступны новые ценовые данные.
Наша цель состоит из двух частей. Сначала вычисляются значения Supertrend на основе цены и ATR. Во-вторых, свечи окрашиваются в соответствии с обнаруженным трендом. Бычьи свечи отображаются в цвете SeaGreen, а медвежьи – в черном цвете. Для окрашивания свечей определяется простая цветовая палитра.
#property indicator_color1 clrBlack, clrSeaGreen
Буфер цвета использует числовые индексы для сопоставления с этими цветами. Значение 0 соответствует черному цвету, а значение 1 – цвету SeaGreen.
Предотвращение дублирования кода с помощью вспомогательных функций
При построении свечей одни и те же присваивания буферов повторяются многократно. Размещение этой логики непосредственно в коде быстро приведет к дублированию и снижению читаемости. Чтобы избежать этого, определяются две вспомогательные функции. Первая функция заполняет буферы для бычьей свечи и присваивает индекс бычьего цвета.
//+---------------------------------------------------------------------------------------------------+ //| Populates candle buffers for a bullish bar and assigns the bullish trend color at the given index | //+---------------------------------------------------------------------------------------------------+ void SetBullishCandle(int index, double &open[], double &high[], double &low[], double &close[]){ bufCandleOpen [index] = open [index]; bufCandleHigh [index] = high [index]; bufCandleLow [index] = low [index]; bufCandleClose[index] = close[index]; bufCandleTrendColor[index] = 1; }
В этой функции значения открытия, максимума, минимума и закрытия указанного бара копируются в буферы свечей индикатора. Затем буферу цвета тренда присваивается значение 1, соответствующее бычьему цвету. Вторая функция выполняет ту же задачу для медвежьих свечей.
//+---------------------------------------------------------------------------------------------------+ //| Populates candle buffers for a bearish bar and assigns the bearish trend color at the given index | //+---------------------------------------------------------------------------------------------------+ void SetBearishCandle(int index, double &open[], double &high[], double &low[], double &close[]){ bufCandleOpen [index] = open [index]; bufCandleHigh [index] = high [index]; bufCandleLow [index] = low [index]; bufCandleClose[index] = close[index]; bufCandleTrendColor[index] = 0; }
Единственное отличие заключается в том, что буферу цвета присваивается значение 0, указывающее на медвежью свечу. Эти две функции позволяют последовательно создавать и окрашивать свечи, одновременно сохраняя основную логику Supertrend читаемой и компактной.
Безопасная работа с массивами цен
Функция OnCalculate предоставляет массивы ценовых рядов, а именно open, high, low и close. Эти массивы являются константными и не могут передаваться по ссылке в пользовательские функции. Чтобы обойти это ограничение, внутри OnCalculate создаются локальные копии этих массивов.
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int32_t rates_total, ... { //--- Temporary buffers used to store price data for rendering custom colored candles double sOpen []; double sHigh []; double sLow []; double sClose[]; ... return rates_total; }
Эти массивы служат рабочими буферами. В них копируются ценовые данные, после чего они безопасно передаются вспомогательным функциям без изменения исходного ценового ряда.
Начальный расчет при подключении индикатора
При первом подключении индикатора к графику параметр prev_calculated имеет значение ноль. Это означает, что предыдущих расчетов нет и требуется обработать все доступные исторические данные. Это состояние определяется следующим условием:
if(prev_calculated == 0)
Внутри этого блока все буферы индикатора сначала инициализируются значением EMPTY_VALUE.
//--- This block is executed when the indicator is initially attached to a chart if(prev_calculated == 0){ //--- Start with clean buffers at first calculation ArrayInitialize(bufCandleOpen, EMPTY_VALUE); ArrayInitialize(bufCandleHigh, EMPTY_VALUE); ArrayInitialize(bufCandleLow, EMPTY_VALUE); ArrayInitialize(bufCandleClose, EMPTY_VALUE); ArrayInitialize(bufSupertrendUpperBand, EMPTY_VALUE); ArrayInitialize(bufSupertrendLowerBand, EMPTY_VALUE); }
В MQL5 значение EMPTY_VALUE дает терминалу указание ничего не отрисовывать по этому индексу. Это поведение полезно для полос Supertrend, поскольку в любой момент времени, в зависимости от направления тренда, видна только одна полоса.
Определение и инициализация состояний тренда
Логика Supertrend основана на направлении тренда. На любом баре тренд может быть бычьим, медвежьим или еще формирующимся. Для ясного представления этих состояний определяются три константы:
const double TREND_BULLISH = 1.0; const double TREND_BEARISH = 0.0; const double TREND_NEUTRAL = -1.0;
Эти значения хранятся в отдельном буфере состояния тренда. Перед началом расчетов весь буфер инициализируется нейтральным состоянием. Это гарантирует, что в начале алгоритм считает тренд отсутствующим.
Копирование ценовых данных и проверка истории
Все еще внутри блока начального расчета массивы цен терминала копируются в локальные рабочие буферы:
//--- This block is executed when the indicator is initially attached to a chart if(prev_calculated == 0){ ... //--- Copy price data into local working buffers to safely manipulate candle values without altering the original price arrays ArrayCopy(sOpen, open); ArrayCopy(sHigh, high); ArrayCopy(sLow, low); ArrayCopy(sClose, close); }
Далее проверяется, достаточно ли исторических данных для расчета ATR.
//--- This block is executed when the indicator is initially attached to a chart if(prev_calculated == 0){ ... //--- Ensure sufficient historical data is available to calculate the ATR period. if(rates_total < atrPeriod){ Print("Insufficient bars to initialize Supertrend: ATR period requires more historical data."); return rates_total; } }
Поскольку Supertrend зависит от ATR, для продолжения требуется как минимум atrPeriod баров. Если данных недостаточно, функция завершается и ожидает загрузки большего числа баров.
Получение значений ATR
Полосы Supertrend рассчитываются на основе значений ATR. Вся серия ATR извлекается с помощью CopyBuffer:
//--- This block is executed when the indicator is initially attached to a chart if(prev_calculated == 0){ ... //--- Get all ATR values int numberOfCopiedATRValues = CopyBuffer(atrHandle, 0, 0, rates_total, atrValues); if(numberOfCopiedATRValues == -1){ Print("Error while copying ATR values: ", GetLastError()); return rates_total; } }
Если эта операция завершается ошибкой, обработка прекращается, чтобы избежать работы с недействительными данными.
Вычисление Supertrend на исторических барах
После выполнения всех предварительных условий выполняется перебор исторических баров для вычисления значений Supertrend.
//--- This block is executed when the indicator is initially attached to a chart if(prev_calculated == 0){ ... //--- Iterate through historical price data to calculate Supertrend values starting from the first valid ATR window. for(int i = atrPeriod - 1; i < rates_total - 1; i++){ //--- Calculate the current bar midpoint and derive the raw Supertrend upper and lower bands using the ATR multiplier double barMidpoint = (high[i] + low[i]) / 2.0; double upperBandValue = barMidpoint + atrValues[i] * atrMultiplier; double lowerBandValue = barMidpoint - atrValues[i] * atrMultiplier; //--- Initialize the first valid Supertrend bands once enough ATR data is available and skip further processing for this bar if(i == (atrPeriod - 1)){ bufSupertrendUpperBand[atrPeriod - 1] = upperBandValue; bufSupertrendLowerBand[atrPeriod - 1] = lowerBandValue; continue; } //--- Handle initial trend resolution when no prior trend has been established if(bufTrendState[i - 1] == TREND_NEUTRAL){ if(close[i] > bufSupertrendUpperBand[i - 1] || close[i] < bufSupertrendLowerBand[i - 1]){ if(close[i] > bufSupertrendUpperBand[i - 1]){ bufTrendState[i] = TREND_BULLISH; SetBullishCandle(i, sOpen, sHigh, sLow, sClose); bufSupertrendUpperBand[i] = EMPTY_VALUE; bufSupertrendLowerBand[i] = lowerBandValue; } if(close[i] < bufSupertrendLowerBand[i - 1]){ bufTrendState[i] = TREND_BEARISH; SetBearishCandle(i, sOpen, sHigh, sLow, sClose); bufSupertrendLowerBand[i] = EMPTY_VALUE; bufSupertrendUpperBand[i] = upperBandValue; } }else{ if(upperBandValue < bufSupertrendUpperBand[i - 1]){ bufSupertrendUpperBand[i] = upperBandValue; }else{ bufSupertrendUpperBand[i] = bufSupertrendUpperBand[i - 1]; } if(lowerBandValue > bufSupertrendLowerBand[i - 1]){ bufSupertrendLowerBand[i] = lowerBandValue; }else{ bufSupertrendLowerBand[i] = bufSupertrendLowerBand[i - 1]; } } } //--- Maintain or invalidate the bullish trend based on price interaction with the lower Supertrend band if(bufTrendState[i - 1] == TREND_BULLISH){ if(close[i] < bufSupertrendLowerBand[i - 1]){ bufTrendState[i] = TREND_BEARISH; SetBearishCandle(i, sOpen, sHigh, sLow, sClose); bufSupertrendLowerBand[i] = EMPTY_VALUE; bufSupertrendUpperBand[i] = upperBandValue; }else{ if(lowerBandValue > bufSupertrendLowerBand[i - 1]){ bufSupertrendLowerBand[i] = lowerBandValue; SetBullishCandle(i, sOpen, sHigh, sLow, sClose); bufTrendState[i] = TREND_BULLISH; }else{ bufSupertrendLowerBand[i] = bufSupertrendLowerBand[i - 1]; SetBullishCandle(i, sOpen, sHigh, sLow, sClose); bufTrendState[i] = TREND_BULLISH; } } } //--- Maintain or invalidate the bearish trend based on price interaction with the upper Supertrend band if(bufTrendState[i - 1] == TREND_BEARISH){ if(close[i] > bufSupertrendUpperBand[i - 1]){ bufTrendState[i] = TREND_BULLISH; SetBullishCandle(i, sOpen, sHigh, sLow, sClose); bufSupertrendUpperBand[i] = EMPTY_VALUE; bufSupertrendLowerBand[i] = lowerBandValue; }else{ if(upperBandValue < bufSupertrendUpperBand[i - 1]){ bufSupertrendUpperBand[i] = upperBandValue; SetBearishCandle(i, sOpen, sHigh, sLow, sClose); bufTrendState[i] = TREND_BEARISH; }else{ bufSupertrendUpperBand[i] = bufSupertrendUpperBand[i - 1]; SetBearishCandle(i, sOpen, sHigh, sLow, sClose); bufTrendState[i] = TREND_BEARISH; } } } } }
Цикл начинается с atrPeriod - 1, первого индекса, для которого ATR становится действительным. Для каждого бара рассчитывается средняя цена и определяются исходные верхняя и нижняя полосы Supertrend с использованием множителя ATR. На первом баре с допустимым значением ATR инициализируются обе полосы, после чего остальная логика пропускается. После этого начинается определение тренда.
Если предыдущий тренд нейтральный, взаимодействие цены с предыдущими полосами определяет, устанавливается ли бычий или медвежий тренд. После установления тренда активной остается только одна полоса, а противоположная скрывается с помощью EMPTY_VALUE.
Когда предыдущий тренд бычий, пересечение ценой нижней полосы вызывает медвежий разворот. В противном случае бычий тренд продолжается, а нижняя полоса корректируется или переносится вперед. Медвежий сценарий следует той же логике в обратном порядке. Закрытие выше верхней полосы сигнализирует о бычьем развороте, а продолжение тренда сужает или сохраняет верхнюю полосу. На каждом этапе свечи создаются и окрашиваются с помощью вспомогательных функций, обеспечивая визуальную согласованность.
Обновление Supertrend в реальном времени
После первоначального расчета OnCalculate снова вызывается при формировании нового бара. В этом случае prev_calculated не равно ни нулю, ни rates_total.
//--- This block is executed on every new bar open if(prev_calculated != rates_total && prev_calculated != 0){ //--- Copy price data into local working buffers to safely manipulate candle values without altering the original price arrays ArrayCopy(sOpen, open); ArrayCopy(sHigh, high); ArrayCopy(sLow, low); ArrayCopy(sClose, close); //--- Start with clean buffers bufSupertrendLowerBand[rates_total - 1] = EMPTY_VALUE; bufSupertrendLowerBand[rates_total - 2] = EMPTY_VALUE; bufSupertrendUpperBand[rates_total - 1] = EMPTY_VALUE; bufSupertrendUpperBand[rates_total - 2] = EMPTY_VALUE; //--- Get all ATR values int numberOfCopiedATRValues = CopyBuffer(atrHandle, 0, 0, rates_total, atrValues); if(numberOfCopiedATRValues == -1){ Print("Error while copying ATR values: ", GetLastError()); return rates_total; } //--- Define indices for the most recently closed bar and the bar immediately preceding it int elapsedBarIndex = rates_total - 2; int priorElapsedBarIndex = rates_total - 3; //--- Compute the Supertrend midpoint and derive the upper and lower bands using the ATR multiplier double barMidpoint = (high[elapsedBarIndex] + low[elapsedBarIndex]) / 2.0; double upperBandValue = barMidpoint + atrValues[elapsedBarIndex] * atrMultiplier; double lowerBandValue = barMidpoint - atrValues[elapsedBarIndex] * atrMultiplier; //--- Handle Supertrend continuation or reversal logic when the previous bar was bullish if(bufTrendState[priorElapsedBarIndex] == TREND_BULLISH){ if(close[elapsedBarIndex] < bufSupertrendLowerBand[priorElapsedBarIndex]){ bufTrendState[elapsedBarIndex] = TREND_BEARISH; SetBearishCandle(elapsedBarIndex, sOpen, sHigh, sLow, sClose); bufSupertrendUpperBand[elapsedBarIndex] = upperBandValue; bufSupertrendLowerBand[elapsedBarIndex] = EMPTY_VALUE; }else{ if(lowerBandValue > bufSupertrendLowerBand[priorElapsedBarIndex]){ bufSupertrendLowerBand[elapsedBarIndex] = lowerBandValue; bufSupertrendUpperBand[elapsedBarIndex] = EMPTY_VALUE; SetBullishCandle(elapsedBarIndex, sOpen, sHigh, sLow, sClose); bufTrendState[elapsedBarIndex] = TREND_BULLISH; }else{ bufSupertrendLowerBand[elapsedBarIndex] = bufSupertrendLowerBand[priorElapsedBarIndex]; bufSupertrendUpperBand[elapsedBarIndex] = EMPTY_VALUE; SetBullishCandle(elapsedBarIndex, sOpen, sHigh, sLow, sClose); bufTrendState[elapsedBarIndex] = TREND_BULLISH; } } } //--- Handle Supertrend continuation or reversal logic when the previous bar was bearish if(bufTrendState[priorElapsedBarIndex] == TREND_BEARISH){ if(close[elapsedBarIndex] > bufSupertrendUpperBand[priorElapsedBarIndex]){ bufTrendState[elapsedBarIndex] = TREND_BULLISH; SetBullishCandle(elapsedBarIndex, sOpen, sHigh, sLow, sClose); bufSupertrendLowerBand[elapsedBarIndex] = lowerBandValue; bufSupertrendUpperBand[elapsedBarIndex] = EMPTY_VALUE; }else{ if(upperBandValue < bufSupertrendUpperBand[priorElapsedBarIndex]){ bufSupertrendUpperBand[elapsedBarIndex] = upperBandValue; bufSupertrendLowerBand[elapsedBarIndex] = EMPTY_VALUE; SetBearishCandle(elapsedBarIndex, sOpen, sHigh, sLow, sClose); bufTrendState[elapsedBarIndex] = TREND_BEARISH; }else{ bufSupertrendUpperBand[elapsedBarIndex] = bufSupertrendUpperBand[priorElapsedBarIndex]; bufSupertrendLowerBand[elapsedBarIndex] = EMPTY_VALUE; SetBearishCandle(elapsedBarIndex, sOpen, sHigh, sLow, sClose); bufTrendState[elapsedBarIndex] = TREND_BEARISH; } } } }
Этот блок обновляет только последний закрытый бар, предотвращая перерисовку. Сначала ценовые данные снова копируются в локальные буферы, затем для последних двух баров очищаются значения полос Supertrend, чтобы избежать остаточных отрисовок. Значения ATR обновляются, после чего определяются два ключевых индекса: последний закрытый бар и бар перед ним. Используя эти индексы, вычисляются новые полосы Supertrend и применяется та же логика продолжения и разворота, что использовалась при обработке исторических данных. Обновляется только последний бар, что обеспечивает эффективность расчетов и стабильность результатов.
Настройка графических построений для отрисовки
На этом этапе все буферы индикатора корректно определены, а логика Supertrend полностью реализована. Однако после подключения индикатора к графику пока ничего не отображается. Это ожидаемое поведение. В MQL5 вычисление значений и отрисовка графических элементов – это две отдельные задачи. Хотя буферы заполняются действительными данными, терминал пока не может их отрисовать. Чтобы индикатор стал видимым, необходимо явно настроить графические построения.
Графические построения настраиваются с помощью PlotIndexSetInteger и связанных функций. Эта настройка обычно выполняется внутри функции OnInit сразу после привязки буферов индикатора к соответствующим индексам графических построений.
Настройка графического построения цветных свечей
Первое графическое построение отрисовывает ценовые свечи с динамическими цветами в зависимости от направления тренда. Это графическое построение использует режим отрисовки DRAW_COLOR_CANDLES. Внутри OnInit первое графическое построение настраивается следующим образом:
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... //--- Configure Graphic Plots PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_COLOR_CANDLES); PlotIndexSetDouble (0, PLOT_EMPTY_VALUE, EMPTY_VALUE); return INIT_SUCCEEDED; }
Здесь графическое построение с индексом 0 относится к первому графическому построению индикатора. Задавая тип отрисовки DRAW_COLOR_CANDLES, мы указываем терминалу интерпретировать первые пять буферов как данные свечей. Этот режим отрисовки использует пять буферов в определенном порядке: open, high, low, close и индекс цвета. Настройка пустого значения гарантирует, что значение буфера свечей, помеченное как EMPTY_VALUE, не отрисовывается. Это позволяет отрисовывать свечи только тогда, когда логика явно заполняет соответствующие буферы.
Именование буферов свечей для первого графического построения
Чтобы корректно связать несколько буферов с одним графическим построением свечей, их метки задаются с помощью директивы #property:
#property indicator_label1 "SupertrendOpen;SupertrendHigh;SupertrendLow;SupertrendClose"
Эта директива присваивает имена буферам свечных данных первого графического построения. Порядок имеет решающее значение. Терминал использует эту последовательность для сопоставления каждого буфера с соответствующим компонентом свечи. Благодаря этому MQL5 распознает, что эти буферы вместе формируют одно графическое построение цветных свечей, а не отдельные графические объекты. Это также повышает наглядность при просмотре буферов индикатора в окне данных.
Настройка полосы Supertrend для нисходящего тренда
Следующее графическое построение отрисовывает верхнюю полосу Supertrend, видимую во время медвежьих трендов. Эта полоса отрисовывается как простая линия. Настройка выполняется следующим образом:
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... //--- Configure Graphic Plots ... PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE); PlotIndexSetInteger(1, PLOT_LINE_STYLE, STYLE_SOLID); PlotIndexSetInteger(1, PLOT_LINE_WIDTH, 1); PlotIndexSetInteger(1, PLOT_LINE_COLOR, clrBlack); PlotIndexSetDouble (1, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetString (1, PLOT_LABEL, "downtrend"); return INIT_SUCCEEDED; }
Графическое построение с индексом 1 относится ко второму графическому построению индикатора. Оно задается как линия со сплошным стилем и шириной один пиксель. Задается черный цвет, визуально соответствующий медвежьим условиям. Настройка пустого значения играет здесь важную роль. Если буфер содержит EMPTY_VALUE, линия на этом баре не отрисовывается. Это позволяет полосе нисходящего тренда появляться только при медвежьем рынке и оставаться скрытой в противном случае. Метка графического построения определяет, как эта линия отображается в окне данных и легенде.
Настройка полосы Supertrend для восходящего тренда
Полоса восходящего тренда настраивается так же, как и полоса нисходящего тренда; отличаются только индекс графического построения, цвет и метка.
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... //--- Configure Graphic Plots ... PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_LINE); PlotIndexSetInteger(2, PLOT_LINE_STYLE, STYLE_SOLID); PlotIndexSetInteger(2, PLOT_LINE_WIDTH, 1); PlotIndexSetInteger(2, PLOT_LINE_COLOR, clrSeaGreen); PlotIndexSetDouble (2, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetString (2, PLOT_LABEL, "uptrend"); return INIT_SUCCEEDED; }
Это графическое построение отрисовывает нижнюю полосу Supertrend во время бычьих трендов. Поскольку логика повторяет конфигурацию нисходящего тренда, применяются те же правила отрисовки. В зависимости от состояния тренда в каждый момент видна только одна полоса.
Настройка общих свойств индикатора
Наконец, настраиваются общие свойства индикатора, влияющие на его отображение в терминале.
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... //--- General indicator configurations IndicatorSetString(INDICATOR_SHORTNAME, "Supertrend Indicator"); IndicatorSetInteger(INDICATOR_DIGITS, Digits()); return INIT_SUCCEEDED; }
Краткое имя определяет, как индикатор отображается на графике и в списке индикаторов. Использование краткого имени улучшает читаемость при добавлении нескольких индикаторов. Настройка числа знаков гарантирует, что все отображаемые значения соответствуют точности цены символа. Это важно для согласованности, особенно при работе с символами, использующими разные десятичные форматы.
После настройки графических построений терминал знает, как отрисовывать данные индикатора. Цветные свечи отражают текущий тренд, полосы Supertrend появляются только при необходимости, а пустые значения предотвращают нежелательную отрисовку. На этом этапе индикатор Supertrend полностью функционален, визуально корректен и не перерисовывается. Логика индикатора, управление буферами и настройка отрисовки теперь работают вместе как единая согласованная система.
Тестирование
На этом этапе индикатор должен компилироваться без ошибок и корректно отрисовываться на графике. Теперь индикатор можно подключить к любому выбранному символу и таймфрейму, чтобы наблюдать реакцию цветных свечей и полос Supertrend на изменение рыночных условий в реальном времени.
Ниже приведен скриншот готового индикатора Supertrend, примененного к четырехчасовому графику золота.

Это подтверждает, что и логика расчетов, и настройка отрисовки работают должным образом.
Заключение
В этой статье мы вышли за рамки теории и создали реальный рабочий инструмент. Разработан и реализован полностью функциональный индикатор Supertrend на языке MQL5, который надежно работает на реальном рынке, не перерисовывается и представляет внутреннюю логику в ясной и структурированной форме. Это не демонстрация и не упрощенная реализация. Это практический инструмент, который можно использовать непосредственно в торговле и анализе, а также как основу для советников и коммерческих систем.
Что еще важнее, сам индикатор – лишь часть результата. По ходу работы мы освоили принципы надежной архитектуры индикатора, дисциплинированного управления буферами, безопасной обработки данных реального рынка и четкого разделения расчетов и отрисовки. Это ключевые навыки, применимые к каждому серьезному индикатору MQL5, а не только к Supertrend. После освоения этих основ создание более продвинутых и индивидуальных инструментов становится значительно проще.
Самостоятельная разработка индикатора помогает развеять загадочность, которой часто окутаны популярные торговые инструменты. Мы получили контроль над поведением, визуальным оформлением и производительностью и теперь точно понимаем, почему индикатор работает именно так в реальном времени. Именно эта уверенность отличает пользователя индикаторов от их разработчика.
На этом завершается первый выпуск серии "Мастер-класс по созданию пользовательских индикаторов". В следующих выпусках мы применим данный подход к другим широко используемым индикаторам: разберем их и соберем заново с четким пониманием цели. Цель остается прежней: меньше "черных ящиков", более качественные инструменты и более глубокое понимание графиков, которыми мы пользуемся каждый день.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/20755
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Нейросети в трейдинге: Двухуровневая адаптация торговой политики (Объект верхнего уровня)
Индикатор Sigma Score для MetaTrader 5: Простой детектор статистических аномалий
Интеграция MQL5 с пакетами обработки данных (Часть 7): Построение многоагентных сред для межсимвольного взаимодействия
Интеграция MQL5 с пакетами обработки данных (Часть 6): Объединение рыночной обратной связи и адаптации модели
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Вы для статьи взяли материал от "Опубликован: 18 октября 2011 г. в 15:10 "
https://www.mql5.com/ru/code/576
Когда этот индикатор был написан для Metatrader 5 - TradingView ещё не было.
Делайте более качественное описание с проверкой фактов.
Вы использовали материал из статьи «Опубликовано: 18 октября 2011 г. в 15:10»
https://www.mql5.com/ru/code/576
Когда этот индикатор был написан для MetaTrader 5, TradingView ещё не существовало.
Пожалуйста, предоставьте более подробное описание и убедитесь, что факты проверены.