ADX Issues - When accessed from AFL


Not able to generate ADX values from AFL - but the same is available in the charts using the builtin functions.


Trying to access the same using AFL code as below:

Filter = 1;
AddColumn(C, "Close");
AddColumn(PDI(), "PDI");
AddColumn(MDI(), "MDI");
AddColumn(ADX(), "ADX");

Getting correct values for PDI, MDI but ADX which calculates of these two values is showing as below:


@Tomasz - any inputs on the above Tomas ?

From my experience, this kind of problem is related to your data, may be some NULLs ?

@awilson - thought of that - but the same data is used for the graph and it works.

Also, ADX() is calculated using PDI() and MDI() values - both of which are calculated correctly and match the numbers on the graph. So see no reason why ADX() is behaving weirdly.

@virtualkg: when you see something different on a chart than in an exploration or other analysis, the underlying cause is often Pad & Align. One thing that will cause the ADX behavior that you've observed is when there are enough consecutive bars that all have the same price data, which is exactly what happens when you have data holes that are filled by Pad & Align. Since I use Pad & Align nearly all the time, I wrote my own "safe" version of ADX that can recover even when this condition occurs. The output of this function does not perfectly match the built-in ADX function on the early bars in the array, but ADX() and SafeADX() converge reasonably quickly and the values are close enough for my purposes. Someone else might be able to come up with an even better alternative, but the function below is at least a place to start.

// Calculate ADX in a way that does not fail when prices are the same for an extended period of time

function SafeADX(range)
	upMove = H - Ref(H,-1);
	downMove = Ref(L,-1) - L;
	posDM = IIf(upMove > 0 AND upMove > downMove, upMove, 0);
	negDM = IIf(downMove > 0 AND downMove > upMove, downMove, 0);
	trueRange = ATR(1);
	avgPosDM = Wilders(posDM, range);
	avgNegDM = Wilders(negDM, range);
	avgTrueRange = Wilders(trueRange, range);
	posDI = IIf(avgTrueRange == 0, 0, 100 * avgPosDM/avgTrueRange);
	negDI = IIf(avgTrueRange == 0, 0, 100 * avgNegDM/avgTrueRange);
	dx = IIf((posDI + negDI) == 0, 0, 100 * abs(posDI - negDI) / (posDI + negDI));
	avgDX = Wilders(dx, range);
	return avgDX;

nPeriods = Param("Periods", 14, 2, 200, 1);

Plot(SafeADX(nPeriods), "SafeADX("+nPeriods+")", ParamColor("SafeADX Color", colorBlue), ParamStyle("SafeADX style", styleThick));

// For testing
Filter = True;
AddColumn(ADX(nPeriods), "Standard ADX("+nPeriods+")");
AddColumn(SafeADX(nPeriods), "SafeADX("+nPeriods+")");

That does not seem to be true. I've created some data holes with a few weeks of missing bars and have checked pad&align (pad&align symbol has all data for that period) and ADX(10) still outputs normal repeating ADX values without "1.#R".

1 Like

I believe the issue may only occur when the duplicate data occurs before there have been enough bars to calculate the first valid ADX value. For example, in my Norgate database this occurs with CRH, which has its first quote on 11-Jan-1990 and the second quote on 28-Feb-1990. AmiBroker calculates the first ADX(14) value on 23-Feb-1990, and that value is displayed in an Exploration as 1.#R not only on 23-Feb-1990 but for the entire history of CRH.

Other symbols show similar behavior, although some have a value of -1.#J instead of 1.#R. I suspect the difference is related to whether DI+ or DI- cannot be calculated, but haven't spent the time to nail down all the nuances.

1 Like

@mradtke - while what you are saying might sense if even the PDI() and MDI() values where showing 1.#R, but they are computing just fine.

As seen from the code (your's) below:

dx = IIf((posDI + negDI) == 0, 0, 100 * abs(posDI - negDI) / (posDI + negDI));
avgDX = Wilders(dx, range);

ADX is derived from PDI() and MDI() - so the underlying data (corruption/missing/hole, etc) should be immaterial. Furthermore, it can be seen from the graph that the data is continuous and non-pad aligned and so even that argument doesn't hold good.

@Tomasz - please share your input. Please help us understand why and how there is a difference between the values shown for ADX in the chart and using AFL - when they are effectively calling the same underlying builtin function call (i.e) ADX() on the same data ?

@virtualkg the chart proves nothing because it's not showing ALL of your data. I gave you code that you could copy and paste and run as an exploration. Did you even try it? Also, did you verify whether P&A is enabled or disabled in your analysis settings? If it's enabled, I would suggest disabling it and running your original test again to see if you get different results.

All those -1.#J, -1.#R are different forms of not-a-number, infinity, etc. Typically result of invalid (illegal) operation like division by zero, log from negative number, square root from negative number, etc. If you are getting those, it means that your code (or your data) cause illegal arithmetic operation. In majority of cases in T/A software this means division by zero (like for example dividing by H-L difference when H and L are the same). Read this: