Português
preview
Скользящая средняя на MQL5 с нуля: Просто и доступно

Скользящая средняя на MQL5 с нуля: Просто и доступно

MetaTrader 5Примеры | 18 ноября 2024, 13:09
1 704 2
Artyom Trishkin
Artyom Trishkin

Содержание



Введение

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

Скользящие средние часто и повсеместно используются для решения различных прикладных задач. Математически простая скользящая средняя — это обычное среднее арифметическое определённого ряда числовых значений. При создании различных индикаторов или скриптов и советников для терминала MetaTrader 5, скользящие средние так или иначе используются в расчётах. Скользящие средние для трейдеров — это простой и достаточно эффективный инструмент для определения направления трендов, сглаживания незначительных ценовых колебаний (шумов), либо для создания торговых стратегий на основе скользящих средних и других индикаторов, широко представленных как в клиентском терминале, так и на ресурсе mql5.com.

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


Simple Moving Average (SMA) — простое скользящее среднее

Простое скользящее среднее рассчитывается, как среднее арифметическое заданного количества числовых значений, например, цен закрытия баров. В каждой точке расчёта значения скользящей средней имеют одинаковый вес по отношению к соседним точками рассчитываемого числового ряда. Иными словами, и применительно к индикатору SMA, на каждом баре линии индикатора (N) мы видим среднее значение соседних слева баров (N + N-1 + N-2 + N-3 + N-x) / x, где x — это период усреднения (количество рассчитываемых баров).

SMA - это

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


Рис.1. Простое скользящее среднее. SMA по ценам Close, с периодом расчёта 10

Расчёт

Расчёт индикатора SMA по ценам закрытия баров можно выразить так:

SMA = SUM(CLOSE(i), N) / N 

где:

  • SUM — сумма;
  • CLOSE(i) — цена закрытия текущего периода;
  • N — число периодов расчета.

В индикаторе расчёт простой скользящей средней может быть таким:

double result=0;
for(int j=0; j<period; j++)
   result+=close[i-j];
result/=period;

Здесь:

  • result — переменная, в которую записывается результат расчёта SMA
  • period — период расчёта SMA: количество данных в рассчитываемом числовом ряде, именно здесь — цен закрытия баров
  • i — индекс главного цикла индикатора
  • j — индекс цикла для расчёта среднего значения цен закрытия баров слева от бара с индексом i

То есть, при расчёте среднего для периода сглаживания 5, проходим в цикле от бара с индексом i и складываем все цены Close баров с индексом i-j (i-0 + i-1 + i-2 + i-3 + i-4).

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

Посмотрим код индикатора:

//+------------------------------------------------------------------+
//|                                           SMAonPriceCloseRAW.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1

//--- plot MA
#property indicator_label1  "SMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- input parameters
input int      InpPeriod   =  10;   // SMA Period

//--- indicator buffers
double         MABuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,MABuffer,INDICATOR_DATA);
   
//--- успешная инициализация
   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[])
  {
//--- в цикле от значения InpPeriod до текущего бара истории
   for(int i=InpPeriod; i<rates_total; i++)
     {
      //--- рассчитываем среднее цен close за InpPeriod баров
      double result=0;
      for(int j=0; j<InpPeriod; j++)
         result+=close[i-j];
      result/=InpPeriod;
      
      //--- Записываем результат расчёта в буфер
      MABuffer[i]=result;
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }

Это простейший индикатор, позволяющий увидеть на графике средние значения цен Close за указанный в настройках период для каждого бара истории (InpPeriod). Значения отображаются в виде линии на графике цен.

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

Таким образом, идя в цикле от начала истории, мы для каждого бара цикла i рассчитываем среднее значение цен закрытия баров слева в цикле j. Именно поэтому основной цикл начинается не от нуля, а от значения количества баров, для которых рассчитываем среднее — чтобы слева было требуемое количество баров в самом начале расчёта SMA.

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

indicator is too slow, 66141 ms. rewrite the indicator, please

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

Файл индикатора SMAonPriceCloseRAW.mq5 можно найти в прикреплённых к статье файлах.

Оптимизация расчётов

Под экономным расчётом индикатора подразумевается такая последовательность расчётов:

  • При первом запуске индикатора (либо при каких-либо изменениях в истории символа) производится полный расчёт индикатора по всей доступной истории. 
  • После полного расчёта, на графике будут отрисованы все рассчитанные данные, и теперь нужно рассчитывать и изменять данные на каждом новом тике только для текущего бара.

Расчёт индикатора начинается при поступлении события Calculate. При этом вызывается обработчик этого события OnCalculate().

Обычно это происходит при поступлении нового тика по символу, для которого рассчитывается индикатор.

Существует два варианта определения обработчика OnCalculate(). В пределах одного индикатора нельзя использовать оба варианта функции.

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

int OnCalculate (const int rates_total,      // размер массива price[]
                 const int prev_calculated,  // обработано баров на предыдущем вызове
                 const int begin,            // откуда начинаются значимые данные
                 const double& price[]       // массив для расчета
   );

В качестве массива price[] может быть передана одна из ценовых таймсерий, либо рассчитанный буфер какого-либо индикатора.

Выбор необходимой таймсерии или индикатора в качестве массива price[] осуществляется пользователем на вкладке "Parameters" при запуске индикатора.

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

int OnCalculate (const int rates_total,      // размер входных таймсерий
                 const int prev_calculated,  // обработано баров на предыдущем вызове
                 const datetime& time[],     // Time
                 const double& open[],       // Open
                 const double& high[],       // High
                 const double& low[],        // Low
                 const double& close[],      // Close
                 const long& tick_volume[],  // Tick Volume
                 const long& volume[],       // Real Volume
                 const int& spread[]         // Spread
   );
  • Параметры open[], high[], low[] и close[] содержат массивы с ценами открытия, максимальной, минимальной ценами и ценами закрытия текущего таймфрейма.
  • Параметр time[] содержит массив со значениями времени открытия.
  • Параметр spread[] — массив, содержащий историю спредов (если спред предусмотрен для данного торгового инструмента).
  • Параметры volume[] и tick_volume[] содержат соответственно историю торгового и тикового объема.
  • Параметр rates_total содержит количество баров, доступных индикатору для расчета, и соответствует количеству баров, доступных на графике.
  • Параметр prev_calculated при вызове функции содержит значение, которое вернула функция OnCalculate() на предыдущем вызове. Это позволяет реализовать экономные алгоритмы расчета пользовательского индикатора с тем, чтобы избежать повторных расчетов для тех баров, которые не изменились с предыдущего запуска этой функции. Для этого обычно достаточно вернуть значение параметра rates_total, которое содержит количество баров при текущем вызове функции. Если с момента последнего вызова функции OnCalculate() ценовые данные были изменены (подкачана более глубокая история или были заполнены пропуски истории), то значение входного параметра prev_calculated будет установлено в нулевое значение самим терминалом.

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

Так как цикл индикатора проходит по историческим данным, начиная от некоего числа и до значения rates_total-1, то, зная сколько баров было просчитано на прошлом запуске индикатора (значение хранится в переменной prev_calculated), мы можем управлять значением, с которого необходимо начинать цикл расчёта.

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

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

Установка количества просчитываемых баров в переменную start должна выглядеть так:

//--- Если это первый запуск или изменение в исторических данных
   if(prev_calculated==0)
     {
      //--- инициализируем буфер индикатора пустым значением и
      //--- устанавливаем начало расчёта на значение Period
      ArrayInitialize(MABuffer,EMPTY_VALUE);
      start=Period;
     }
//--- Если это не первый запуск - началом расчёта будет текущий бар
   else
      start=prev_calculated-1;

При первом запуске индикатора, сначала в его буфер записывается инициализирующее значение. Здесь это EMPTY_VALUE — пустое значение буфера индикатора, не участвующее в отрисовке. А далее, в переменную start записывается индекс бара, с которого начинается главный цикл индикатора. Если это не первый запуск индикатора, то в переменной prev_calculated записано количество уже посчитанных баров на прошлом вызове обработчика OnCalculate(). Поэтому в этом случае, в качестве бара, с которого начинается цикл, устанавливаем индекс текущего бара, а это в подавляющем большинстве prev_calculated-1.

Так как из обработчика OnCalculate() возвращается некое значение (обычно rates_total), то мы можем сами регулировать количество баров, которое необходимо посчитать на следующем вызове обработчика. Если возвращаем количество посчитанных баров, хранящееся в rates_tota, то на следующем вызове OnCalculate это значение будет записано в переменной prev_calculated. Соответственно, если мы указываем номер бара для начала цикла как prev_calculated-1, то на текущем баре это будет индекс текущего бара, а при открытии нового бара — это будет индекс предыдущего бара. Таким образом мы указываем номер бара для старта цикла:

  • при первом запуске — от значения периода расчёта индикатора
  • на открытии нового бара — от предыдущего бара (рассчитывается прошлый и текущий бар)
  • на текущем баре на каждом новом тике рассчитываем один текущий бар

Посмотрим полный код индикатора:

//+------------------------------------------------------------------+
//|                                           SMAonPriceCloseECO.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1

//--- plot MA
#property indicator_label1  "SMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- input parameters
input int      InpPeriod   =  10;   // SMA Period

//--- indicator buffers
double         MABuffer[];

//--- global variables
int   ExtPeriod;  // период расчёта SMA
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,MABuffer,INDICATOR_DATA);
   
