ADX

//@version=6
indicator("ADX_RD", format=format.price, precision=2, timeframe="", timeframe_gaps=true)

// ADX_RD - Average Directional Index (Ryan DeBraal)
// This indicator provides a complete visualization of trend strength and directional pressure
// using the classic ADX system with Wilder smoothing. It plots the ADX line along with the
// +DI (bullish pressure) and -DI (bearish pressure) lines to show both the strength and the
// dominant side of the market. The script enhances the standard ADX toolkit by adding dynamic
// line styling, adjustable smoothing, opacity control, and visual thresholds that help traders
// quickly assess whether a trend is worth trading.
//
// OVERVIEW
// ADX (Average Directional Index) measures the strength of a trend, regardless of whether
// the trend is moving up or down. By itself, ADX does not indicate direction. Instead, it
// quantifies how strong the current move is. The companion lines — +DI and -DI — indicate
// which side (buyers or sellers) is currently exerting more directional force.
//
// HOW IT WORKS
// - +DI rises when price makes stronger upward moves (higher highs).
// - -DI rises when price makes stronger downward moves (lower lows).
// - ADX rises when either side is pushing strongly and the market is becoming directional.
//   It falls when price movement becomes weak, noisy, or range-bound.
//
// ENHANCED FEATURES
// - Wilder-smoothing of +DI, -DI, and ADX for consistent trend-strength measurement.
// - Configurable threshold level (default 20), widely used to separate weak markets from
//   trending ones. When ADX remains below this threshold, conditions are often choppy.
// - Automatic color shifting of the ADX line:
//       ADX < threshold → white (weak or no trend)
//       ADX >= threshold → yellow (trend developing or strong)
// - Adaptive line thickness behavior: the ADX line becomes thicker when the trend is strong,
//   helping visually highlight actionable conditions.
// - Optional display of +DI and -DI lines, each rendered with adjustable opacity so they can
//   either stand out or stay subtle depending on the trader's preference.
// - Horizontal dotted reference line at the threshold for quick visual anchoring.
// - All smoothing lengths and display parameters can be customized.
//
// PURPOSE AND TRADING USE
// The goal of this indicator is to let traders quickly answer two questions:
//   1. Is the market trending or flat?
//   2. If trending, who is in control: buyers or sellers?
// ADX_RD is especially useful when:
// - Confirming breakouts (ADX rising above threshold)
// - Filtering entries for trend-following strategies
// - Avoiding low-probability trades during sideways or volatile chop
// - Pairing with MACD, EMA, RSI, VWAP, or price-action setups as a final trend-strength filter
//
// IMPORTANT NOTES
// - ADX measures *strength*, not direction.
// - Direction comes from +DI and -DI:
//       +DI above -DI → bullish pressure dominant
//       -DI above +DI → bearish pressure dominant
// - High ADX with a clean DI separation typically indicates the strongest opportunities.
// - Low ADX implies signals from other indicators may fail due to lack of trend.
//
// In short, ADX_RD provides a clean, enhanced visualization of trend conditions, helping traders
// avoid chop, focus on strong directional setups, and make more disciplined entries.

// Inputs
lineThickness = input.int(1, "ADX Line Thickness")
adxlen = input.int(14, "ADX Smoothing")
dilen = input.int(14, "DI Length")
showDI = input.bool(true, "Show +DI / -DI Lines")

// Directional Movement and DI calculation
dirmov(len) =>
    up = ta.change(high)
    down = -ta.change(low)
    plusDM = na(up) ? na : (up > down and up > 0 ? up : 0)
    minusDM = na(down) ? na : (down > up and down > 0 ? down : 0)
    truerange = ta.rma(ta.tr, len)
    plus = fixnan(100 * ta.rma(plusDM, len) / truerange)
    minus = fixnan(100 * ta.rma(minusDM, len) / truerange)
    [plus, minus]

// ADX calculation using Wilder smoothing
adx(dilen, adxlen) =>
    [plus, minus] = dirmov(dilen)
    sum = plus + minus
    adx = 100 * ta.rma(math.abs(plus - minus) / (sum == 0 ? 1 : sum), adxlen)

// Get DI and ADX values
[plusDI, minusDI] = dirmov(dilen)
sig = adx(dilen, adxlen)

// Dynamic color: white if below 20, yellow if above
sigColor = sig < 20 ? color.new(color.white, 95) : color.yellow

// ADX plot
plot(sig, color=sigColor, title="ADX", linewidth=lineThickness * 2)

// +DI / -DI plots (optional)
plot(showDI ? plusDI : na, title="+DI", color=color.new(color.green, 0), linewidth=1)
plot(showDI ? minusDI : na, title="-DI", color=color.new(color.red, 0), linewidth=1)

// Horizontal dotted line at 20
hline(20, "Threshold 20", color=color.gray, linestyle=hline.style_dotted, linewidth=1)