So in my continuing series of C# implementations of common indicators, I spent all of yesterday working out the ADX. The ADX was originally developed by J. Welles Wilder and published in his book New Concepts in Technical Trading Systems, June 1978.

Various sites report implementations, but always define it in terms of indicators which have varying definitions. Namely FxStreet defines the general concept here, but only in terms of DI+/-, TR and DM+/-, each of which has varying definitions. ForexReal defines ADX here, but uses a completely different concept of TR. Stockwiz has a good overview of all of the variables used (at least they define all of their variables) here. I will be defining the ADX all the way down to price action (what you need when you are coding this…) as best I can to the original definition by J Welles Wilder.

Lets start by defining the Directional Move indicators

## Directional Move Indicator

= the Positive Direction Movement Indicator

= the Negative Direction Movement Indicator

We use two helper variables to track the delta extreme price changes from yesterday

If today’s range is entirely within yesterday’s range, or the range is the same, then there has been no directional movement.

If the range moved up, then there has been a positive directional move.

If the range moved down, then there has been a negative directional move.

## Average Directional Move Indicator

= the Average Positive Direction Movement Indicator for N periods

= the Average Negative Direction Movement Indicator for N periods

The Welles Wilder Average is used here to stay true to form, but this average introduces a lot of latency, so I will also implement an exponential moving average.

Alternatively, the formula for the ADM with an exponential moving average is shown below.

## True Range

is the true range for a given period. It is a measure of volatility and takes into account any overnight gap in the period’s price.

## Average True Range

is the average true range for N periods.

The Welles Wilder Average is used here again to stay true to form, but for my C# implementation I will be using the exponential moving average.

Alternatively the ATR can be calculated with the exponential moving average as shown below.

## Directional Index

is the average positive directional movement indicator normalized by the average true range.

is the average negative directional movement indicator normalized by the average true range.

The directional index calculation is very straight forward and shown below.

## Directional Movement Index

– the directional movement index is the difference of the directional indices over the sum directional indices.

## Average Directional Movement Index

is the average directional movement calculated over N periods.

Staying true to form again, the Welles Wilder Average is used below.

Again, you can alternatively use the exponential moving average as shown below.

## C# implementation

So after the laborious research to determine exactly what the ADX is and should be (exponential vs Welles Wilder Average), here is the C# implementation of this indicator.

//The Average Directional Indicator

if(barHistory[timePeriod].Count > 1)

{

//Directional Movement Indicator

double deltaHigh = cBar.High – barHistory[timePeriod][barHistory[timePeriod].Count – 2].High;

double deltaLow = barHistory[timePeriod][barHistory[timePeriod].Count – 2].Low – cBar.Low;

if((deltaHigh < 0 && deltaLow < 0) || (deltaHigh == deltaLow))

{

sig.DmPlus = 0;

sig.DmMinus = 0;

}

else

if(deltaHigh > deltaLow)

{

sig.DmPlus = deltaHigh;

sig.DmMinus = 0;

}

else

if (deltaHigh < deltaLow)

{

sig.DmPlus = 0;

sig.DmMinus = deltaLow;

}

//Average Directional Movement Indicator

if(barHistory[timePeriod].Count <= 2)

{

sig.AdmPlus = sig.DmPlus;

sig.AdmMinus = sig.DmMinus;

}

else

{

double a = (double) 2/(double) (calc.DMIPeriod + 1);

sig.AdmPlus = sig.DmPlus * a +

symbolHistory[timePeriod][symbolHistory[timePeriod].Count-2].AdmPlus * (1-a);

sig.AdmMinus = sig.DmMinus * a +

symbolHistory[timePeriod][symbolHistory[timePeriod].Count – 2].AdmMinus * (1 – a);

}

//True Range Indicator

sig.TrueRange = Math.Max(Math.Abs(cBar.High – cBar.Low),

Math.Max(

Math.Abs(cBar.High – barHistory[timePeriod][barHistory[timePeriod].Count – 2].Close),

Math.Abs(barHistory[timePeriod][barHistory[timePeriod].Count – 2].Close – cBar.Low)));

//Average True Range Indicator

if(barHistory[timePeriod].Count <= 2)

{

sig.AverageTrueRange = sig.TrueRange;

}

else

{

double a = (double)2 / (double)(calc.ADXPeriod + 1);

sig.AverageTrueRange = sig.TrueRange * a +

symbolHistory[timePeriod][symbolHistory[timePeriod].Count – 2].AverageTrueRange * (1 – a);

}

//Directional index Indicator

if (sig.TrueRange != 0)

{

sig.DiPlus = 100 * sig.AdmPlus/sig.TrueRange;

sig.DiMinus = 100 * sig.AdmMinus/sig.TrueRange;

}

else

{

sig.DiPlus = symbolHistory[timePeriod][symbolHistory[timePeriod].Count – 2].DiPlus;

sig.DiMinus = symbolHistory[timePeriod][symbolHistory[timePeriod].Count – 2].DiMinus;

}

//Directional Movement Index Indicator

if ((sig.DiPlus + sig.DiMinus) != 0)

sig.Dx = Math.Abs((sig.DiPlus – sig.DiMinus)) / (sig.DiPlus + sig.DiMinus) * 100;

else

sig.Dx = symbolHistory[timePeriod][symbolHistory[timePeriod].Count – 2].Dx;

//Average Directional Movement Indicator

if (barHistory[timePeriod].Count <= 2)

{

sig.Adx = sig.Dx;

}

else

{

double a = (double)2 / (double)(calc.DMIPeriod + 1);

sig.Adx = sig.Dx * a +

symbolHistory[timePeriod][symbolHistory[timePeriod].Count – 2].Adx * (1 – a);

}

}

## Sample Data

This is a sample data set consisting of the NYSE A/D 1-min bar data (“Close”) from August 28, 2007 and the 14 period ADX in red.