How Does ADX / DMI Tell If There Is a Trend Right Now?
Use It as a Switch for Your Other Strategies
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?
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.
| Line | Question it answers | Range |
|---|---|---|
+DI | How strong is the bullish side | 0–100, typically 10–40 |
−DI | How strong is the bearish side | 0–100, typically 10–40 |
ADX | Strength 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.
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.
What ADX level actually counts as "trending"?
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.
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.| Timeframe | Rough median ADX | Threshold to use as a switch |
|---|---|---|
| 5m | 22–28 | Use the 70th percentile of the last 90 days |
| 1H | 18–24 | 20–22 |
| 4H | 16–22 | 20–25 (close to Wilder's original) |
| 1D | 15–20 | 25 (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
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 condition | Enter when ADX > threshold | Enter when ADX < threshold | |
| Behaviour during ranges | Gets sawed back and forth, hit rate collapses | This is its home turf | |
| Behaviour during strong trends | This is its home turf | Gets steamrolled — the reversion premise fails | |
| Effect of adding an ADX switch | Fewer entries and fewer losses during ranges | Fewer entries and fewer losses during strong trends | |
| When the switch flips off, close existing positions? | Let the stop handle it, no forced close | Strongly 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.
//@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 > thresholdThree 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.
// 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.
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.
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.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.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?
Can I stack ADX with RSI and MACD?
Should the TradingView alert carry the current ADX value out to the webhook?
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?
During the periods when the ADX switch is off, what should my capital be doing?
Get started
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