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.
Hola, muy buena argumentacion respaldada por su respectiva implementacion en C#, solo me queda una duda,
puede que en esta parte:
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.
se te halla pasado y colocaste el calculo del indicador True Range en Lugar de DX ?
Saludos.
Wow, this is awesome, exactly what I was looking for. Thank you.
At 14:24, the ADX takes off and climbs to .35 while the price barely moves. Shouldn’t the ADX be falling during this period?
Ah, I see now that you are comparing it w/ the NYSE A/D 1-min bar data.
I have not been able to get this formulas equal to the Marketscope ADX values. For some reason the first adx calculated is equal, but from the 2nd Adx it is not getting equal. Did you check the values that your formulas calculate against any other tool? It seems that it’s something about the Average Directional Movement Indicator, because the ATR i’m getting through your formulas is accurate against de Marketscope ATR.
Anyway your post has been so helpfull, but I want to get values that match exactly compared to the marketscope tool so I can verify more clearly my strategy.
The ADX formula is wrong. Replace the TR with DX and it works fine for me. Besides that, GREAT work
Great work – I’ve been struggling to build this myself due to the complexity of the indicator. This helped me a lot and is the best explanation I’ve seen on the web. Thanks!
I did it this way (for DMI and -DMI only). I didn’t really get ur method (iam not that good at math lol)
Used a array for the Low,High,Close data’s named Quotes. Any feedback is welcome =)
private void CalcDMI()
{
decimal TR = 0;
decimal DMP = 0;
decimal DMM = 0;
for (int x = 0; x 0 && HD > LD) ? HD : 0;
DMM = (LD > 0 && LD > HD) ? LD : 0;
}
PDI = (DMP * 100) / TR;
MDI = (DMM * 100) / TR;
}
hmm my reply is all f*cked up =( guess i cant post that many chars, nvermind than xD. srry!
Hi,
ultimately which indicator do you recomend between the exponential MA and the Welles Wilder Avergae ? It seems to me that the 14 days Wilder average is like a 27 exponential moving average … but i’d like to get a confirmation on what to use …
TKs a lot for all the formula though !
@cdm: yes, the length ‘n’ wilder average is just a length ’2n-1′ EMA.
Thanks a bunch! This formula was just what I needed for my school report.
ciao,
q.
Thanks for a detailed explanation on ADX, it was quite informative. Thanks again for the good work
Great Work, I implemented the same but in a much more gruesome brute force kinda manner. Knowing the formula helps and simplifies it a lot.
Do you have the src for this available? if not then its fine.
Thanks anyways
Hello everyone… how exactly should i get the Previous parameters (t-1)? e.g. when the formula says: PlusADM(t) = PlusADM(t-1)*(1-n/n)+(PlusDM(t))*(1/n) ; when the PlusADM(t-1) should come from? if i starts by the order from the begining, and i have only current and historical data for open, close, high, and low parameters so when High(t) means the high for November 5 then high(t-1) means high of november 4, it’s makes sense for PlusDM and MinusDM since they depend only on the parameters of open and close data and we can get them, but the PlusADM(t=Nov5 for example) defined with the previous PlusADM in it [PlusADM(Nov4)] so where it’s should starts from (and if you can get the historical PlusADM (for Nov4) then what’s the point in all that formula?), i don’t have the Nov4 PlusADM so assuming i start the application on Nov5 the current PlusADM cannot be defined right? what i miss here?
thanx alot.
Can you send me all source code of you class please. It’ll be very helpful.
Thanks.
what values do you take for t-1 when considering calculations for the first day? Do caclulations really only start on Day 2 since that is only when one has previouos days’ data to use in calc?
click here
If a brand-new article becomes available or if any changes happen on this site I’m interested.