Technical Analysis · Trend Filtering

How Does ADX / DMI Tell If There Is a Trend Right Now?
Use It as a Switch for Your Other Strategies

2026-08-18·11 min

Your breakout strategy made 6% in three days during a strong run, then the market went flat for two weeks and gave that 6% right back — same entry rules, not a single line of code changed. You have been wondering whether there is a way to just have the strategy sit out the chop.

ADX (Average Directional Index) was literally designed for this — Wilder introduced it alongside RSI in his 1978 book New Concepts in Technical Trading Systems. Unlike RSI or MACD, it is not an entry signal; it answers a question that sits one layer upstream: should this strategy be running right now at all?

Bottom line up front: using ADX by itself as an entry signal is something nearly everyone tries, and nearly everyone gets whipsawed on. Its one real use case is different — you already have a breakout strategy that gets chopped up during ranges, or a mean-reversion strategy that gets steamrolled during trends, and you use ADX to turn them off when they should not be running. This post does not teach you how to enter with ADX; it shows you how to bolt it onto a strategy you already have. At the end there is a copy-pasteable Pine Script skeleton — that being TradingView's scripting language for writing strategy logic on the chart.
14
Wilder's default period, unchanged since 1978
20 → 25
Wilder's original ranging → trending thresholds
P70
Adaptive threshold recommended for crypto perpetuals: the 70th percentile of ADX over the last 200 bars

What ADX is actually computing — start with the mechanics

The ADX line on its own does not carry much intuitive meaning. To read it, you have to look at the two lines underneath — `+DI` and `−DI`. All three together are called DMI (Directional Movement Index), and Wilder's original design was to look at them as a set; looking at ADX alone throws away the direction information.

Roughly, the mechanics are this. Compare each bar to the previous one: if today's high is higher than yesterday's high, and it exceeds it by more than today's low undershoots yesterday's low, that counts as `+DM` (positive directional movement); the reverse counts as `−DM`. Sum `+DM` over the last 14 bars, divide by True Range over the same window with Wilder smoothing, and you get `+DI`; the same treatment on `−DM` gives you `−DI`. ADX is the absolute difference between `+DI` and `−DI`, smoothed one more time.

The takeaway is: ADX only tells you the strength of the trend, not its direction. For direction, you look at which of `+DI` or `−DI` is on top. What each of the three lines represents is in the table below.

LineQuestion it answersRange
+DIHow strong is the bullish side0–100, typically 10–40
−DIHow strong is the bearish side0–100, typically 10–40
ADXStrength of whichever side dominates (direction-agnostic)0–100, typically 10–60

Sources: the ta.dmi entry in the Pine Script v6 Language Reference, and Wilder's original 1978 definitions in New Concepts in Technical Trading Systems (verified August 2026).

The default period of 14 is Wilder's own original parameter, and most platforms have kept it. TradingView's ta.dmi() follows the same convention: ta.dmi(14, 14), where the first 14 is the DI length and the second is the ADX smoothing length. These two can be tuned separately, but do not touch them without testing first — most published discussions of ADX thresholds assume a default of 14, and the moment you change it those thresholds stop lining up.

Why ADX alone does not work as an entry signal

Looking only at the ADX line makes it easy to arrive at a rule like "ADX > 25 means there is a trend, so I enter", and then get slapped in live trading. The reason is right there in the third column above — ADX has no direction. When ADX climbs from 15 to 30, it might be a rising trend gaining strength, or it might be a falling trend gaining strength; from that one line alone you cannot tell them apart.

The second problem is lag. ADX is built from two layers of smoothing (first the DM/TR components, then the absolute difference), so by the time it climbs above 25 and you decide "there is a trend", price has already moved a chunk. Using it as an entry signal means you are always catching the middle-to-late stage of the move.

An epistemological caveat
The "ADX only lights up in the middle-to-late stage" claim is a consequence you can derive from the two layers of smoothing, not a sentence Wilder wrote in the original book. You can see the lag yourself by overlaying ta.dmi(14, 14) on any obviously trending stretch, but treat it as "mechanical reasoning plus chart observation", not an official statement.

