Расчет индикатора достаточно громоздкий.
Шаг 1
Рассчитывается положительное и отрицательное направленное движение +DM и –DM, на основании правил, которые показаны на рис..
Эти правила могут быть формализованы следующим образом.
Если Ht > Ht-1, то +DMt = Ht – Ht-1, иначе +DMt = 0
Если Lt < Lt-1, то –DMt = Lt-1 – Lt, иначе –DMt = 0
Меньшее из +DMt и –DMt приравнивается к нулю. А если они равны друг другу, то к нулю приравниваются оба.
Шаг 2
Вычисляется истинный диапазон TR (True Range)
TRt = max( |Lt – C t-1|, |Ht – Ct-1|, |Ht – Lt| )
Шаг 3
Вычисляем сглаженные индикаторы положительного направления +DI и отрицательного направления –DI.
Если TRt = 0, то +SDIt = 0 и –SDIt = 0,
Если TRt ≠ 0, то +SDIt = +DMt / TRt и –SDIt = –DMt / TRt.
Сглаживая +SDI и -SDI экспоненциальным скользящим средним (EMA) с периодом Period, получаем
+DIt = EMA( +SDI, Period),
–DIt = EMA(–SDI, Period).
Шаг 4
Вычисляем среднее направленное движение ADX.
Для этого сначала находим направленное движение DX.
DXt = (|+DIt – –DIt| / |+DIt + –DIt|) × 100.
Затем, сглаживая ряд DX, получаем значение ADX:
ADXt = EMA (DX, Period).
Индикатор ADX показывает силу тенденции, которая определяется как частота и величина формирования новых экстремумов. При росте индикатора ADX, можно говорить о том, что рыночный тренд становится сильнее. Падающий индикатор ADX сигнализирует, что доминирующая тенденция на рынке ослабевает или меняется. Линии +DI и –DI показывают превалирование новых максимумов или минимумов в текущем движении цены.
Типовые параметры
Для индикатора обычно используется следующее типовое значение параметра Period = 14 на дневном тайм-фрейме.
Сигналы
- ADX растет – показывает силу текущей тенденции.
- ADX начинает расти из области менее 15 – начало тенденции после консолидации.
- Пересечение +DI и -DI определяет направление сигнала.
Автор: Уэллс Уайлдер (Welles Wilder).
Первоисточник: Welles Wilder. New Concepts in Technical Trading Systems. 1978.
Пример:
Исходный текст:
Код: Выделить всё
function Initialize()
{
  IndicatorName = "ADX";
  PriceStudy = false;
  AddInput("Input", Inputs.Candle);         
  AddParameter("Period", 14);
  AddSeries("ADX", DrawAs.Line, Color.Blue);   
  AddSeries("DIP", DrawAs.Line, Color.Green);   
  AddSeries("DIN", DrawAs.Line, Color.Red);     
  AddGlobalVariable("DIp", Types.Double, 0.0);
  AddGlobalVariable("DIn", Types.Double, 0.0);
  AddGlobalVariable("vATR", Types.Double, 0.0);
}
function Evaluate()
{
// AlfaDirect. 2015. OX 
// ADX (Average Directional Index) Сглаживание EMA.
// Реализация MQL
double KC = (double)2.0 / (Period + 1.0);
double KE = 1.0 - KC;
if (CurrentIndex == 0)
{
   DIp = 0.0;    DIn = 0.0;    DIP = 0.0;    DIN = 0.0;    ADX = 0.0;
    vATR = Input.High[0] - Input.Low[0];
}
else
{
    // Расчет (DX+    DX-) --------------------------
    double dH = Input.High[0] - Input.High[-1];         
    double dL = Input.Low[-1] - Input.Low[0];
   double DXp = 0.0; 
   double DXn = 0.0; 
    if (dH > 0.0)  
       DXp = dH; 
    else 
       DXp = 0.0;
    if (dL > 0)
        DXn = dL; 
    else 
        DXn = 0.0; 
    if (DXp == DXn)
    {
       DXn = 0.0;         DXp = 0.0; 
    }
    
    if (DXp > DXn)
       DXn = 0.0; 
    
    if (DXp < DXn)
       DXp = 0.0; 
    
    // Расчет TR --------------------------------------------------
    double TR = Math.Max(Math.Max(Math.Abs(Input.High[0] - Input.Low[0]), Math.Abs(Input.High[0] - Input.Close[-1])), Math.Abs(Input.Low[0] - Input.Close[-1]));
       vATR = KE*vATR + KC*TR;
         
    // Расчет (DI+  DI-) ----------------------------------------------
    if (vATR < 0.00000000001)
    { 
        DIp = KE*DIp;  
        DIn = KE*DIn;  
        DIP = DIP[-1];
        DIN = DIN[-1];
    }
    else
    {
        DIp = KE*DIp + KC*DXp;  
        DIn = KE*DIn + KC*DXn;  
        DIP = DIp / vATR * 100.0;
        DIN = DIn / vATR * 100.0;
    }
    // ADX --------------------------------
    double  div = ( DIP[0] + DIN[0] );
    double  Buffer = 0.0;
    if (div == 0.0)  
        Buffer = 0.0;
    else
        Buffer = 100.0 * (Math.Abs(DIP[0]-DIN[0]) / div);
    ADX = KE*ADX[-1] + KC*Buffer;  
}
}
Индикатор является встроенным индикатором, поэтому создавать пользовательский индикатор не имеет смысла.