//--- успешная инициализация
   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[])
  {
//--- Корректируем введённое значение периода расчёта SMA
   ExtPeriod=(InpPeriod<1 ? 10 : InpPeriod);
   
//--- Если не хватает исторических данных для расчёта - возвращаем 0
   if(rates_total<ExtPeriod)
      return 0;
      
   int start=0;   // бар начала расчёта
   
//--- Если это первый запуск или изменение в исторических данных
   if(prev_calculated==0)
     {
      //--- инициализируем буфер индикатора пустым значением и
      //--- устанавливаем начало расчёта на значение ExtPeriod
      ArrayInitialize(MABuffer,EMPTY_VALUE);
      start=ExtPeriod;
     }
//--- Если это не первый запуск - началом расчёта будет текущий бар
   else
      start=prev_calculated-1;
      
//--- в цикле от значения start до текущего бара истории
   for(int i=start; i<rates_total; i++)
     {
      //--- рассчитываем среднее цен close за ExtPeriod баров
      double result=0;
      for(int j=0; j<ExtPeriod; j++)
         result+=close[i-j];
      result/=ExtPeriod;
      
      //--- Записываем результат расчёта в буфер
      MABuffer[i]=result;
     }
     
//--- возвращаем количество посчитанных баров для следующего вызова OnCalculate
   return(rates_total);
  }

Файл индикатора SMAonPriceCloseECO.mq5 можно найти в прикреплённых к статье файлах.

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

Посмотрим, как индикатор SMA в текущем исполнении просчитывается на истории. Для примера покажем самое начало расчёта простой скользящей средней с периодом расчёта 5 баров.

При запуске просчёт индикатора начинается не с нулевого бара, а с бара, равного (количество баров периода расчёта SMA) - 1:

Основной цикл начинается на баре с индексом 4. Для расчёта значения SMA на этом баре, выполняется цикл по барам с индексами 4, 3, 2, 1 и 0 и значения цены на этих барах складываются, а затем полученная сумма делится на количество периодов расчёта SMA - здесь это 5. Для упрощения расчётов на рисунке отображены простые целочисленные значения 2, 4, 6, 8 и 10 на соответствующих барах в качестве значений цен баров. В итоге, на баре с индексом 4 значение SMA равно 6 = (2+4+6+8+10)/5.

После смещения индекса основного цикла расчёта SMA, опять в цикле рассчитывается значение SMA для следующего бара с индексом 5:

На следующей итерации основного цикла, опять во внутреннем цикле рассчитывается SMA для бара с индексом 6:

И далее всё по той же схеме - на каждом очередном смещении индекса основного цикла просчитываются во внутренних циклах значения SMA для каждого последующего бара.
И так до тех пор, пока основной цикл не дойдёт до текущего бара:


Затем при расчёте SMA на текущем баре с приходом каждого очередного тика будет выполняться внутренний цикл для расчёта SMA на текущем баре.

Что такое SMA? Это среднее арифметическое цен за определённый период. Мы уже знаем, что для расчёта значения SMA на одном баре, нужно сумму предыдущих Period цен разделить на период расчёта Period. Мы можем при запуске индикатора рассчитать самое первое значение SMA сложением в цикле предыдущих Period цен и эту сумму разделить на Period. И теперь, при смещении скользящего окна расчёта SMA вправо, уже не обязательно в цикле складывать предыдущие цены и делить на их количество Period — ведь у нас уже есть рассчитанное значение SMA на прошлом баре.

Достаточно вычесть из этого значения самую первую цену из участвовавших в расчёте среднего значения и добавить к результату текущую цену, не забыв их разделить на Period. Всё. То есть, самый первый бар SMA рассчитывается сложением в цикле Period цен и делением результата сложения на значение Period, а далее — только арифметические операции сложения, вычитания и деления:

Расчёт первого значения SMA:


Далее, при смещении индекса основного цикла просто делаем расчёт:


И далее по тому же сценарию, но с новыми данными:


И на каждом смещении индекса основного цикла


Каждый раз получаем новое значение SMA из ранее посчитанного


Рассмотрим такой индикатор:

//+------------------------------------------------------------------+
//|                                              SMAonPriceClose.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1

//--- plot MA
#property indicator_label1  "SMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- input parameters
input int      InpPeriod   =  10;   // SMA Period

//--- indicator buffers
double         MABuffer[];

//--- global variables
int   ExtPeriod;  // период расчёта SMA
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,MABuffer,INDICATOR_DATA);
   
//--- успешная инициализация
   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[])
  {
//--- Корректируем введённое значение периода расчёта SMA
   ExtPeriod=(InpPeriod<1 ? 10 : InpPeriod);
   
//--- Если не хватает исторических данных для расчёта - возвращаем 0
   if(rates_total<ExtPeriod)
      return 0;
      
   int start=0;   // бар начала расчёта
   
//--- Если это первый запуск или изменение в исторических данных
   if(prev_calculated==0)
     {
      //--- инициализируем буфер индикатора пустым значением,
      //--- устанавливаем начало расчёта на значение ExtPeriod и
      //--- рассчитываем среднее цен close за ExtPeriod баров для первого значения SMA на баре start-1
      ArrayInitialize(MABuffer,EMPTY_VALUE);
      start=ExtPeriod;
      double value=0;
      for(int i=0; i<start; i++)
         value+=close[i];
      MABuffer[start-1]=value/ExtPeriod;
     }
//--- Если это не первый запуск - началом расчёта будет текущий бар
   else
      start=prev_calculated-1;
      
//--- в цикле от значения start до текущего бара истории
   for(int i=start; i<rates_total; i++)
     {
      //--- определяем цены для расчёта SMA
      double ma_prev=MABuffer[i-1];             // Предыдущее рассчитанное значение SMA
      double price_first=close[i-ExtPeriod];    // Цена close ExtPeriod баров назад
      //--- Записываем в буфер текущее значение SMA, рассчитанное как 
      //--- (прошлое значение SMA + (текущая цена close - цена close ExtPeriod баров назад) / период расчёта SMA ExtPeriod)
      MABuffer[i]=ma_prev+(close[i]-price_first)/ExtPeriod;
     }
     
//--- возвращаем количество посчитанных баров для следующего вызова OnCalculate
   return(rates_total);
  }

Индикатор можно запустить на графике и сравнить со стандартным SMA, предварительно установив для них одинаковые периоды расчёта. Данный индикатор использует один цикл длиной в период расчёта MA Period при старте, а далее, при первом запуске в основном цикле рассчитывает значения SMA на основании самого первого рассчитанного значения SMA для всей истории инструмента. На текущем баре он выполняет математический расчёт значения SMA для каждого текущего тика.

Файл индикатора SMAonPriceClose.mq5 можно найти в прикреплённых к статье файлах.


Exponential Moving Average (EMA) — экспоненциальное скользящее среднее

Экспоненциально сглаженное скользящее среднее определяется путем добавления к предыдущему значению рассчитанного скользящего среднего определенной доли текущей цены закрытия. При использовании экспоненциальных скользящих средних, больший вес имеют последние цены закрытия. При расчете EMA веса цен баров, участвующих в расчёте, убывают экспоненциально со скоростью, которая задается сглаживающей константой k (1 > k > 0). Чаще всего k рассчитывают, исходя из периода расчёта скользящей средней: k = 2.0 / (N + 1), где N — количество периодов расчёта.

EMA:

  • Быстрее реагирует на изменения цены, что делает её предпочтительной для краткосрочной торговли,
  • Более эффективна в определении трендов и сигналов на Buy и Sell, так как учитывает свежие данные,
  • Часто используется для пересечений с другими EMA (например, 50 и 200), чтобы определить моменты покупки или продажи.

Рис.2. Экспоненциальное скользящее среднее. EMA по ценам Close, с периодом расчёта 10

Расчёт

Р-процентное экспоненциальное скользящее среднее будет иметь вид:

EMA = (CLOSE(i) * P) + (EMA(i - 1) * (1 - P))

где:

  • CLOSE(i) — цена закрытия текущего периода;
  • EMA(i - 1) — значение скользящего среднего предыдущего периода;
  • P — доля использования значения цен (сглаживающая константа).

Напишем простой индикатор, показывающий расчёт экспоненциальной скользящей средней:

//+------------------------------------------------------------------+
//|                                           EMAonPriceCloseRAW.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot MA
#property indicator_label1  "EMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- input parameters
input int      InpPeriod   =  10;   // EMA Period

//--- indicator buffers
double         MABuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,MABuffer,INDICATOR_DATA);
   
//--- успешная инициализация
   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[])
  {
//--- в цикле от нуля (начало истории) до текущего бара
   for(int i=0; i<rates_total; i++)
     {
      double result=0;
      double smf=2.0/(InpPeriod+1.0);                       // фактор сглаживания
      double prev_value=(i>=1 ? MABuffer[i-1] : close[i]);  // предыдущее рассчитанное значение EMA
      
      //--- рассчитываем EMA на основании цены Close бара, прошлого значения EMA и фактора сглаживания
      result=close[i]*smf+prev_value*(1-smf);
      
      //--- Записываем результат расчёта в буфер
      MABuffer[i]=result;
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }

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

Индикатор EMAonPriceCloseRAW.mq5 можно посмотреть в приложенных к статье файлах.

Оптимизация расчётов

Сделаем экономный просчёт индикатора. На первом запуске он просчитает всю историю, а далее на каждом новом тике будет пересчитывать только текущий бар:

//+------------------------------------------------------------------+
//|                                              EMAonPriceClose.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot MA
#property indicator_label1  "EMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- input parameters
input int      InpPeriod   =  10;   // EMA Period

//--- indicator buffers
double         MABuffer[];

//--- global variables
int   ExtPeriod;  // период расчёта EMA
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,MABuffer,INDICATOR_DATA);
   
//--- успешная инициализация
   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[])
  {
//--- Корректируем введённое значение периода расчёта EMA
   ExtPeriod=(InpPeriod<1 ? 10 : InpPeriod);
   
//--- Если не хватает исторических данных для расчёта - возвращаем 0
   if(rates_total<ExtPeriod)
      return 0;
      
   int start=0;   // бар начала расчёта
   
//--- Если это первый запуск или изменение в исторических данных
   if(prev_calculated==0)
     {
      //--- инициализируем буфер индикатора пустым значением и устанавливаем начало расчёта на значение 0
      ArrayInitialize(MABuffer,EMPTY_VALUE);
      start=0;
     }
//--- Если это не первый запуск - началом расчёта будет текущий бар
   else
      start=prev_calculated-1;
      
//--- в цикле от значения start до текущего бара истории
   for(int i=start; i<rates_total; i++)
     {
      double result=0;
      double smf=2.0/(ExtPeriod+1.0);                       // фактор сглаживания
      double prev_value=(i>=1 ? MABuffer[i-1] : close[i]);  // предыдущее рассчитанное значение EMA
      
      //--- рассчитываем значение EMA для текущего бара цикла
      result=close[i]*smf+prev_value*(1-smf);
      
      //--- Записываем результат расчёта в буфер
      MABuffer[i]=result;
     }
     
//--- возвращаем количество посчитанных баров для следующего вызова OnCalculate
   return(rates_total);
  }

Если введено значение рассчитываемого периода меньше 1, то устанавливаем значение по умолчанию для скользящих средних равное 10.
Расчёт экспоненциальной скользящей средней использует ранее рассчитанное значение EMA на прошлом баре.

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

В данном индикаторе реализован экономный расчёт данных: при первом запуске просчитывается вся доступная история, а на последующих вызовах OnCalculate() просчитывается только текущий бар.

Файл индикатора EMAonPriceClose.mq5 можно посмотреть в прикреплённых к статье файлах.


Smoothed Moving Average (SMMA) — сглаженное скользящее среднее

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

SMMA:

  • Менее подвержена колебаниям, чем SMA и EMA, что делает её полезной для анализа более стабильных трендов,
  • Хорошо подходит для долгосрочного анализа, так как сглаживает резкие колебания цен,
  • Может использоваться для формирования более надежных торговых сигналов.

Рис.3. Сглаженное скользящее среднее. SMMA по ценам Close, с периодом расчёта 10

Расчёт

Первое значение сглаженного скользящего среднего рассчитывается, как простое скользящее среднее (SMA):

SUM1  = SUM(CLOSE(i), N)
SMMA1 = SUM1 / N 

Второе значение рассчитывается по следующей формуле:

SMMA(i) = (SMMA1*(N-1) + CLOSE(i)) / N

Все последующие значения скользящей средней рассчитываются по следующей формуле:

PREVSUM = SMMA(i - 1) * N
SMMA(i) =(PREVSUM - SMMA(i - 1) + CLOSE(i)) / N 

где:

  • SUM — сумма;
  • SUM1 — сумма цен закрытия N периодов, отсчитываемая от предыдущего бара;
  • PREVSUM — сглаженная сумма предыдущего бара;
  • SMMA(i-1) — сглаженное скользящее среднее предыдущего бара;
  • SMMA(i) — сглаженное скользящее среднее текущего бара (кроме первого);
  • CLOSE(i) — текущая цена закрытия;
  • N — период сглаживания.

В результате арифметических преобразований формула может быть упрощена:

SMMA(i) = (SMMA(i - 1) * (N - 1) + CLOSE(i)) / N 

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

//+------------------------------------------------------------------+
//|                                          SMMAonPriceCloseRAW.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1

//--- plot MA
#property indicator_label1  "SMMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- input parameters
input int      InpPeriod=10;  // SMMA Period

//--- indicator buffers
double         MABuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,MABuffer,INDICATOR_DATA);
   
//---
   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[])
  {
//---
   double result=0.0;
   for(int i=InpPeriod-1; i<rates_total; i++)
     {
      //--- первый расчёт
      if(i==InpPeriod-1)
        {
         //--- рассчитаем простую скользящую среднюю для InpPeriod первых баров
         for(int j=0; j<InpPeriod; j++)
           {
            double price=close[i-j];
            result+=price;
           }
         result/=InpPeriod;
         //--- записываем первое отображаемое значение SMMA, рассчитанное как SMA
         MABuffer[InpPeriod-1]=result;
        }
      //--- все последующие расчёты
      else
         result=(MABuffer[i-1]*(InpPeriod-1)+close[i])/InpPeriod;
      
      //--- Записываем результат расчёта в буфер
      MABuffer[i]=result;
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }

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

Оптимизация расчётов

Необходимо сделать контроль вводимого значения периода расчёта SMMA, полный расчёт всей истории при первом запуске, а далее — на каждом новом тике выполнять расчёт только на текущем баре:

//+------------------------------------------------------------------+
//|                                             SMMAonPriceClose.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot MA
#property indicator_label1  "SMMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- input parameters
input int      InpPeriod=10;

//--- indicator buffers
double         MABuffer[];

//--- global variables
int   ExtPeriod;  // период расчёта SMMA
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,MABuffer,INDICATOR_DATA);
   
//--- успешная инициализация 
   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[])
  {
//--- Корректируем введённое значение периода расчёта SMMA
   ExtPeriod=(InpPeriod<1 ? 10 : InpPeriod);
   
//--- Если не хватает исторических данных для расчёта - возвращаем 0
   if(rates_total<ExtPeriod)
      return 0;
      
   double result=0;
   int    start =0;
   
//--- Если это первый запуск или изменение в исторических данных
   if(prev_calculated==0)
     {
      //--- инициализируем буфер индикатора пустым значением и устанавливаем начало расчёта на значение ExtPeriod
      ArrayInitialize(MABuffer,EMPTY_VALUE);
      start=ExtPeriod;

      //--- рассчитаем простую скользящую среднюю для ExtPeriod первых баров
      for(int i=0; i<start; i++)
         result+=close[i];
      result/=ExtPeriod;
      //--- записываем первое отображаемое значение SMMA, рассчитанное как SMA
      MABuffer[start-1]=result;
     }
   else
      start=prev_calculated-1;
      
//--- в цикле от значения start до текущего бара истории
//--- рассчитываем значение SMMA для текущего бара цикла
   for(int i=start; i<rates_total; i++)
      MABuffer[i]=(MABuffer[i-1]*(ExtPeriod-1)+close[i])/ExtPeriod;
      
//--- возвращаем количество посчитанных баров для следующего вызова OnCalculate
   return(rates_total);
  }

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


Linear Weighted Moving Average (LWMA) — линейно-взвешенное скользящее среднее

Во взвешенном скользящем среднем последним данным присваивается больший вес, а более ранним — меньший. Это позволяет LWMA быть более чувствительной к недавним изменениям цен. В этой скользящей средней вес цен баров убывает линейно  — для нулевого (текущего) он максимален, для бара с номером N-1 равен 0.

LWMA:

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

Рис.4. Линейно-взвешенное скользящее среднее. LWMA по ценам Close, с периодом расчёта 10

Расчёт

Взвешенное скользящее среднее рассчитывается путем умножения каждой из цен закрытия в рассматриваемом ряду на определенный весовой коэффициент:

LWMA = SUM(CLOSE(i) * i, N) / SUM(i, N) 

где:

  • SUM — сумма;
  • CLOSE(i) — текущая цена закрытия;
  • SUM(i, N) — сумма весовых коэффициентов;
  • N — период сглаживания.

Напишем простой индикатор, показывающий расчёт линейно-взвешенной скользящей средней:

//+------------------------------------------------------------------+
//|                                          LWMAonPriceCloseRAW.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot MA
#property indicator_label1  "LWMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- input parameters
input int      InpPeriod=10;  // LWMA Period
//--- indicator buffers
double         MABuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,MABuffer,INDICATOR_DATA);
   
//---
   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[])
  {
//--- в цикле от InpPeriod-1 до текущего бара
   double result=0.0;
   for(int i=InpPeriod-1; i<rates_total; i++)
     {
      //--- рассчитываем веса (wsum) и сумму весовых коэффициентов (sum) InpPeriod баров
      double sum =0.0;
      int    wsum=0;
      for(int j=InpPeriod; j>0; j--)
        {
         wsum+=j;
         sum +=close[i-j+1]*(InpPeriod-j+1);
        }
      //--- получаем значение LWMA для текущего бара цикла
      result=sum/wsum;
      //--- Записываем результат расчёта в буфер
      MABuffer[i]=result;
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }

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

Файл индикатора LWMAonPriceCloseRAW.mq5 можно найти в прикреплённых к статье файлах.

Оптимизация расчётов

Оптимизируем расчёт индикатора, чтобы не было пересчёта всей истории на каждом тике, и добавим проверку введённого значения периода расчёта LWMA:

//+------------------------------------------------------------------+
//|                                             LWMAonPriceClose.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot MA
#property indicator_label1  "LWMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- input parameters
input int      InpPeriod   =  10;   // LWMA Period

//--- indicator buffers
double         MABuffer[];

//--- global variables
int   ExtPeriod;  // период расчёта LWMA
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,MABuffer,INDICATOR_DATA);
   
//--- успешная инициализация
   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[])
  {
//--- Корректируем введённое значение периода расчёта LWMA
   ExtPeriod=(InpPeriod<1 ? 10 : InpPeriod);
   
//--- Если не хватает исторических данных для расчёта - возвращаем 0
   if(rates_total<ExtPeriod)
      return 0;
      
   double result=0;
   int    start =0;
   
//--- Если это первый запуск или изменение в исторических данных
   if(prev_calculated==0)
     {
      //--- инициализируем буфер индикатора пустым значением и устанавливаем начало расчёта на значение ExtPeriod-1
      ArrayInitialize(MABuffer,EMPTY_VALUE);
      start=ExtPeriod-1;
     }
//--- Если это не первый запуск - началом расчёта будет текущий бар
   else
      start=prev_calculated-1;
      
//--- в цикле от значения start до текущего бара истории
//--- рассчитываем значение LWMA для текущего бара цикла
   for(int i=start; i<rates_total; i++)
     {
      //--- рассчитываем веса (wsum) и сумму весовых коэффициентов (sum) ExtPeriod баров
      double sum =0.0;
      int    wsum=0;
      for(int j=ExtPeriod; j>0; j--)
        {
         wsum+=j;
         sum +=close[i-j+1]*(ExtPeriod-j+1);
        }
      //--- получаем значение LWMA для текущего бара цикла
      result=sum/wsum;
      //--- Записываем результат расчёта в буфер
      MABuffer[i]=result;
     }
      
//--- возвращаем количество посчитанных баров для следующего вызова OnCalculate
   return(rates_total);
  }

О принципах экономного расчёта индикаторов подробно рассказано в разделе оптимизации простой скользящей средней.

Файл индикатора можно посмотреть в прикреплённых к статье файлах.


Преимущества и недостатки четырёх типов средних

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

Вот вкратце преимущества и недостатки четырёх базовых скользящих средних:

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

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

    Недостатки:
    • Реагирует на изменения медленно, что может привести к запоздалым сигналам,
    • Одинакова чувствительна к колебаниям цены на всём диапазоне периода расчёта (веса всех цен одинаковы).

  2. EMA (Экспоненциальная скользящая средняя) придает большее значение последним ценам, что делает её более чувствительной к новым изменениям цен. Используется для более быстрых сигналов для открытия и закрытия позиций. Предпочитается краткосрочными трейдерами и скальперами, которые ищут более быстрые входы и выходы на рынке.

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

    Недостатки:
    • Может давать ложные сигналы при резких колебаниях рынка.
    • Сложнее в расчете по сравнению с SMA.

  3. SMMA (Сглаженная скользящая средняя) считается более сглаженной версией EMA и SMA, что позволяет избежать резких колебаний, сохраняя при этом актуальность информации. Подходит для тех трейдеров, которые хотят избежать ложных сигналов, удобна для анализа и подтверждения тренда.

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

    Недостатки:
    • Может медленно реагировать на изменения рынка, подобно SMA.
    • Возможны задержки для обнаружения трендов.

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

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

    Недостатки:
    • Сложнее в расчете, особенно по сравнению с SMA и EMA.
    • Может также давать ложные сигналы на нестабильных рынках.



Заключение

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

На рисунке выше показана разница между одинаковыми по периоду расчёта (10) скользящими средними, но разными по типу:

Красная - SMA, зелёная - EMA, золотистая - SMMA, синяя - LWMA.

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

Подводя итоги, резумируем:

Скользящая средняя (SMA) — это статистический метод, используемый для анализа временных рядов и сглаживания данных, что позволяет выявить тренды и краткосрочные направленные движения, динамические уровни поддержки/сопротивления, границы каналов и т.п. Первые применения концепции скользящей средней датируются началом XX века, когда экономисты и инженеры начали использовать её для анализа данных и предсказания будущих значений. Что интересно, во второй мировой войне расчёты зенитных орудий для целеуказания использовали методы расчёта SMA.

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

На одном и том же графике цены, скользящие средние с одинаковым периодом расчёта, но различными типами будут по-разному отображать данные:

  • SMA будет более гладким и будет показывать уровень поддержки или сопротивления, но с задержкой,
  • EMA будет следовать за ценами, располагаясь ближе к цене и быстрее реагируя на изменения тренда,
  • SMMA будет представлять собой более сглаженную линию, чем SMA, с меньшей реакцией на резкие изменения,
  • LWMA будет также быстро реагировать на изменения, но его поведение будет более волатильным по сравнению с EMA и SMMA.

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


Таблица-список прикреплённых файлов:

#
Тип
Имя 
 Описание
1
Индикатор
SMAonPriceCloseRAW.mq5
Индикатор с примером расчёта SMA. Только грубый расчёт, без организации экономного просчёта индикатора и без оптимизации рассчётов
2
Индикатор
SMAonPriceCloseECO.mq5
Индикатор, рассчитывающий SMA. Организован экономный просчёт индикатора без оптимизации рассчётов
3
Индикатор
SMAonPriceClose.mq5
Индикатор, рассчитывающий SMA. Организован экономный просчёт индикатора с оптимизацией рассчётов SMA
4
Индикатор
EMAonPriceCloseRAW.mq5
Индикатор с примером расчёта EMA. Только грубый расчёт, без организации экономного просчёта индикатора
5
Индикатор
EMAonPriceClose.mq5
Индикатор, рассчитывающий EMA. Организован экономный просчёт индикатора
6
Индикатор
SMMAonPriceCloseRAW.mq5
Индикатор с примером расчёта SMMA. Только грубый расчёт, без организации экономного просчёта индикатора
7
Индикатор
SMMAonPriceClose.mq5
Индикатор, рассчитывающий SMMA. Организован экономный просчёт индикатора
8
Индикатор
LWMAonPriceCloseRAW.mq5
Индикатор с примером расчёта LWMA. Только грубый расчёт, без организации экономного просчёта индикатора
9
Индикатор
LWMAonPriceClose.mq5
Индикатор, рассчитывающий LWMA. Организован экономный просчёт индикатора
Последние комментарии | Перейти к обсуждению на форуме трейдеров (2)
Alexey Viktorov
Alexey Viktorov | 18 нояб. 2024 в 14:33

Спасибо за хорошую статью. Но всё-же не могу не покритиковать. Такое у меня сегодня настроение.

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

lynxntech
lynxntech | 18 нояб. 2024 в 15:11

полезная информация, сразу в одном месте,

и наконец-то i++ цикл

Нейросети в трейдинге: Повышение эффективности Transformer путем снижения резкости (Окончание) Нейросети в трейдинге: Повышение эффективности Transformer путем снижения резкости (Окончание)
SAMformer предлагает решение ключевых проблем Transformer в долгосрочном прогнозировании временных рядов, включая сложность обучения и слабое обобщение на малых выборках. Его неглубокая архитектура и оптимизация с учетом резкости обеспечивают избегание плохих локальных минимумов. В данной статье мы продолжим реализацию подходов с использованием MQL5 и оценим их практическую ценность.
Изучение MQL5 — от новичка до профи (Часть VI):  Основы написания советников Изучение MQL5 — от новичка до профи (Часть VI): Основы написания советников
Статья продолжает цикл для начинающих. Здесь будут рассмотрены основные принципы построения советников. Мы создадим два советника: первый будет торговать без индикаторов, отложенными ордерами, второй — на основе стандартного индикатора MA, торгующий с помощью сделок по текущей цене. Здесь я предполагаю, что вы уже не совсем новичок и владеете материалом предыдущих статей относительно свободно.
Разрабатываем мультивалютный советник (Часть 20): Приводим в порядок конвейер этапов автоматической оптимизации проектов (I) Разрабатываем мультивалютный советник (Часть 20): Приводим в порядок конвейер этапов автоматической оптимизации проектов (I)
Мы создали уже довольно много компонентов, которые помогают организовать процесс автоматической оптимизации. При создании мы придерживались традиционной цикличности: от создания минимального рабочего кода до рефакторинга и получения улучшенного кода. Пришло время заняться наведением порядка в нашей базе данных, которая тоже является ключевым компонентом в создаваемой системе.
Нейросети в трейдинге: Повышение эффективности Transformer путем снижения резкости (SAMformer) Нейросети в трейдинге: Повышение эффективности Transformer путем снижения резкости (SAMformer)
Обучение моделей Transformer требует больших объемов данных и часто затруднено из-за слабой способности моделей к обобщению на малых выборках. Фреймворк SAMformer помогает решить эту проблему, избегая плохих локальных минимумов. И повышает эффективность моделей даже на ограниченных обучающих выборках.