So whatever ADX-based entry you go for — "ADX crosses above 20" or "+DI crosses above −DI" — you have to accept two things up front: you are entering the middle-to-late stage, and you will get whipsawed as a matter of course. This path is not impossible; the people who have made it work almost always stacked additional filters on top of ADX (multi-timeframe, volume, breakout wick behaviour). ADX cannot carry entry duty on its own.

Wilder's original book gave only two thresholds: below 20 means no clear trend, above 25 means a clear trend — StockCharts' ChartSchool cites Wilder exactly this way. Most textbooks tack on a few finer buckets on top (25–50 clear trend, 50+ very strong trend) for intuition, but that upper bucket is a later convention; the number 50 is not in Wilder's book. The original two thresholds have been the working reference for nearly fifty years, and are what most textbooks mean by "trending or not".

But these numbers came from his observations of 1970s commodities and FX markets. Intraday crypto perpetuals are a different world: much higher volatility, more fake breakouts, 24-hour trading with no session gap. On a 5-minute chart with the same 14-bar period, ADX almost never dips below 20. Hard-coding a threshold of 25 there means the switch is effectively on all day — which is the same as no switch at all.

These thresholds are a snapshot, not a guarantee
The table below is a set of reference numbers I pulled by overlaying ta.dmi(14, 14) on BTCUSDT.P at different timeframes and looking at the ADX distribution over the last 90 days (verified August 2026). Before you actually use these as a switch, overlay it yourself — different instruments and different windows drift, especially when the market switches between bull and bear the whole distribution shifts up or down.
TimeframeRough median ADXThreshold to use as a switch
5m22–28Use the 70th percentile of the last 90 days
1H18–2420–22
4H16–2220–25 (close to Wilder's original)
1D15–2025 (close to Wilder's original)

Reference values observed on BTCUSDT.P over the last 90 days (verified August 2026). This is a snapshot, not a promise — verify on your own chart before applying.

Rather than memorising numbers, the more durable approach is to use a percentile instead of an absolute value — treat it as "in a trend" when ADX exceeds the 70th percentile of the last 200 bars. That way the same Pine Script can be used across timeframes and instruments without hand-editing the threshold each time.

Bolting it onto a strategy: two ways it stacks

Trend-following
ADX high = on, ADX low = off (breakout, momentum, CTA)
Mean-reversion
ADX low = on, ADX high = off (Bollinger fade, support bounce)
One ADX line
The two directions are opposite, so in theory they take turns on stage

The core logic of using ADX as a switch has only one shape, but two directions: trend-following strategies turn on when ADX is high and off when it is low; mean-reversion strategies do the opposite. The intuition is easy, but there are more moving parts than you might expect once you wire it in.

Trend-following (breakout, momentum)Mean-reversion (Bollinger fade)
ADX switch conditionEnter when ADX > thresholdEnter when ADX < threshold
Behaviour during rangesGets sawed back and forth, hit rate collapsesThis is its home turf
Behaviour during strong trendsThis is its home turfGets steamrolled — the reversion premise fails
Effect of adding an ADX switchFewer entries and fewer losses during rangesFewer entries and fewer losses during strong trends
When the switch flips off, close existing positions?Let the stop handle it, no forced closeStrongly recommend closing — the reversion premise is gone

That last row is the one people miss most often: "switch off" and "flatten" are not the same action. Turning the switch off only blocks new entries; what to do with an open position is a separate decision. A trend strategy can safely let its own stop handle the exit; a mean-reversion strategy that entered and then watched ADX rip from 15 to 35 has lost the premise it was betting on ("price will come back"), and the safer move is to actively close rather than wait for the stop.

Wiring the switch in Pine Script

Below is the minimum usable skeleton. It is not meant to be dropped straight into a backtest as-is — the entry logic is intentionally left blank. The point is how the regimeOn variable is computed and how you hook it into your own entry conditions. Replace longSig and shortSig with your own signals and you have a complete strategy.

pine
//@version=6
        strategy("Trend Strategy with ADX Regime Filter",
             overlay          = true,
             default_qty_type = strategy.percent_of_equity,
             default_qty_value= 10,
             initial_capital  = 10000)

        // ─── ADX parameters ───
        diLen       = input.int(14,   "DI Length")
        adxLen      = input.int(14,   "ADX Smoothing")
        useAdaptive = input.bool(true,"Use percentile instead of a fixed threshold")
        fixedThr    = input.float(20, "Fixed threshold (used when useAdaptive = false)")
        pctLookback = input.int(200,  "Percentile lookback (bars)")
        pctRank     = input.float(70, "Percentile (%)")

        // ─── DMI + regime switch ───
        [diPlus, diMinus, adx] = ta.dmi(diLen, adxLen)
        adaptiveThr = ta.percentile_linear_interpolation(adx, pctLookback, pctRank)
        threshold   = useAdaptive ? adaptiveThr : fixedThr
        regimeOn    = adx > threshold

Three details are worth expanding on. ta.dmi() returns three values in one call — `+DI`, `−DI`, ADX — which you destructure into an array. ta.percentile_linear_interpolation(adx, 200, 70) is a built-in that arrived in Pine v5; it computes the 70th percentile of ADX over the last 200 bars directly, so you do not have to sort by hand. The useAdaptive toggle is there so you can A/B the percentile version against the fixed-threshold version on the same backtest — otherwise arguing which one is better has no evidence to stand on.

All of the above only computes the switch itself. Below is how you connect it to your actual entry conditions — using the simplest possible Donchian breakout as an example. Swap longSig and shortSig for your own and you have a complete strategy.

pine
// Continues from the same strategy() block above

        // ─── Entry conditions (swap in your own) ───
        lookback = 20
        hh       = ta.highest(high, lookback)[1]
        ll       = ta.lowest(low,  lookback)[1]
        longSig  = close > hh
        shortSig = close < ll

        // ─── Only enter when the regime switch is on ───
        if regimeOn and longSig
            strategy.entry("Long",  strategy.long)
        if regimeOn and shortSig
            strategy.entry("Short", strategy.short)

        // Chart visual: green background when regime is on
        bgcolor(regimeOn ? color.new(color.green, 90) : na, title = "Regime On")

The `[1]` offset is deliberate — `ta.highest(high, 20)[1]` is the highest high of the last 20 bars not including the current bar, which stops you from using future data in your entry condition (one flavour of `repainting`). This is one of the most classic pitfalls covered in Pine Script automation traps.

This code was not backtested
Treat it as a skeleton — I have not run a backtest on it. Adding an ADX switch and watching the backtest numbers jump upward is normal, and having the live results fail to follow is equally normal — the reason is that if the backtest window happens to contain a clean bull-or-bear regime, the range periods the switch shuts out were losing periods by construction, so the backtest looks great; that does not mean the next batch of live-market ranges will be blocked by the same switch. For more on backtest vs live gaps, see the first section of Webhook position sizing.

The two mistakes people make most often with ADX filters

These two are the ones almost every first-time filter builder trips over. Neither raises an error, and neither shows up obviously in the backtest numbers.

1
Your strategy runs on the 5-minute chart, but the ADX condition is based on ADX > 25 on the 4-hour chart?
Yes →Timeframe mismatch. One tick up on the 4H ADX can map to roughly 48 bars on the 5m chart, and by the moment 4H ADX > 25 registers, the 5m has usually already dulled out. If you must go cross-timeframe, use request.security — its lookahead has defaulted to barmerge.lookahead_off (the safe value) since v3, so as long as you do not explicitly pass barmerge.lookahead_on, the backtest will not sneak future data in.
No, I compute ADX on the same timeframe as the strategy →Next question.
2
After adding the ADX switch, when you extend the backtest window from one year to three years, do the numbers still look as good?
One year looks great, three years falls apart →Strong smell of overfitting. If the ADX threshold was optimised on a single year of data, it is functionally curve-fitted. Using a percentile (percentile_linear_interpolation) rather than a fixed threshold eases this, but does not cure it — the best defence is walk-forward analysis, not a single run over all history.
Three years still looks OK, but live results lag →See the next Callout — this is usually a distribution mismatch between bull and bear phases in your test window versus the future.
Both one-year and three-year look good and live matches →Then put small money on it for three months — live tests beat everything.

The first mistake — timeframe mismatch — does not fail to compile; it just makes your live results diverge from your backtest. The second is more insidious because it "silently gets better" during the backtest window: tune the threshold to 22 on 2022–2024 data and it looks fantastic; but 2022 was an obvious year-long downtrend, so that threshold was essentially fitted to that regime, and by the time 2025 spends three months chopping sideways, it is completely wrong.

The honest section: what ADX cannot filter

However well you tune it, there are a few things ADX structurally cannot do. Listing them here to save you the time — we have tried these ourselves, and the answer is no.

  • Short news spikes. Wilder's ADX has two layers of smoothing, so it is slow by design. By the time ADX lights up, the three-bar rip that followed a CPI print has usually already given half of it back.
  • Slow, low-volatility trends. If price grinds up bar by bar but each bar has a small range, True Range and DM are both small, and ADX can stay under 15 for the entire climb. An ADX switch will keep this shut out end-to-end, and you will miss it.
  • The head and tail of a "fake trend". While ADX climbs from 15 to 22, you cannot tell whether a real trend is starting or a fake breakout is building momentum. Waiting for ADX > 25 to confirm usually means you are already near the middle of the move.
  • "Is this trend up or down". ADX has no direction. For that you need to see which of `+DI` and `−DI` is on top, or pair it with a direction cue such as a moving average.

Any filter — not just ADX — trades "fewer losing entries" against "more missed real signals"; if you tighten the filter, you will miss more. The pattern an ADX filter misses most is a "quiet uptrend": price walks silently upward but ADX never breaks 20. This shape shows up especially in late-cycle bull markets, and it is a structural blind spot of the tool.

FAQ

Can I change ADX's period of 14?
You can, but once you do the "25 is the trend threshold" numbers you see in textbooks and forums no longer line up with your ADX. People shortening it (to 7, say) usually want ADX to react faster; the price is more noise — the switch will flip on and off constantly during ranges. Lengthening it (to 21) filters out short fake breakouts at the cost of slower entries. Without hard testing, stay at 14.
Can I stack ADX with RSI and MACD?
Yes, and people do it often. Just be clear on what each one answers: RSI speaks to overbought/oversold (relative momentum), MACD speaks to the relationship between two moving averages (direction plus momentum), and ADX speaks to strength. If you require all three to line up before entering, signals will get very rare — that usually means the backtest looks pretty because you added filters, but live almost never fires. Before adding another filter, ask which specific kind of fake signal you are trying to filter out.
Should the TradingView alert carry the current ADX value out to the webhook?
Not unless something downstream actually consumes it. The ADX switch is part of the entry condition — when regimeOn is false, Pine Script does not call strategy.entry, so no alert fires. Sending it out only inflates the payload and the parsing load. If you want to debug whether the switch is firing, plotting the transitions with plotshape is more direct than reading it out of the alert.
Backtest results improved a lot after adding the ADX switch — can I go straight to live?
Ask yourself one question first: was the threshold picked on the same slice of history you are now backtesting on? If so, that "improvement" is very likely curve-fitting. At a minimum, do two things — split the data into in-sample and out-of-sample, tune only in-sample and confirm out-of-sample; and use a percentile rather than a fixed threshold to reduce dependence on the absolute ADX values in one window. If live still lags after those two, market structure has probably drifted from the window you tuned on.
During the periods when the ADX switch is off, what should my capital be doing?
There is no one-size-fits-all answer; it depends on how many strategies you run. If you run only one trend strategy, the answer is to sit in cash — parked in a stablecoin or a savings account. If you run a trend plus a mean-reversion pair, they share the same ADX line but in opposite directions and, in theory, take turns being on. If you run a single strategy and want no idle periods, you either accept losing a little in ranges or accept missing the occasional real trend — one or the other, no third option.

Get started

Ready to ship what you just learned?

Take your Pine Script strategy with the ADX switch bolted on, wire it up to a webhook, and let TVSBot handle execution — using your own exchange API key, dry-run first to confirm the switch really shuts entries off, and your own risk controls.

Get Started for Free