◆ New — Strategy Validator, Code Fixer & Prop Compliance Checker are live. Try one free →
Home / Indicators / Range Filter
Trend indicator

Range Filter

A recursive deadband filter that only moves when price closes further than its own smoothed typical range.

Illustrative diagram — not live market data.

What it is

The Range Filter is a trend-smoothing overlay popularized by a widely copied open-source TradingView script, usually attributed to the user DonovanWall. Despite enormous usage it has essentially no formal documentation, so this page reconstructs the mechanics directly from the published code. The core idea is a deadband filter: the indicator measures how far price typically moves from bar to bar, smooths that measurement, and then draws a line that only moves when the close travels further than that typical amount. Small moves are absorbed — the line stays flat — while larger moves drag it up or down, with bands plotted one smoothed range above and below the line. The result looks like a step-line that is colored one way while rising and another while falling, and most versions print arrows when the direction changes. It is a noise filter, not a forecast: it re-describes past closes with sub-threshold movement removed, and it carries no information about future price. This is educational content only, not financial advice; no indicator predicts price, and trading involves risk of loss.

How it works

The calculation has three stages. First, measure movement: take the absolute one-bar change in close, |close − close[1]|. Second, smooth it twice: an EMA of that absolute change over the sample period (default 100), then an EMA of the result over (2 × period − 1) bars, multiplied by the range multiplier (default 3). This 'smoothed range' is the deadband half-width. Third, update the filter recursively: if the close is above the previous filter value, the new value is the maximum of the old value and (close − smoothed range); if the close is at or below it, the new value is the minimum of the old value and (close + smoothed range). In plain terms, the line refuses to move unless price closes more than one smoothed range beyond it, and it never moves against the side price is on. Direction is simply whether the filter rose or fell versus the previous bar, and the popular scripts color the line and print arrows on direction changes. Because the filter is recursive, each value depends on the entire prior series, so two charts with different history lengths can disagree slightly near the start of the data. On confirmed bars the calculation is deterministic and does not repaint.

How traders read it

Common settings

The viral script's defaults are a sample period of 100 and a range multiplier of 3, applied to the close. Both numbers are conventions from the original code, not derived values. Shorter periods make the smoothed range react faster to volatility changes; larger multipliers widen the deadband. Because flip counts change dramatically with small parameter changes, it is worth mapping behavior across a grid of settings on your own data before relying on any single pair.

Strengths

Pitfalls to watch

Pine v6 example

//@version=6
indicator("Range Filter Example", overlay = true)

per = input.int(100, "Sample Period", minval = 2)
mult = input.float(3.0, "Range Multiplier", minval = 0.1, step = 0.1)

absChange = math.abs(nz(ta.change(close)))
avgRange = ta.ema(absChange, per)
smoothRange = ta.ema(avgRange, per * 2 - 1) * mult

var float filt = close
filt := close > filt ? math.max(filt, close - smoothRange) : math.min(filt, close + smoothRange)

isUp = filt > filt[1]
isDown = filt < filt[1]

plot(filt, "Range Filter", color = isUp ? color.teal : isDown ? color.red : color.gray, linewidth = 2)
plot(filt + smoothRange, "Upper Band", color = color.new(color.gray, 70))
plot(filt - smoothRange, "Lower Band", color = color.new(color.gray, 70))

flipUp = isUp and not isUp[1] and barstate.isconfirmed
flipDn = isDown and not isDown[1] and barstate.isconfirmed
plotshape(flipUp, "Turn Up", style = shape.triangleup, location = location.belowbar, color = color.teal)
plotshape(flipDn, "Turn Down", style = shape.triangledown, location = location.abovebar, color = color.red)

Pro tip: Before using any Range Filter setting, count its direction flips across a range of period/multiplier pairs on your instrument — if the flip count swings wildly between neighboring settings, the signals you see are largely a parameter artifact rather than a property of the market. Gate alerts on bar confirmation so live behavior matches closed-bar behavior. Educational information only, not financial advice; no indicator is predictive, and trading involves risk of loss.

Built an indicator from this? Run it through the Validator to catch look-ahead bias and repainting, or convert a strategy to Pine Script.

Educational only — not financial advice, not a recommendation to trade. No indicator is predictive; trading involves substantial risk of loss.

Catch the bug that compiles.Run auditGet Pro