Own ADX Indicator Calculation in Excel

Hi, I have implemented formula of ADX in excel referring to this link. My values are verified with the amibroker to some extent but in some cases, it’s not. What I can see is there is a difference in values when High Difference and Low Difference are same.
Please open the attachment and check, I have marked the corner cases in red color. You can find row number 202, where there is a difference in ADX values.

@chinta I don’t see any attachment. However, as a general rule I have found that AmiBroker’s implementation of indicators is extremely accurate, so I would double-check your own formula first.

@chinta - in once sentence: there is no attachment in your post but it does not matter as you can be 100% sure that AmiBroker ADX is correct. Check your math. Use original Wilders’ book and make sure you are using proper Wilders smoothing. Once done correctly you would have same results as AmiBroker.

1 Like

I am really sorry but I forgot to attach the attachment. Amibroker forum is not allowing me to attach excel file, so I am attaching the snapshot from excel file of the issue that I am facing.I want to clarify one point that I am not doubting the formula implemented by Ambroker, I just want your help in understanding how it is implemented.
In the attached snapshot, you can see my values are matching with Amibroker to some extent, but at row 204 they are different.
Can someone please help me figure what I might be doing wrong?ADXIssue

Looks like since your values are matching with Amibroker your smoothing techniques are correct. I guess only when both HighDiff and LowDiff are same your values are not matching.

@Tomasz In case the difference between high and low is same, which one do we consider for the indicator calculation?

Sorry, but we do not debug user excel sheets here. Our code is written in highly optimized C++ and x86/x64 assembly, not in Excel. At first your “ADX amibroker” column does not show actual values in AmiBroker but values rounded to 2 decimal digits. If you used proper formatting option in exploration’s AddColumn you would get more digits. Row 191 marked in red is nothing more than rounding.

AddColumn( ADX( 14 ), "ADX", 1.5 ); // example

As for row 204 you need to find the reason yourself as a) we don’t have crystal ball to know what formula you used in Excel; b) we really do not provide Excel support here

Also recommended reading is http://www.amibroker.com/kb/2010/07/20/about-floating-point-arithmetic/

You can’t attach .XLS files in this forum because .XLS and .DOC files can contain macros and they are pretty often used by viruses and we won’t allow this forum as potential virus spreading medium.

@Tomasz Thanks a lot for your response. I would like to share the C++ code snippet that I am using for ADX Calculation.

for(int ii=m_iStartIndex; ii<=m_iEndIndex; ii++)
        if(ii < 1) {
                m_pdValue[ii] = 0;
        double dHighDiff = (m_pdHigh[ii] - m_pdHigh[ii-1]);
        double dLowDiff = (m_pdLow[ii-1] - m_pdLow[ii]);
        m_dPlusDM[ii] = (dHighDiff > dLowDiff && dHighDiff > 0 ) ? dHighDiff : 0;
        m_dMinusDM[ii] = (dLowDiff > dHighDiff && dLowDiff > 0) ? dLowDiff : 0;
        m_dEMAPlusDM[ii] = (m_dEMAPlusDM[ii-1] * (m_iPeriod-1) + m_dPlusDM[ii])/m_iPeriod;
        m_dEMAMinusDM[ii] = (m_dEMAMinusDM[ii-1] * (m_iPeriod-1) + m_dMinusDM[ii])/m_iPeriod;
        if(m_dATR[ii] == 0 || ((m_dEMAPlusDM[ii] + m_dEMAMinusDM[ii]) == 0)) {
        m_dPlusDI[ii] = 100 * m_dEMAPlusDM[ii] / m_dATR[ii];
        m_dMinusDI[ii] = 100 * m_dEMAMinusDM[ii] / m_dATR[ii];
        m_dDirectionalIndex[ii] = 100 * abs((m_dPlusDI[ii] - m_dMinusDI[ii])/(m_dPlusDI[ii] + m_dMinusDI[ii]));
        m_dADXValue[ii] = (m_pdValue[ii-1]*(m_iPeriod-1)+m_dDirectionalIndex[ii])/m_iPeriod;

Please assume that m_dATR is updated in some other location and it’s value is correct, I can understand that with this implementation the initial values will be different but I am okay with that as I will always have huge historical data in my database to tune the indicator.
I can understand that Amibroker values are rounded off in my file, I marked row 191 and row 204 for some different reason as follows:
As @dagapiyush has pointed it out, In both the rows, High difference and the low difference is same and I would like to know what should be done in such scenario out of following cases:
a) Both +DM and -DM are 0.
b) +DM equals High Difference and -DM 0.
c) -DM equals Low Difference and +DM 0.
I am going with the “case a”, for which my answer is correct for row 191 (as it is rounded off and I am fine with it) and it is not for row 204.
Please help me understand the reason behind this and how to handle it. Thanks again :slight_smile:

1 Like

Hi @chinta,

:ok_man: 5 months late, recently, I was also looking for the same and saw this post. Below is my solution which repaints the inbuilt functions as hinted by Tomasz.

	 per = Param( "Period", 14, 3, 89, 1 );
	 TR = Max( H - L, Max( abs( H - Ref( C, -1 ) ), abs( L - Ref( C, -1 ) ) ) );
	 pDMI = IIf( H - Ref( H, -1 ) > Ref( L, -1 ) - L, Max( H - Ref( H, -1 ), 0 ), 0 );
	 mDMI = IIf( Ref( L, -1 ) - L > H - Ref( H, -1 ), Max( Ref( L, -1 ) - L, 0 ), 0 );
	 avgTR = Wilders( TR, per );
	 avgPDI = Wilders( pDMI, per );
	 avgMDI = Wilders( mDMI, per );
	 perPDI = ( avgPDI / avgTR ) * 100;
	 perMDI = ( avgMDI / avgTR ) * 100;
	 diff = abs( perPDI - perMDI );
	 add = perPDI + perMDI;
	 DX = ( diff / add ) * 100;
	 _ADX = Wilders( DX, per );
	 Plot( _ADX, "ADX", ParamColor( "ADX color", colorBlue ), ParamStyle("ADX style", styleThick ) );
	 Plot( perPDI, "+DI", ParamColor( "+DI color", colorGreen ), ParamStyle("+DI style") );
	 Plot( perMDI, "-DI", ParamColor( "-DI color", colorRed ), ParamStyle("-DI style") );

Inbuit ADX, PDI and MDI:

range = Param("Periods", 14, 2, 200, 1 );
Plot( ADX(range), _DEFAULT_NAME(), ParamColor( "ADX color", colorBlue ), ParamStyle("ADX style", styleThick ) );
Plot( PDI(range), "+DI", ParamColor( "+DI color", colorGreen ), ParamStyle("+DI style") );
Plot( MDI(range), "-DI", ParamColor( "-DI color", colorRed ), ParamStyle("-DI style") );

@Lennon I found your very old note using the site Search function. Thanks for sharing the AFL code for a manual computation of the ADX indicator. It was very useful to me.

Hi @Russman,

Glad to see that you are using the Search to find solutions. In case you are wondering how the inbuilt Wilders function calculates internally, here is a snippet for you. Do play with the GUI checkboxes! :slight_smile:

SetChartBkColor( colorBlack );
SetChartOptions( 0, chartShowDates | chartLogarithmic );
Plot( C, "Price", colorDefault, styleCandle );

GuiSetFont( "Courier New", 10 );
ChkBxEMAId = 1;
GuiCheckBox( "EMA", ChkBxEMAId, 5, 18, 40, 20, notifyClicked );
ChkBxWldrsId = ChkBxEMAId + 1;
GuiCheckBox( "Wilders", ChkBxWldrsId, 5, 35, 80, 20, notifyClicked );
GuiSetColors( ChkBxEMAId, ChkBxWldrsId, 1, clrText = colorWhite, clrBk = colorDefault, clrBor = colorDefault );

n = Param( "Wilders Period", 10, 1, 100, 1 );
fEMA = 2 / ( n + 1 ); // EMA Factor
fWilders = 1 / n; 	  // Wilders Factor

if( GuiGetCheck( ChkBxEMAId ) ) {
	 CustomEMA = AMA( C, fEMA );
	 Plot( EMA( C, n ), "Inbuilt EMA", colorGold, styleDots | styleNoLine | styleThick );
	 Plot( CustomEMA, "Custom EMA", colorWhite );

if( GuiGetCheck( ChkBxWldrsId ) ) {
	 CustomWilders = AMA( C, fWilders ); // Double-smoothed EMA
	 Plot( Wilders( C, n ), "Inbuilt Wilders", colorGold, styleDots | styleNoLine | styleThick );
	 Plot( CustomWilders, "CustomWilders", ColorRGB( 70, 160, 255 ) );

As you would notice, both EMA and Wilders uses the same AMA (Adaptive Moving Average) function, the difference is in their factors. Hence, Wilders Smoothed Moving Average (WSMA) is simply a double-smoothed Exponential Moving Average (EMA). For instance, a 19-period EMA is identical to 10-period WSMA:

PerEMA = Param( "EMA Periods", 19, 1, 300, 1 );
PerWilders = Param( "Wilders Periods", 10, 1, 300, 1 );
Plot( EMA( C, PerEMA ), "EMA", colorGold, styleDots | styleNoLine | styleThick );
Plot( Wilders( C, PerWilders ), "Wilders", ColorRGB( 70, 160, 255 ) );

Now, if you further dive deep and question what is AMA? Then, follow Tomasz's technique:

for( i = 1; i < BarCount; i++ )
     output[ i ] = factor[ i ] * input[ i ] + ( 1 - factor[ i ] ) * output[ i - 1 ];

(Example taken from AMA function guide)

Now you will be able to comprehend how EMA and its variations are calculated internally.


Hi @Cougar

For someone like me who does not have a programming background, I have managed to accomplish some very useful things using Amibroker in terms of charting, system backtesting and indicator creation. The examples you provided in your reply, which obviously come from someone with much more experience, will undoubtedly allow me to further my knowledge and are much appreciated. :smiley:


Experience creates discrimination. Everyone carry their own experience, their own discrimination otherwise known as perception. Surpass that perception and you have realization. This realization is unique and same for all. Its a proof that we are all the same from the same but appear in different forms just like our ideas. :+1:


Thank you both