What it does
A Donchian Channel draws the highest high and lowest low of the last N bars. When price pushes beyond either edge, it has made a new N-bar extreme, which is one of the oldest and simplest definitions of a breakout. This indicator plots the channel, its midline, and marks the first bar that breaks above or below it.
An optional ATR buffer asks price to clear the edge by a meaningful distance, which helps ignore breakouts of only a few ticks.
How it works
- Upper = highest high of the previous N bars (the current bar is excluded, so it can actually break the channel).
- Lower = lowest low of the previous N bars.
- Midline = (upper + lower) ÷ 2.
- Trigger levels: with the ATR filter off they equal the channel edges. With it on, upper trigger = upper + multiplier × ATR and lower trigger = lower − multiplier × ATR. The triggers are shown as faint dots.
- A bullish breakout prints on the first closed bar whose close (or high, in wick mode) is above the upper trigger after a bar that was not. A bearish breakout is the mirror image.
- Separate alerts fire when price closes across the midline.
How to use it
Donchian breakouts are a classic trend-following entry: buy new highs, sell new lows, and accept that many attempts will fail while a few may run. Longer channels (20 to 55 bars on H4 or D1) produce fewer, more significant signals. Shorter channels react faster but break out more often in sideways markets.
Ideas that traders commonly combine with it:
- The opposite channel edge or the midline as a trailing exit reference.
- A higher-timeframe trend filter, taking only breakouts in the same direction.
- The ATR buffer on instruments with frequent wicks through obvious highs and lows, such as gold or indices around their opening times.
Breakout entries can suffer slippage when many orders are triggered at the same level, so factor that into your risk management.
Settings
| Input | Default | What it changes |
|---|---|---|
| Channel length (bars) | 20 | How far back the high and low are measured. |
| Breakout on wick instead of close | off | Earlier signals, more false breaks. |
| Require ATR buffer | off | Turns on the buffer filter. |
| ATR length | 14 | Smoothness of the buffer. |
| ATR buffer multiplier | 0.25 | Larger values demand a cleaner break. |
| Show midline / Fill channel | on | Visual options. |
Limitations
- In ranges, price often pokes beyond the channel and returns. Expect strings of failed breakouts.
- The channel is a step function: it only moves when an old extreme drops out of the window, so it can sit flat for long periods.
- Wick mode reacts to a single spike, which may be a spread widening rather than real trading.
- The ATR buffer delays entries; a strong move will be signaled later than the raw breakout.
- Signals are confirmed at bar close, so the entry price is usually beyond the channel edge.
Pine Script source
In TradingView open Pine Editor, paste the code, click Save and then Add to chart.
FXP_DonchianChannelBreakout.pine
59 lines
// © FXPIPS ONLINE — https://fxpips.online/tradingview-indicators/donchian-channel-breakout/
// License: MIT. Educational tool — not financial advice. Trading involves substantial risk.
//@version=6
indicator("FXP Donchian Channel Breakout", shorttitle = "FXP Donchian", overlay = true)
// ── Inputs ─────────────────────────────────────────────────────────────
grpDC = "Donchian Channel"
dcLen = input.int(20, "Channel length (bars)", minval = 2, group = grpDC)
useWicks = input.bool(false, "Breakout on wick instead of close", group = grpDC)
grpF = "ATR filter"
useAtr = input.bool(false, "Require ATR buffer beyond the channel", group = grpF)
atrLen = input.int(14, "ATR length", minval = 1, group = grpF)
atrBuf = input.float(0.25, "ATR buffer multiplier", minval = 0.0, step = 0.05, group = grpF)
grpVis = "Display"
showMid = input.bool(true, "Show midline", group = grpVis)
showFill = input.bool(true, "Fill channel", group = grpVis)
bullCol = input.color(color.teal, "Bullish color", group = grpVis)
bearCol = input.color(color.red, "Bearish color", group = grpVis)
// ── Calculation ────────────────────────────────────────────────────────
// The channel uses the previous N bars only, so the current bar can break it.
upper = ta.highest(high, dcLen)[1]
lower = ta.lowest(low, dcLen)[1]
mid = (upper + lower) / 2.0
atr = ta.atr(atrLen)
buffer = useAtr ? atrBuf * atr : 0.0
float upTrig = upper + buffer
float dnTrig = lower - buffer
float upSrc = useWicks ? high : close
float dnSrc = useWicks ? low : close
bool aboveNow = upSrc > upTrig
bool belowNow = dnSrc < dnTrig
bool bullBreak = barstate.isconfirmed and aboveNow and not aboveNow[1]
bool bearBreak = barstate.isconfirmed and belowNow and not belowNow[1]
bool midUp = ta.crossover(close, mid) and barstate.isconfirmed
bool midDn = ta.crossunder(close, mid) and barstate.isconfirmed
// ── Plots ──────────────────────────────────────────────────────────────
pU = plot(upper, "Upper channel", color = bullCol)
pL = plot(lower, "Lower channel", color = bearCol)
plot(showMid ? mid : na, "Midline", color = color.new(color.gray, 20), style = plot.style_linebr)
plot(useAtr ? upTrig : na, "Upper trigger", color = color.new(bullCol, 60), style = plot.style_circles, linewidth = 1)
plot(useAtr ? dnTrig : na, "Lower trigger", color = color.new(bearCol, 60), style = plot.style_circles, linewidth = 1)
fill(pU, pL, color = showFill ? color.new(color.blue, 93) : na, title = "Channel fill")
plotshape(bullBreak, "Bullish breakout", shape.triangleup, location.belowbar, bullCol, size = size.small)
plotshape(bearBreak, "Bearish breakout", shape.triangledown, location.abovebar, bearCol, size = size.small)
// ── Alerts ─────────────────────────────────────────────────────────────
alertcondition(bullBreak, "Bullish Donchian breakout", "FXP Donchian: breakout above the {{interval}} channel on {{ticker}} at {{close}}")
alertcondition(bearBreak, "Bearish Donchian breakout", "FXP Donchian: breakout below the {{interval}} channel on {{ticker}} at {{close}}")
alertcondition(midUp, "Close above midline", "FXP Donchian: close above midline on {{ticker}} {{interval}}")
alertcondition(midDn, "Close below midline", "FXP Donchian: close below midline on {{ticker}} {{interval}}")

