What it does
The Adaptive Supertrend is a trend-following stop line that sits below price in an uptrend and above price in a downtrend. It works like the classic ATR Supertrend, with one change: the band multiplier is not fixed. When current volatility is high compared with its own recent history, the bands widen; when volatility is unusually quiet, they tighten.
The aim is to give the trend more room during turbulent phases, where a fixed band often gets clipped by noise, and to react faster in calm markets, where a wide fixed band can give back a lot of the move before flipping.
How it works
- ATR is calculated over the ATR length.
- The current ATR is ranked against the last "Volatility lookback" ATR values with a percentile rank (0 to 100), then normalized to 0–1.
- Multiplier = Base multiplier × (1 + Adaptation strength × (2 × rank − 1)). With the defaults, the multiplier moves between 1.5 and 4.5, and equals 3.0 when ATR sits at its median.
- Raw bands are Source ± multiplier × ATR. The lower band may only rise (and the upper band may only fall) unless the previous close broke through it, which is the standard Supertrend ratchet.
- The trend turns bearish when price closes below the previous lower band and bullish when it closes above the previous upper band.
Flip labels and alerts require a closed bar, so a signal never appears and then disappears on the live candle. The current multiplier is shown in the Data Window.
How to use it
- Treat the green line as a trailing reference in an uptrend and the red line in a downtrend. Many traders use it to judge whether a trend is intact rather than as a stand-alone entry trigger.
- A flip is a change of state, not a prediction. Look for confirmation such as a break of support or resistance, a higher-timeframe trend in the same direction, or a momentum reading that agrees.
- The distance between price and the line is a rough measure of risk if you plan a stop-loss around it. Size positions with the Position Size Calculator.
- It suits trending instruments such as gold, indices and major pairs on M15 to D1. On very low timeframes the volatility ranking becomes noisy.
Settings
| Input | Default | What it changes |
|---|---|---|
| ATR length | 10 | Smoothing of the volatility measure. Longer = steadier bands. |
| Base multiplier | 3.0 | Overall band width. Higher = fewer, later flips. |
| Volatility lookback | 100 | History used for the percentile rank. Longer = slower adaptation. |
| Adaptation strength | 0.5 | Range of the multiplier around the base. 0 turns adaptation off. |
| Band source | hl2 | Price the bands are centred on. |
| Show trend-flip labels | On | Bull/Bear labels on confirmed flips. |
| Shade trend zone | On | Light fill between price and the active line. |
Limitations
- Like every trailing-stop indicator it lags. Flips arrive after the turn, and in sideways markets it can flip back and forth repeatedly.
- Adaptation can work against you: a sudden volatility spike widens the bands just as a reversal begins, delaying the flip.
- The percentile rank needs history; on the first bars of a chart the multiplier defaults to the base value.
- Signals confirm on bar close, so on higher timeframes the move may already be well underway when the label appears. Gaps over a weekend can jump straight through the line.
Pine Script source
In TradingView open Pine Editor, paste the code, click Save and then Add to chart.
FXP_AdaptiveSupertrend.pine
65 lines
// © FXPIPS ONLINE — https://fxpips.online/tradingview-indicators/adaptive-supertrend/
// License: MIT. Educational tool — not financial advice. Trading involves substantial risk.
//@version=6
// ATR Supertrend whose band multiplier widens when ATR is high versus its own history
// and tightens when ATR is low. Trend flips are confirmed on bar close.
indicator("FXP Adaptive Supertrend", shorttitle = "FXP Adaptive ST", overlay = true)
// ── Inputs ─────────────────────────────────────────────────────────────
grpCalc = "Calculation"
atrLen = input.int(10, "ATR length", minval = 1, group = grpCalc)
baseMult = input.float(3.0, "Base multiplier", minval = 0.1, step = 0.1, group = grpCalc)
rankLen = input.int(100, "Volatility lookback", minval = 10, group = grpCalc, tooltip = "Bars used to rank the current ATR against its own recent history (percentile rank).")
adaptAmt = input.float(0.5, "Adaptation strength", minval = 0.0, maxval = 0.9, step = 0.05, group = grpCalc, tooltip = "0 = classic fixed multiplier. 0.5 = the multiplier moves between 50% and 150% of the base value.")
src = input.source(hl2, "Band source", group = grpCalc)
grpVis = "Display"
showSignals = input.bool(true, "Show trend-flip labels", group = grpVis)
showFill = input.bool(true, "Shade trend zone", group = grpVis)
colBull = input.color(#26a69a, "Bullish color", group = grpVis)
colBear = input.color(#ef5350, "Bearish color", group = grpVis)
// ── Adaptive multiplier ────────────────────────────────────────────────
atr = ta.atr(atrLen)
volRank = ta.percentrank(atr, rankLen)
rankNorm = na(volRank) ? 0.5 : volRank / 100.0
mult = baseMult * (1.0 + adaptAmt * (2.0 * rankNorm - 1.0))
// ── Supertrend bands ───────────────────────────────────────────────────
upperRaw = src + mult * atr
lowerRaw = src - mult * atr
float lowerBand = lowerRaw
float upperBand = upperRaw
prevLower = nz(lowerBand[1], lowerRaw)
prevUpper = nz(upperBand[1], upperRaw)
lowerBand := lowerRaw > prevLower or close[1] < prevLower ? lowerRaw : prevLower
upperBand := upperRaw < prevUpper or close[1] > prevUpper ? upperRaw : prevUpper
// ── Direction ──────────────────────────────────────────────────────────
var int trend = 1
if trend == 1 and close < prevLower
trend := -1
else if trend == -1 and close > prevUpper
trend := 1
flipUp = trend == 1 and trend[1] == -1
flipDown = trend == -1 and trend[1] == 1
bullSignal = flipUp and barstate.isconfirmed
bearSignal = flipDown and barstate.isconfirmed
// ── Plots ──────────────────────────────────────────────────────────────
upPlot = plot(trend == 1 ? lowerBand : na, "Bullish stop line", color = colBull, linewidth = 2, style = plot.style_linebr)
dnPlot = plot(trend == -1 ? upperBand : na, "Bearish stop line", color = colBear, linewidth = 2, style = plot.style_linebr)
midPlot = plot(ohlc4, "Price midpoint", display = display.none)
fill(midPlot, upPlot, color = showFill ? color.new(colBull, 90) : na, title = "Bullish zone")
fill(midPlot, dnPlot, color = showFill ? color.new(colBear, 90) : na, title = "Bearish zone")
plot(mult, "Adaptive multiplier", display = display.data_window)
plotshape(showSignals and bullSignal, "Bullish flip", style = shape.labelup, location = location.belowbar, color = colBull, text = "Bull", textcolor = color.white, size = size.small)
plotshape(showSignals and bearSignal, "Bearish flip", style = shape.labeldown, location = location.abovebar, color = colBear, text = "Bear", textcolor = color.white, size = size.small)
// ── Alerts ─────────────────────────────────────────────────────────────
alertcondition(bullSignal, "Adaptive Supertrend bullish flip", "Adaptive Supertrend flipped bullish on {{ticker}} ({{interval}})")
alertcondition(bearSignal, "Adaptive Supertrend bearish flip", "Adaptive Supertrend flipped bearish on {{ticker}} ({{interval}})")

