Skip to content
Level 1 · Chart ReaderLessonPart 06 · page 4 of 1126 min
26Minutes
6AFL functions
8Sources
StandardRequires
AFL functions taught here6

ADX and Directional Movement

ADX is the indicator most often misread in a single specific way: people watch it rise and conclude that price is going up. It cannot say that. By construction it discards the sign of the move and keeps only the magnitude. This lesson explains what it does keep, what AmiBroker documents about it and — just as important — what AmiBroker does not.

What the directional movement family measures

Section titled “What the directional movement family measures”

The family has three published pieces, and AmiBroker exposes each as its own function.

Directional movement compares how far today’s bar extended beyond yesterday’s in each direction. In the construction Wilder published, a bar has upward directional movement when its high exceeds yesterday’s high by more than yesterday’s low exceeds its low, and downward directional movement in the mirror case. A bar that is entirely inside yesterday’s range has neither. Those raw values are then scaled by the bar’s true range, smoothed, and multiplied by 100 to give the two directional indicators, +DI and -DI.

The directional index takes the two DI lines and measures how far apart they are relative to their sum — a number near 100 when one side dominates completely, near 0 when they are level. That per-bar value is then smoothed again to give ADX.

The published construction, stage by stage

  1. Raw directional movementPer bar: how far the high extended above yesterday’s high, or the low below yesterday’s low. Inside bars contribute nothing.
  2. Scale and smoothDivide by true range and smooth over the period. Produces +DI and -DI, both between 0 and 100.
  3. Directional indexThe gap between +DI and -DI, relative to their sum. The sign is discarded here — this is where direction is lost.
  4. Smooth againA second smoothing pass over the directional index gives ADX. Two smoothing stages is why ADX is slow.

AmiBroker does document Wilder’s smoothing in two places. The RSI page publishes the exact recursion RSI uses, P = ( ( period - 1 ) * P + W ) / period, and the ATR page carries a statement from AmiBroker’s author that ATR “uses WILDERS smoothing (not simple moving average)”. There is also a general-purpose Wilders( ARRAY, periods ) function you can apply to any array.

What is not documented is a formula on the Wilders page — it is a stub — or any statement about which smoothing the DI and ADX stages use. A widely repeated equivalence between Wilder’s smoothing and an exponential average of length 2n - 1 is not published by AmiBroker, and the two functions are seeded differently, so this course does not assert it.

The conventional reading, stated as convention:

  • ADX rising is read as “the trend, whichever way it is going, is strengthening”.
  • ADX above a threshold — 20 or 25 are the usual choices — is read as “trending”.
  • ADX below that threshold is read as “ranging”, and mean-reversion methods are said to suit those conditions better.
  • +DI above -DI is read as upward pressure dominating, and the crossings of the two lines are read as changes of that balance.

Nothing in AmiBroker’s documentation establishes 20 or 25 as meaningful. They are levels people draw. Treat them the way you would treat any other line you chose yourself.

“ADX is falling, so the trend is over.” A falling ADX says the strength measure is declining. That happens when a trend ends, and it also happens when a trend simply becomes less lopsided — a steady, orderly advance with occasional down bars can produce a drifting-down ADX while price keeps climbing.

Reading DI crossings as entries. Both DI lines are already smoothed, and their crossing is then subject to the same interleaving problem as any two-line crossover in a quiet market. The crossing is an event you can measure; it is not evidence about what follows.

Trusting the first hundred bars. ADX has two smoothing stages, at least one of which is recursive on the published construction, and AmiBroker documents no warm-up length. The early part of the series is contaminated for far longer than the nominal period.

Copying the example off the reference page. This one is worth a warning of its own.

All three lines live between 0 and 100, so they belong in their own pane rather than on top of price. Drop them there from Window -> Charts, or apply a formula. If you drag one onto the price pane by mistake you will get a flat line along the bottom; the documented fix is the styleOwnScale style from Parameters -> Style, but a separate pane is the better answer.

For reference levels, the Parameters window’s Axes & Grid tab offers a fixed set of popular grid levels — 30/70, 20/80, 10/90, plus or minus 100, and zero. A line at 25 is not among them, so draw it from the formula. AmiBroker’s documentation specifically recommends PlotGrid rather than plotting a constant array, for performance:

Fragment — not a complete formula

Plot( ADX( 14 ), "ADX(14)", colorBlue, styleLine | styleThick );
Plot( PDI( 14 ), "+DI", colorGreen, styleLine );
Plot( MDI( 14 ), "-DI", colorRed, styleLine );
// PlotGrid( level, color, pattern, width, Label ). The level must be a NUMBER,
// not an array. Patterns 8, 9 and 10 are the only ones available above width 1.
PlotGrid( 25, colorGrey40, 9, 1, True );

Because the two DI lines and ADX share a scale, all three can share one pane. Give ADX the thickest line: it is the one that changes slowly, and the eye needs help separating it from the pair that cross each other constantly.

Fragment — not a complete formula

Strength = ADX( 14 ); // default period is 14
UpPressure = PDI( 14 ); // the +DI line
DownPressure = MDI( 14 ); // the -DI line
Trending = Strength > 25;
UpDominant = UpPressure > DownPressure;

Three documented details to hold on to.

All three default to a period of 14. ADX() with no arguments is ADX( 14 ). The official examples are adx() and adx( 20 ).

None of them takes an input array. They read the built-in High, Low and Close directly. You cannot write ADX( Close, 14 ) and you cannot point them at another symbol by passing one in — the documented route for that is to reassign the predefined price arrays before the call, which is a Part 15 subject.

The names are PDI and MDI. PlusDI() and MinusDI() do not exist in AmiBroker; both names return a 404 on the function reference and appear in neither official index. If you find a formula on the internet that calls them, it was not written for AmiBroker.

Measure the warm-up rather than assuming it

Section titled “Measure the warm-up rather than assuming it”

Since the documentation gives no warm-up length, find out for yourself. NullCount returns, by default, the number of consecutive Null values at the beginning of an array:

Fragment — not a complete formula

Plot( ADX( 14 ), "ADX(14)", colorBlue, styleLine | styleThick );
Title = "Leading empty bars — ADX(14): "
+ NumToStr( NullCount( ADX( 14 ) ), 1.0 )
+ " RSI(14): " + NumToStr( NullCount( RSI( 14 ) ), 1.0 )
+ " MA(Close,14): " + NumToStr( NullCount( MA( Close, 14 ) ), 1.0 );

Apply that to a symbol with a long history and read the numbers. The simple average should report 13 leading empty bars, matching the documented periods - 1 rule. Whatever ADX reports, treat it as the minimum: the first bar with a number is not the first bar you can believe, because recursive smoothing carries its seed forward well past its first output.

ADX claims to measure strength without direction, so the honest test measures magnitude without direction too:

On my universe, over my chosen period, is the average absolute 20-day forward price change larger on bars where ADX(14) closed above 25 than on bars where it closed below?

That is a fair test of what the indicator says it does. It asks about the size of the subsequent move, not its direction, so a strong decline counts the same as a strong advance — which is exactly the claim being examined. It has an obvious failure mode worth knowing in advance: ADX is built from true range, and absolute forward change is a volatility measure too, so a positive result may be telling you only that volatile periods follow volatile periods. Anticipating that objection before you run the test is the difference between research and confirmation.

The full machinery for running a test of this shape — universe, period, measurement, interpretation and the list of things it cannot settle — is the last lesson of this part.

ADX measures how one-sided recent directional movement has been, after discarding which side won, and it does so through two smoothing stages, which is why it is slow. PDI() and MDI() carry the direction; ADX does not. All three default to a 14-bar period, none of them accepts an input array, and the names PlusDI and MinusDI do not exist. AmiBroker documents the syntax and defaults but not the internal formula, the smoothing method or the warm-up length, so treat cross-platform differences as expected and measure the warm-up yourself with NullCount. The 25 line is a convention you drew, not a property of markets.

Check your understanding

Question 1. ADX(14) has risen from 15 to 40 over the last two months. What does that tell you about price?
Show the answer and why

Answer: Recent directional movement has been one-sided, but not which side

The directional index is built from the gap between +DI and -DI relative to their sum, and the sign of that gap is dropped before the final smoothing. Direction comes from comparing PDI() with MDI(), never from ADX itself.

Question 2. Which of these calls is valid AFL?
Show the answer and why

Answer: MDI( 14 )

ADX, PDI and MDI each take a single optional period argument and read the built-in High, Low and Close themselves. PlusDI and MinusDI are not AmiBroker function names at all — the documented names are PDI and MDI.

Question 3. Your AmiBroker ADX(14) differs in the second decimal place from the ADX on another platform. What is the correct conclusion?
Show the answer and why

Answer: The internal smoothing and seeding are not documented, so small differences are expected

AmiBroker publishes the syntax and default for ADX but not its internal formula, smoothing method or initialisation. Two implementations of a recursive, double-smoothed indicator can differ legitimately, especially near the start of the data.

Question 4. Why does this lesson suggest measuring the warm-up with NullCount rather than quoting a bar count?
Title = "ADX leading empty bars: " + NumToStr( NullCount( ADX( 14 ) ), 1.0 );
Show the answer and why

Answer: Because AmiBroker documents no warm-up length for ADX, so any quoted number would be invented

Only MA and RSI have documented warm-up behaviour in this family. NullCount with its default mode counts consecutive Nulls at the beginning of the array, so it answers the question empirically instead of by assertion — and the answer is still only a lower bound, because recursive smoothing stays seed-sensitive after its first output.

Sources for this lesson

8 verified · checked 2026-08-31

  1. 01AFL Function Reference — ADXamibroker.com/guide/afl/adx.html2026-08-31
  2. 02AFL Function Reference — PDIamibroker.com/guide/afl/pdi.html2026-08-31
  3. 03AFL Function Reference — MDIamibroker.com/guide/afl/mdi.html2026-08-31
  4. 04AFL Function Reference — Wildersamibroker.com/guide/afl/wilders.html2026-08-31
  5. 05AFL Function Reference — ATR§ Author comment on Wilder's smoothingamibroker.com/guide/afl/atr.html2026-08-31
  6. 06AFL Function Reference — NullCountamibroker.com/guide/afl/nullcount.html2026-08-31
  7. 07AFL Function Reference — PlotGridamibroker.com/guide/afl/plotgrid.html2026-08-31
  8. 08AmiBroker User's Guide — Parameters window§ Grid levelsamibroker.com/guide/w_param.html2026-08-31

Every technical claim on this page was checked against the official AmiBroker documentation on the date shown. Where the course disagrees with folklore, the source is how you can tell which one to trust.