
Переосмысление индикаторов MQL5 и MetaTrader 5
Введение
MQL5 больше не является простым языком программирования, каким он был раньше для создания простых торговых роботов. Язык стал более совершенным, и в настоящее время вы можете создавать торговые программы большой сложности, развертывать и тестировать их гораздо более надежным и удобным способом.
Все мы в какой-то момент своего торгового пути использовали либо «нативные", либо "пользовательские индикаторы". MetaTrader5 имеет простой интерфейс для загрузки и прикрепления индикатора к графику, что позволяет трейдерам (в основном, трейдерам, работающим вручную) удобно анализировать рынки, используя индикаторы, однако, когда дело доходит до алгоритмической торговли, важно не то, что вы видите на графике, а расчеты индикатора.
Например, при ручной торговле может потребоваться посмотреть на линию индикатора скользящей средней, чтобы определить тренд, является ли это именно тем, что нужно, но при алгоритмической торговле можно определить положительную тенденцию, основываясь на том, находится ли цена закрытия выше или ниже значения скользящей средней, рассчитанного за определенное количество баров.
Когда дело доходит до алгоритмической торговли, чтобы использовать определенный индикатор, например Простую скользящую среднюю (SMA) за период 20, вам необходимо:
int sma_handle; //Declare an indicator handle //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { sma_handle = iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE); //Initialize the indicator inside the OnInit function //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- double sma_buffer[]; CopyBuffer(sma_handle, 0, 0, 1, sma_buffer); //Copy the indicator buffers inside the Ontick function }
Этот подход удобен и работает отлично, чтобы не сказать больше, но он кажется грубым и не дает нам гибкости и контроля над тем, какая информация может быть передана индикатору для немедленных расчетов.
Основываясь на этом подходе, утверждается, что индикатор скользящей средней (MA) должен применяться только к любой одной из ценовых констант, указанных в документации.
ID | Описание |
---|---|
PRICE_CLOSE | Цена закрытия |
PRICE_OPEN | Цена открытия |
PRICE_HIGH | Максимальная цена за период |
PRICE_LOW | Минимальная цена за период |
PRICE_MEDIAN | Средняя цена = (максимум + минимум)/2 |
PRICE_TYPICAL | Типичная цена (максимум + минимум + закрытия)/3 |
PRICE_WEIGHTED | Средняя цена (максимум + минимум + закрытия + закрытия)/4 |
Не говоря уже о том, что вы ограничены методами сглаживания , описанными в документации.
ID | Описание |
---|---|
MODE_SMA | Простое усреднение |
MODE_EMA | Экспоненциальное усреднение |
MODE_SMMA | Сглаженное усреднение |
MODE_LWMA | Линейно-взвешенное усреднение |
Что происходит, когда вы хотите попробовать что-то нестандартное? Например, если вы хотите рассчитать скользящую среднюю разницы между ценами максимума и минимума, это невозможно на основе текущего подхода, поскольку мы ограничены в том, что мы можем делать с индикаторами.
Я понимаю, что большинство индикаторов являются такими, какие они есть, исходя из того, как они были определены и выведены математически, но разве не было бы здорово, если бы мы могли передавать индикаторам различные входные данные и параметры для наблюдения за новыми паттернами на рынке?
Вдохновленный библиотекой технического анализа (TA-Lib) на языке python, этот инновационный подход направлен на то, чтобы предоставить трейдерам и разработчикам алгоритмических систем больше контроля над тем, какая информация поступает в индикатор для немедленных расчетов.
В настоящей статье мы реализуем несколько индикаторов (наиболее часто используемых), используя этот подход "подключи и работай".
Группировка по категориям.
Индикаторы трендов
- Индикатор Простая скользящая средняя
- Индикатор Экспоненциальная скользящая средняя
- Полосы Боллинджера
- Индикатор Parabolic SAR
- Стандартное отклонение
Осцилляторы
- Схождение/расхождение скользящих средних (MACD)
- Индекс относительной силы (RSI)
- Стохастические осцилляторы
- Средний истинный диапазон (ATR)
- Индикатор Momentum
Билл Вильямс
- Индикатор Accelerator Oscillator
- Индикатор Awesome Oscillator
Простая скользящая средняя (SMA) Индикатор
Это один из наиболее часто используемых технических индикаторов. Он вычисляет среднее значение ценового ряда за определенный период времени.
Задаются формулой:
Где:
-
это цены (например (цены закрытия) за
период.
-
это период SMA.
Мы можем легко реализовать эту формулу в векторизованной функции.
File: ta-lib.mqh
vector CTrendIndicators::SMA(const vector &price, uint period, uint shift = 0) { uint size = (uint)price.Size(); if(!CheckShiftPeriod(size, period, shift)) return price; //--- vector ma(size); ma.Fill(NaN); for(uint i = shift + period - 1; i < size; i++) //Loop through all the prices considering the period and shift { double sum = 0; for(uint j = i - period + 1; j <= i; j++) sum += price[j]; //sum of the prices ma[i] = sum / period; //divided by period to find the mean of that period } return ma; }
Именно так рассчитывается индикатор простая скользящая средняя, без использования буферов, без проверки ошибок MQL5 при загрузке индикатора для определенного символа и т.д. что может быть утомительно.
Этот минималистский подход проверяет только корректность значений сдвига и периода, и если это так, функция продолжает вычисления индикатора, возвращая рассчитанные значения в векторной форме. Я решил использовать векторный формат, чтобы получить больше контроля и гибкости в отношении конечного результата.
Поскольку все функции в наших классах индикаторов являются статическими, мы можем легко получить доступ к значениям индикаторов в наших программах на MQL5, например, с помощью простого скрипта.
Файл: Custom Indicators test script.mq5
#include <ta-lib.mqh> //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { vector prices = {1,2,3,4,5,6,7,8,9,10}; int period = 3; Print("SMA values: ", CTrendIndicators::SMA(prices, period)); }
Результаты
2025.01.21 09:57:35.727 Custom Indicators test script (EURUSD,H1) SMA values: [nan,nan,2,3,4,5,6,7,8,9]
Точно так же мы смогли рассчитать индикатор простая скользящая средняя, задав вектор некоторых значений, и позже мы обсудим, как построить график этих значений для визуального индикатора.
Экспоненциальная скользящая средняя (EMA) Индикатор
EMA рассчитывается как среднее значение ценового ряда за определенное количество периодов, точно так же, как и SMA, но он придает больший вес последним ценам, что делает его более чувствительным к изменениям цен по сравнению с простой скользящей средней (SMA).
Задается формулой.
Где:
-
— это EMA в момент времени t.
- Pt - это цена в момент времени t.
-
— это EMA предыдущего периода.
-
является сглаживающим фактором (где n - это период)
Мы можем это реализовать на MQL5 следующим образом:
Файл: ta-lib.mqh
vector CTrendIndicators::EMA(const vector &price, uint period, uint shift = 0) { uint size = (uint)price.Size(); if(!CheckShiftPeriod(size, period, shift)) return price; //--- double alpha = 2.0 / (period + 1.0); // Smoothing factor vector res(size); res.Fill(NaN); // Initialize the EMA with the SMA of the first period vector sma = SMA(price, period, shift); res[period - 1 + shift] = sma[period - 1 + shift]; // Calculate EMA for the rest of the prices for(ulong i = period + shift; i < size; i++) res[i] = alpha * price[i] + (1 - alpha) * res[i - 1]; return res; }
Мы можем получить рассчитанные значения индикатора аналогично тому, как мы это делали для SMA.
Файл: Custom Indicators test script.mq5
void OnStart() { vector prices = {1,2,3,4,5,6,7,8,9,10}; int period = 3; Print("EMA values: ", CTrendIndicators::EMA(prices, period)); }
Результаты
2025.01.21 10:19:54.291 Custom Indicators test script (EURUSD,H1) EMA values: [nan,nan,2,3,4,5,6,7,8,9]
Мы рассчитали индикаторы «Простая скользящая средняя» (SMA) и «Экспоненциальная скользящая средняя» (EMA) отдельно, в отличие от того, как они рассчитываются внутри встроенного индикатора IMA, который предоставляет возможность выбора метода сглаживания, который вы предпочитаете.
Такой раздельный подход требует написания дополнительных строк кода для реализации всех методов сглаживания индикаторов скользящей средней.
Функции для методов сглаживания, таких как MODE_SMMA (Сглаженное усреднение) и (MODE_LWMA) Линейно-взвешенное усреднение , еще предстоит реализовать в библиотеке, поскольку я полагаю, что они не так широко используются, как их аналоги (методы сглаживания SMA и EMA).
Индикатор Bollinger Bands
Это индикатор волатильности, состоящий из трех полос.
- Средняя полоса - это простая скользящая средняя (SMA) цен закрытия за определенный период.
- Верхняя полоса - это средняя полоса плюс величина, кратная стандартному отклонению цен закрытия за тот же период.

Где:
-
обычно равно 2 (стандартное значение для полос Боллинджера),
-
это период для расчета SMA и стандартного отклонения.
Поскольку этот индикатор должен возвращать три (3) одномерных (1D) значения, известных как буферы при использовании встроенного индикатора Полосы Боллинджера, давайте сделаем так, чтобы эта функция возвращала структуру из 3 векторов.
Файл: ta-lib.mqh
struct BB_res_struct { vector upper_band; vector lower_band; vector middle_band; };
BB_res_struct CTrendIndicators::BollingerBands(const vector &price, uint period, uint shift = 0, double k = 2.0) { uint size = (uint)price.Size(); BB_res_struct res; //--- Check for valid parameters if(!CheckShiftPeriod(size, period, shift)) return res; //--- Initialize vectors res.upper_band.Resize(size); res.lower_band.Resize(size); res.upper_band.Fill(NaN); res.lower_band.Fill(NaN); //--- Calculate the middle band (SMA) res.middle_band = SMA(price, period, shift); //--- Calculate the upper and lower bands for(uint i = shift + period - 1; i < size; i++) { double sum_squared_diff = 0; for(uint j = i - period + 1; j <= i; j++) { sum_squared_diff += MathPow(price[j] - res.middle_band[i], 2); } double std_dev = MathSqrt(sum_squared_diff / period); res.upper_band[i] = res.middle_band[i] + (k * std_dev); res.lower_band[i] = res.middle_band[i] - (k * std_dev); } return res; }
Ниже показано, как можно легко реализовывать индикатор Полосы Боллинджера и получать его значения.
Файл: Custom Indicators test script.mq5
void OnStart() { vector prices = {1,2,3,4,5,6,7,8,9,10}; int period = 3; BB_res_struct bb; bb = CTrendIndicators::BollingerBands(prices,period,0,2); Print("BB upper: ",bb.upper_band); Print("BB middle: ",bb.middle_band); Print("BB lower: ",bb.lower_band); }
Результаты
RL 0 11:39:21.000 Custom Indicators test script (EURUSD,H1) BB upper: [nan,nan,3.632993161855452,4.632993161855453,5.632993161855453,6.632993161855453,7.632993161855453,8.632993161855453,9.632993161855453,10.63299316185545] RO 0 11:39:21.000 Custom Indicators test script (EURUSD,H1) BB middle: [nan,nan,2,3,4,5,6,7,8,9] FF 0 11:39:21.000 Custom Indicators test script (EURUSD,H1) BB lower: [nan,nan,0.3670068381445479,1.367006838144548,2.367006838144548,3.367006838144548,4.367006838144547,5.367006838144547,6.367006838144547,7.367006838144547]
Индикатор Parabolic SAR (Стоп-переворот)
Это следующий за трендом индикатор, используемый для выявления потенциальных разворотов на рынке. Он размещает точки выше или ниже цены в зависимости от направления тренда.
Задается формулой.
Для восходящего тренда
Для нисходящего тренда
Где:
-
= Значение SAR за следующий период
-
= Коэффициент ускорения (начинается со значения по умолчанию, например, 0,02 и увеличивается на 0,02 при каждом достижении нового максимума/минимума. До максимального значения 0,2)
-
= Экстремальная точка (самый высокий максимум при восходящем тренде, самый низкий минимум при нисходящем тренде)
В MQL5 этот индикатор можно реализовать следующим образом:
Файл: ta-lib.mqh
vector CTrendIndicators::ParabolicSAR(const vector &high, const vector &low, const vector &close, double step = 0.02, double max = 0.2) { uint size = (uint)close.Size(); vector psar(size); psar.Fill(NaN); // Initialize variables double AF = step; // Acceleration Factor double EP = high[0]; // Extreme Point double SAR = low[0]; // Initial SAR bool isUptrend = true; // Assume uptrend at the start // Calculate Parabolic SAR for(uint i = 0; i < size; i++) { // Update SAR if(isUptrend) SAR = SAR + AF * (EP - SAR); else SAR = SAR + AF * (SAR - EP); // Determine if trend changes if(isUptrend && SAR > low[i]) { // Switch to downtrend isUptrend = false; SAR = EP; // Reset SAR to the most recent EP EP = low[i]; // Reset EP AF = step; // Reset AF } else if(!isUptrend && SAR < high[i]) { // Switch to uptrend isUptrend = true; SAR = EP; // Reset SAR to the most recent EP EP = high[i]; // Reset EP AF = step; // Reset AF } // Update EP and AF if(isUptrend) { if(high[i] > EP) { EP = high[i]; AF = MathMin(AF + step, max); } } else { if(low[i] < EP) { EP = low[i]; AF = MathMin(AF + step, max); } } // Store the SAR value psar[i] = SAR; } return psar; }
В отличие от двух предыдущих индикаторов отслеживания тренда, которые могут получать один вектор в качестве входных данных для цены, parabolic SAR учитывает три (3) значения цены (максимум, минимум и цену закрытия).
Файл: Custom Indicators test script.mq5
void OnStart() { vector close = {1,2,3,4,5,6,7,8,9,10}; vector high = {1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5,10.5}; vector low = {0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5}; Print("Parabolic SAR values: ", CTrendIndicators::ParabolicSAR(high,low,close,0.02,0.2)); }
Результаты
2025.01.21 11:11:03.525 Custom Indicators test script (EURUSD,H1) Parabolic SAR values: [1.5,0.5,0.54,0.6584000000000001,0.8888960000000001,1.25778432,1.782005888,2.46816518144,3.3126220560384,4.302602527072256]
Индикатор Standard Deviation
Этот индикатор измеряет величину отклонения или дисперсии цены от ее среднего значения. Этот показатель часто используется для оценки волатильности рынка.
Высокое значение стандартного отклонения указывает на высокую волатильность, в то время как низкое значение стандартного отклонения указывает на низкую волатильность.
Задается формулой.
Где:
-
= Стандартное отклонение
- n = Период
-
= Ценовая отметка
-
= Среднее значение точек данных
Мы можем это реализовать этот индикатор на MQL5 следующим образом:
Файл: ta-lib.mqh
vector CTrendIndicators::StandardDeviation(const vector &price, uint period, uint shift = 0) { uint size = (uint)price.Size(); // Check if the period and shift are valid if(!CheckShiftPeriod(size, period, shift)) return price; // Initialize standard deviation vector vector std_dev(size); std_dev.Fill(NaN); // Loop through the price data for(uint i = shift + period - 1; i < size; i++) { double sum = 0.0; double sum_sq_diff = 0.0; // Calculate mean for(uint j = i - period + 1; j <= i; j++) sum += price[j]; double mean = sum / period; // Calculate squared differences for(uint j = i - period + 1; j <= i; j++) sum_sq_diff += MathPow(price[j] - mean, 2); // Calculate standard deviation std_dev[i] = MathSqrt(sum_sq_diff / period); } return std_dev; }
Это еще один простой индикатор, который можно назвать следующим образом.
Файл: Custom Indicators test script.mq5
void OnStart() { vector prices = {1,2,3,4,5,6,7,8,9,10}; int period = 3; Print("Stddev values: ", CTrendIndicators::StandardDeviation(prices, period)); }
Результаты
2025.01.21 11:55:11.657 Custom Indicators test script (EURUSD,H1) Stddev values: [nan,nan,0.816496580927726,0.816496580927726,0.816496580927726,0.816496580927726,0.816496580927726,0.816496580927726,0.816496580927726,0.816496580927726]
Схождение/расхождение скользящих средних (MACD)
Этот осциллятор показывает взаимосвязь между двумя скользящими средними цены ценной бумаги. Он широко используется в качестве инструмента технического анализа.
Задается формулой.
Главная линия MACD
Где:
-
= Экспоненциальная скользящая средняя с более коротким периодом (например, 12)
-
= Экспоненциальная скользящая средняя с более длинным периодом (например, 26)
Сигнальная линия
Это сглаженная ЕМА линии MACD, обычно со значением периода 9
Гистограмма Macd
Это разница между линией MACD и сигнальной линией.
Аналогично тому, как мы возвращали рассчитанные значения нескольких полос Боллинджера, мы определяем структуру для возврата значений гистограммы MACD, основной и сигнальной линий.
Файл: ta-lib.mqh
struct MACD_res_struct { vector main; // The MACD Line vector signal; // The Signal Line vector histogram; // The MACD Histogram };
MACD_res_struct COscillatorIndicators::MACD(const vector &price, uint fast_ema = 12, uint slow_ema = 26, uint macd_sma = 9, uint shift = 0) { uint size = (uint)price.Size(); MACD_res_struct res; if(!CheckShiftPeriod(size, slow_ema, shift)) return res; //--- Calculate EMA(short), EMA(long), and MACD Line vector fast_ema_vector = CTrendIndicators::EMA(price, fast_ema, shift); vector slow_ema_vector = CTrendIndicators::EMA(price, slow_ema, shift); res.main.Resize(size); res.main.Fill(NaN); for(uint i = 0; i < size; i++) res.main[i] = fast_ema_vector[i] - slow_ema_vector[i]; //--- Calculate Signal Line (SMA of MACD Line) res.signal = CTrendIndicators::SMA(price, macd_sma, shift); //--- Calculate MACD Histogram res.histogram.Resize(size); res.histogram.Fill(NaN); for(uint i = 0; i < size; i++) res.histogram[i] = res.main[i] - res.signal[i]; return res; }
Мы можем легко получить расчетные значения осциллятора MACD внутри тестового скрипта следующим образом.
Файл: Custom Indicators test script.mq5
void OnStart() { vector prices = {1,2,3,4,5,6,7,8,9,10}; MACD_res_struct macd; macd = COscillatorIndicators::MACD(prices,2,3,4); Print("MACD main: ", macd.main); Print("MACD signal: ", macd.signal); }
Результаты
RD 0 12:28:51.368 Custom Indicators test script (EURUSD,H1) MACD main: [nan,nan,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5] HO 0 12:28:51.368 Custom Indicators test script (EURUSD,H1) MACD signal: [nan,nan,nan,2.5,3.5,4.5,5.5,6.5,7.5,8.5]
Индикатор относительной силы (RSI)
Это импульсный осциллятор, измеряющий скорость и величину движения цены. Он колеблется между 0 и 100, трейдеры используют его для определения условий перекупленности и перепроданности на рынке.
Расчет индикатора RSI включает в себя следующие этапы:
01: Определение средней прибыли и средних убытков за определенный период
02: Расчет относительной силы (RS)
03: Вычисление RSI
Реализация на MQL5
vector COscillatorIndicators::RSI(const vector &price, uint period, uint shift = 0) { uint size = (uint)price.Size(); //--- Check for valid parameters if(!CheckShiftPeriod(size, period, shift)) return price; //--- Initialize vectors vector rsi(size), gains(size), losses(size); rsi.Fill(NaN); gains.Fill(0.0); losses.Fill(0.0); //--- Calculate gains and losses for(uint i = shift + 1; i < size; i++) { double change = price[i] - price[i - 1]; gains[i] = (change > 0) ? change : 0; losses[i] = (change < 0) ? -change : 0; } //--- Initialize first average gain and loss (simple average for the first period) double avg_gain = 0, avg_loss = 0; for(uint i = shift + 1; i < shift + 1 + period; i++) { avg_gain += gains[i]; avg_loss += losses[i]; } avg_gain /= period; avg_loss /= period; //--- Compute RSI for the rest of the periods for(uint i = shift + period; i < size; i++) { // Apply smoothing for average gain and loss avg_gain = ((avg_gain * (period - 1)) + gains[i]) / period; avg_loss = ((avg_loss * (period - 1)) + losses[i]) / period; // Calculate RSI double rs = (avg_loss == 0) ? 0 : avg_gain / avg_loss; rsi[i] = (avg_loss == 0) ? 100 : (100 - (100 / (1 + rs))); } return rsi; }
Ниже показано, как вы можете получить значения из индикатора RSI.
void OnStart() { vector prices = {1,2,3,4,5,6,7,8,9,10}; int period = 3; Print("RSI values: ", COscillatorIndicators::RSI(prices,period)); }
Результаты
2025.01.21 12:51:29.640 Custom Indicators test script (EURUSD,H1) RSI values: [nan,nan,nan,100,100,100,100,100,100,100]
Индикатор Stochastic Odcillator
Это импульсный индикатор, сравнивающий цену закрытия ценной бумаги с ее ценовым диапазоном за указанный период.
Формула расчета этого индикатора состоит из:
Линия %K
Где:
-
это текущая цена закрытия
-
это самая низкая цена за весь ретроспективный период
-
это самая высокая цена за весь ретроспективный период
Линия %D
Это скользящая средняя линии %K, обычно использующая простую скользящую среднюю SMA за 3 периода
Ниже показано, как реализовать этот индикатор на MQL5.
Stochastic_struct COscillatorIndicators::StochasticOscillator(const vector &high, const vector &low, const vector &close, uint k_period = 5, uint d_period = 3, uint period = 3, uint shift = 0) { uint size = (uint)close.Size(); Stochastic_struct res; // Check for valid parameters if(!CheckShiftPeriod(size, period, shift)) return res; // Initialize vectors for %K and %D vector K(size), D(size); K.Fill(NaN); D.Fill(NaN); // Calculate %K for(uint i = shift + period - 1; i < size; i++) { double H_max = -DBL_MAX, L_min = DBL_MAX; // Find the highest high and the lowest low over the lookback period for(uint j = i - period + 1; j <= i; j++) { H_max = MathMax(H_max, high[j]); L_min = MathMin(L_min, low[j]); } // Calculate %K double K_value = (H_max - L_min != 0) ? ((close[i] - L_min) / (H_max - L_min)) * 100 : 0; K[i] = K_value; } // Smooth %K with a simple moving average (k_period) vector smoothedK(size); smoothedK.Fill(NaN); for(uint i = shift + k_period - 1; i < size; i++) { double sum = 0; for(uint j = i - k_period + 1; j <= i; j++) { sum += K[j]; } smoothedK[i] = sum / k_period; } // Calculate %D (3-period moving average of %K) D = CTrendIndicators::SMA(smoothedK, period, shift); res.main = K; res.signal = D; return res; }
Мы возвращаем сигнал и основную линию в виде структуры.
void OnStart() { vector close = {1,2,3,4,5,6,7,8,9,10}; vector high = {1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5,10.5}; vector low = {0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5}; Stochastic_struct stoch; stoch = COscillatorIndicators::StochasticOscillator(high,low,close,5,3,3); Print("Stoch main: ", stoch.main); Print("Stoch signal: ", stoch.signal); }
Индикатор Средний истинный диапазон (ATR)
Это полезный индикатор для понимания волатильности рынка. Он измеряет средний диапазон между высокими и низкими ценами за определенный период.
Задается формулой.
01: Расчет Истинного диапазона (TR)
Где:
- H - максимум текущего периода.
-
это минимум теущего периода.
-
это цена закрытия предыдущего периода.
02: Расчет индикатора Средний истинный диапазон (ATR)
ATR - это скользящая средняя истинного диапазона за определенный период.
SMA это Простая скользящая средняя.
Мы можем это реализовать этот индикатор на MQL5 следующим образом:
vector COscillatorIndicators::ATR(const vector &high, const vector &low, const vector &close, uint period = 14, uint shift = 0) { uint size = (uint)close.Size(); // Check for valid parameters if(!CheckShiftPeriod(size, period, shift)) return close; // Initialize the True Range (TR) and ATR vectors vector TR(size); TR.Fill(NaN); // Calculate the True Range for each period for(uint i = shift + 1; i < size; i++) { double H = high[i]; double L = low[i]; double C_prev = close[i - 1]; // Calculate the three possible True Range values double TR1 = H - L; double TR2 = MathAbs(H - C_prev); double TR3 = MathAbs(L - C_prev); // True Range is the maximum of the three TR[i] = MathMax(TR1, MathMax(TR2, TR3)); } //--- Smooth the True Range using a simple moving average (SMA) over the specified period return CTrendIndicators::SMA(TR, period, shift); }
Ниже показано, как можно получить значения для этого индикатора.
void OnStart() { vector close = {1,2,3,4,5,6,7,8,9,10}; vector high = {1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5,10.5}; vector low = {0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5}; Print("ATR values: ", COscillatorIndicators::ATR(high,low,close,3)); }
Результаты
2025.01.21 13:57:59.943 Custom Indicators test script (EURUSD,H1) ATR values: [nan,nan,nan,1.5,1.5,1.5,1.5,1.5,1.5,1.5]
Индикатор Momentum
Это простой индикатор, используемый для измерения скорости, с которой меняется цена актива в течение определенного периода. Он помогает определять тренды и потенциальные точки разворота трендов.
Задается простой формулой.
Где:
- Momentum(t) = значение импульса в период времени t
- Price(t) = текущая цена
- Price(t - n) = Цена на n периодов назад
- n = период, за который рассчитывается импульс
В некоторых вариантах для расчета импульса используется соотношение.
Мы реализуем индикатор momentum, используя этот вариант.
Реализация на MQL5
vector COscillatorIndicators::MomentumIndicator(const vector &price, uint period, uint shift = 0) { uint size = (uint)price.Size(); // Check for valid input if(!CheckShiftPeriod(size, period, shift)) return price; // Initialize the momentum vector vector momentum(size); momentum.Fill(NaN); // Calculate Momentum for(uint i = shift + period; i < size; i++) { //momentum[i] = price[i] - price[i - period]; // Momentum difference formula // using the ratio formula: momentum[i] = (price[i] / price[i - period]) * 100; } return momentum; }
Индикатор Awesome Oscillator
Это импульсный индикатор, вычисляющий разницу между двумя простыми скользящими средними (SMA) средней цены.
Задается формулой:
Где:
-
= SMA с более коротким периодом (обычно 5)
-
= SMA с более длинным периодом (обычно 34)
Ниже представлена реализация на MQL5.
vector CBillWilliamsIndicators::AwesomeOscillator(const vector &high, const vector &low, uint fast_period = 5, uint slow_period = 34, uint shift = 0) { uint size = (uint)high.Size(); if(size != low.Size()) return vector::Zeros(0); // Ensure high and low vectors are of the same size if(!CheckShiftPeriod(size, slow_period, shift)) return vector::Zeros(0); // Validate shift and slow period // Initialize vectors vector ao(size), median_price(size); ao.Fill(NaN); median_price.Fill(NaN); // Calculate Median Price for(uint i = 0; i < size; i++) median_price[i] = (high[i] + low[i]) / 2; // Calculate Fast and Slow SMAs of the Median Price vector sma_fast = CTrendIndicators::SMA(median_price, fast_period, shift); vector sma_slow = CTrendIndicators::SMA(median_price, slow_period, shift); // Calculate AO for(uint i = 0; i < size; i++) ao[i] = sma_fast[i] - sma_slow[i]; return ao; }
Поскольку у нас есть очень простые векторы для высоких и низких цен, мы можем установить быстрый период равным 3, а медленный - 5.
void OnStart() { vector close = {1,2,3,4,5,6,7,8,9,10}; vector high = {1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5,10.5}; vector low = {0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5}; Print("AO values: ", CBillWilliamsIndicators::AwesomeOscillator(high,low,3,5)); }
Результаты.
2025.01.21 14:25:50.590 Custom Indicators test script (EURUSD,H1) AO values: [nan,nan,nan,nan,1,1,1,1,1,1]
Индикатор Accelerator Oscillator
Индикатор Accelerator Oscillator (AC) это инструмент технического анализа, отслеживающий скорость изменения ценового импульса. Он показывает, ускоряется или замедляется движущая сила рынка, помогая трейдерам предвидеть возможные развороты.
Он рассчитывается как разница между Awesome Oscillator и 5-периодной простой скользящей средней (SMA) АО.
Задается приведенной ниже формулой.

Мы можем это реализовать этот индикатор на MQL5 следующим образом:
vector CBillWilliamsIndicators::AcceleratorOscillator(const vector &high, const vector &low, uint ao_period_fast = 5, // Fast period for AO uint ao_period_slow = 34, // Slow period for AO uint ac_period = 5 // Period for AC SMA ) { uint size = (uint)high.Size(); if(size != low.Size()) return vector::Zeros(0); // Ensure high and low vectors are of the same size // Validate shift and period if(!CheckShiftPeriod(size, ao_period_slow, 0)) return vector::Zeros(0); // Calculate AO (Awesome Oscillator) vector ao = AwesomeOscillator(high, low, ao_period_fast, ao_period_slow); // Calculate AC (Accelerator Oscillator) vector ac(size); ac.Fill(NaN); vector ao_sma_ac = CTrendIndicators::SMA(ao, ac_period); for(uint i = 0; i < size; i++) ac[i] = ao[i] - ao_sma_ac[i]; return ac; }
Поскольку Accelerator Oscillator очень похож на Awesome Oscillator, мы можем вызвать его функцию с аналогичными аргументами.
void OnStart() { vector close = {1,2,3,4,5,6,7,8,9,10}; vector high = {1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5,10.5}; vector low = {0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5}; //--- Bill williams indicator Print("AO values: ", CBillWilliamsIndicators::AwesomeOscillator(high,low,3,5)); Print("AC values: ", CBillWilliamsIndicators::AcceleratorOscillator(high,low,3,5)); }
Результаты
MQ 0 14:40:36.296 Custom Indicators test script (EURUSD,H1) AO values: [nan,nan,nan,nan,1,1,1,1,1,1] EL 0 14:40:36.296 Custom Indicators test script (EURUSD,H1) AC values: [nan,nan,nan,nan,nan,nan,nan,nan,0,0]
Упрощенный сбор данных по индикаторам
Теперь, когда мы увидели, как некоторые индикаторы были реализованы в библиотеке, мы можем попытаться собрать любую информацию, которую хотели бы получить с рынка, и на ее основе построить индикатор. Например, я собираюсь рассчитать скользящую среднюю для цен открытия, максимума, минимума и закрытия.
Начинаем с получения значений OHLC.
int size = 1000; vector open, high, low, close; open.CopyRates(Symbol(), Period(), COPY_RATES_OPEN, 1, size); high.CopyRates(Symbol(), Period(), COPY_RATES_HIGH, 1, size); low.CopyRates(Symbol(), Period(), COPY_RATES_LOW, 1, size); close.CopyRates(Symbol(), Period(), COPY_RATES_CLOSE, 1, size);
Начиная с простой скользящей средней за период 20, примененной к ценам открытия.
vector sma_open = CTrendIndicators::SMA(open, 20);
Мы можем без особых усилий собирать различные индикаторы SMA для разных периодов и по разным ценам.
vector sma_open = CTrendIndicators::SMA(open, 20); vector sma_high = CTrendIndicators::SMA(high, 50); vector sma_low = CTrendIndicators::SMA(low, 100); vector sma_close = CTrendIndicators::SMA(close, 20);
Давайте вместо этого поместим их в матрицу и будем наблюдать за ними в целом.
matrix Indicators(size, 4); Indicators.Col(CTrendIndicators::SMA(open, 20), 0); Indicators.Col(CTrendIndicators::SMA(high, 50), 1); Indicators.Col(CTrendIndicators::SMA(low, 100), 2); Indicators.Col(CTrendIndicators::SMA(close, 20), 3); Print("Indicators matrix\n",Indicators);
Результаты
NK 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0485715,1.0484514,nan,1.048488] LL 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0484425,1.0485544,nan,1.0484265] RP 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.048381,1.0486754,nan,1.048299] QG 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0483055,1.0488004,nan,1.048152] KK 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0481585,1.0489198,nan,1.048296] HL 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.048303,1.049033,nan,1.0485255] DS 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.048533,1.0491756,nan,1.0487015] OK 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.048658,1.0493158,1.0475226,1.0488295] KD 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0487895,1.0494628,1.047473,1.0488985] JR 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0488575,1.0494916,1.0474256,1.0489465] FR 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0489055,1.049475,1.0473723,1.0490045] LL 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.048964,1.0494814,1.0473137,1.049052] HK 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0490075,1.0494728,1.0472494,1.0491065] CF 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.049062,1.0494618,1.0471845,1.049044] RE 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0489995,1.0494452,1.047114,1.048892] FQ 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.048848,1.0494558,1.047044,1.0487065] CL 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0486625,1.0495002,1.0469762,1.0486305] DK 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.048586,1.0496014,1.0469234,1.048582] EE 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0485375,1.0496714,1.0468866,1.048646] RE 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0486015,1.0497982,1.046857200000001,1.04877] IP 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0487245,1.0498646,1.0468378,1.0490025] DO 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0489565,1.0499466,1.046833500000001,1.0492415] GN 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0491975,1.050113,1.046846700000001,1.0497525] CK 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0497085,1.0502838,1.046881000000001,1.0502025] IJ 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.050159,1.0503826,1.046898100000001,1.0506915] PF 0 18:30:25.100 Custom Indicators test script (EURUSD,H1) [1.0506475,1.0504916,1.046935200000001,1.051158…]
Допустим, я хочу измерить динамику этих переменных, которые у меня есть, создав на их основе индикатор динамики.
Indicators.Col(COscillatorIndicators::MomentumIndicator(open, 20), 4); Indicators.Col(COscillatorIndicators::MomentumIndicator(high, 50), 5); Indicators.Col(COscillatorIndicators::MomentumIndicator(low, 100), 6); Indicators.Col(COscillatorIndicators::MomentumIndicator(close, 20), 7);
Результаты
IN 0 18:39:34.172 Custom Indicators test script (EURUSD,H1) [1.0441885,nan,nan,1.0438975,99.43679181343492,nan,nan,99.44502817843157] LN 0 18:39:34.172 Custom Indicators test script (EURUSD,H1) [1.0438975,1.0495116,nan,1.043593,99.44407828753189,nan,nan,99.41864350150351] QS 0 18:39:34.172 Custom Indicators test script (EURUSD,H1) [1.0435925,1.0492638,nan,1.0433225,99.4176888931316,98.82473464044848,nan,99.4833645288208] HG 0 18:39:34.172 Custom Indicators test script (EURUSD,H1) [1.0436275,1.049148199999999,nan,1.043363,100.0668474731655,99.45161810609009,nan,100.0773424743863] EH 0 18:39:34.172 Custom Indicators test script (EURUSD,H1) [1.0436685,1.0490618,nan,1.043385,100.0782973197491,99.59030385797199,nan,100.0420047732697] KO 0 18:39:34.172 Custom Indicators test script (EURUSD,H1) [1.0436925,1.0489454,nan,1.0434175,100.0458251389074,99.4479854313681,nan,100.0620536907626] JQ 0 18:39:34.172 Custom Indicators test script (EURUSD,H1) [1.0437225,1.048834,nan,1.043484,100.0572803299347,99.47183265534476,nan,100.1270939444036] JE 0 18:39:34.172 Custom Indicators test script (EURUSD,H1) [1.043788,1.048718,nan,1.0435725,100.1251839535195,99.45010144680205,nan,100.1690625149243] LE 0 18:39:34.172 Custom Indicators test script (EURUSD,H1) [1.043877,1.048595199999999,nan,1.0435315,100.1700192943244,99.41799844546816,nan,99.92180198737388] MI 0 18:39:34.172 Custom Indicators test script (EURUSD,H1) [1.0438365,1.048457,nan,1.0437085,99.92275488503829,99.34503611305946,nan,100.3389538390831] HN 0 18:39:34.172 Custom Indicators test script (EURUSD,H1) [1.044013,1.0483164,nan,1.044095,100.3379931060896,99.33386396801032,nan,100.7431263218612] KS 0 18:39:34.172 Custom Indicators test script (EURUSD,H1) [1.0443985,1.048186,nan,1.044364,100.7411964891704,99.38227742565063,nan,100.5158345877638] EE 0 18:39:34.172 Custom Indicators test script (EURUSD,H1) [1.0446665,1.0480502,nan,1.044532,100.5139219145509,99.35649569733499,nan,100.3225558712848…]
Построение графиков индикаторов, созданных с помощью пользовательских функций
Давайте попытаемся сделать полученные из этой библиотеки расчеты индикаторов видимыми для человеческого глаза.
Несмотря на то, что этот подход направлен скорее на сбор данных, чем на визуализацию, давайте визуализируем расчеты индикатора в пользовательском индикаторе MetaTrader 5.
Визуализация индикатора SMA (20).
#property indicator_chart_window #property indicator_buffers 1 #property indicator_plots 1 #property indicator_color1 clrDodgerBlue #property indicator_type1 DRAW_LINE #property indicator_style1 STYLE_SOLID #include <ta-lib.mqh> input int period_ = 20; //SMA period double buffer[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0, buffer, INDICATOR_DATA); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0); PlotIndexSetString(0,PLOT_LABEL,"SMA("+string(period_)+")"); PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,period_+1); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //--- if (prev_calculated==0) //Initial indicator calculation, For Plotting the entire past { vector buffer_vector = CTrendIndicators::SMA(close, period_); VectorToArray(buffer_vector, buffer); //We assign the calculations into an array format } else //For plotting the current value { for (int i=prev_calculated-1; i<rates_total; i++) //Loop from the prev_calculated bars -1 to the total bars present { double temp_close[]; //For storing temporary close values int size = period_*2; //We are going to copy an equivalent of period x 2 to leave a room for NaN values if (ArrayCopy(temp_close, close, 0, i - size, size) < 0) { printf("Failed to copy closing price values to a temporary array, err = %d",GetLastError()); continue; } vector indicator_values = CTrendIndicators::SMA(temp_close, period_); ulong last_index = indicator_values.Size() - 1; //The last value in the vector is the recent calculated indicator value buffer[i] = indicator_values[last_index]; //Assing the last indicator value to the last value in the buffer } } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| A crude way to convert a vector into Array | //+------------------------------------------------------------------+ template <typename T> void VectorToArray(const vector<T> &v, T &arr[]) { ArrayResize(arr, (uint)v.Size()); for (uint i=0; i<(uint)v.Size(); i++) arr[i] = v[i]; }
Результаты
Заключительные мысли
Такой подход к индивидуальному сбору значений показателей удобен, когда речь заходит о сборе данных, а не о какой-либо другой конкретной задаче, он хорошо подходит для аналитики данных и энтузиастов, ищущих инновационные способы сбора данных индикаторов для целей анализа.
Я часто сталкивался с необходимостью быстрого получения нескольких значений индикаторов без необходимости инициализировать индикатор и выполнять все те скучные действия, которые часто приводят к ошибкам MetaTrader5. В связи с растущим спросом на данные в MQL5, обусловленным его новой способностью работать со сложными моделями ИИ и машинного обучения (ML), нам нужны различные и эффективные способы извлечения и визуализации данных индикаторов для целей анализа и обучения ML.
Всем добра.
Таблица вложений
Имя файла | Описание/назначение |
---|---|
Include\ta-lib.mqh | Библиотека MQL5 со всеми индикаторами, описанными в этой статье. |
Indicators\Trend Indicators Redefined.mq5 | Индикатор, содержащий индикатор простой скользящей средней, реализованный в демонстрационных целях. |
Scripts\Custom Indicators test script.mq5 | Простой скрипт, созданный для тестирования и отладки кода индикаторов. |
Источники и ссылки
- Индекс относительной силы (RSI) Индикатор, объясняемый формулой
- Скользящая средняя (MA): Цель, виды использования, формула, примеры
- Как использовать полосы Боллинджера для оценки трендов
- Индикатор Parabolic SAR: Определение, формула, торговые стратегии
- Формула стандартного отклонения и соотношение использования и дисперсии
- Что такое MACD?
- Стохастический осциллятор: Что это такое, как это работает, как рассчитать
- Средний истинный диапазон (ATR) Формула, что он означает и каким образом его использовать
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/16931
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.






- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования