Skip to content

The Double Donchian Channel Breakout strategy coded for TradingView

The Double Donchian Channel Breakout strategy coded for TradingView

Section titled “The Double Donchian Channel Breakout strategy coded for TradingView”

TL;DR
Use a fast Donchian channel for entries, a slower one for exits, and optional pyramiding to capture sustained trends the way the original Turtle traders did.

DifficultyIntermediate
Time to implement20-25 min
CategoryStrategies
//@version=5
strategy("Double Donchian", overlay=true, pyramiding=2)
fastLen = input.int(20, "Fast channel")
slowLen = input.int(55, "Slow channel")
upperFast = ta.highest(high, fastLen)
lowerFast = ta.lowest(low, fastLen)
upperSlow = ta.highest(high, slowLen)
lowerSlow = ta.lowest(low, slowLen)
if ta.crossover(close, upperFast)
strategy.entry("Long", strategy.long)
if ta.crossunder(close, lowerFast)
strategy.entry("Short", strategy.short)
strategy.exit("Long Exit", "Long", stop=lowerSlow)
strategy.exit("Short Exit", "Short", stop=upperSlow)
Tip. Stacking entries works best when you size by volatility. Add ATR-based position sizing so each additional leg risks the same amount of capital.

The double Donchian technique adds structure to breakout trading: fast channels detect new highs/lows quickly, while slower channels keep you in trends until meaningful reversals occur. Pine Script makes the entire Turtle-style blueprint approachable in a few dozen lines.

  • Configure two Donchian channels and decide which powers entries vs. exits.
  • Implement pyramiding with ATR-based risk so add-on trades stay proportionate.
  • Align exits (slow channel, ATR stops, or both) with the trend you’re capturing.
  • Plot channels and annotate fills for easier debugging.
HelperPurpose
ta.highest / ta.lowestConstruct Donchian channels (fast and slow).
`strategy(entryexit)`
ta.atrSize positions and compute emergency stops.
input.int, input.float, input.boolExpose tunable channel lengths, pyramiding, risk.
plot, fillVisualise channels and the zones between them.
  1. Capture channel settings & risk
    Provide inputs for fast/slow lengths, pyramiding count, ATR risk per leg.

    fastLen = input.int(20, "Fast channel", minval=1)
    slowLen = input.int(55, "Slow channel", minval=1)
    pyramid = input.int(2, "Pyramiding", minval=0, maxval=4)
    riskATR = input.float(2.0, "Stop distance (ATR)", step=0.1)
    strategy("Double Donchian", overlay=true, pyramiding=pyramid)
  2. Compute channels and sizing
    Generate upper/lower bands and calculate quantity from ATR.

    upperFast = ta.highest(high, fastLen)
    lowerFast = ta.lowest(low, fastLen)
    upperSlow = ta.highest(high, slowLen)
    lowerSlow = ta.lowest(low, slowLen)
    atr = ta.atr(14)
    riskCapital = strategy.equity * 0.01 // risk 1% by default
    qty = atr > 0 ? math.floor(riskCapital / (atr * riskATR)) : 0
  3. Stage entries & exits
    Use fast-channel breaks for entries; trail stops at the slow channel (or ATR-based fallbacks).

    if ta.crossover(close, upperFast) and qty > 0
    strategy.entry("Long", strategy.long, qty=qty)
    if ta.crossunder(close, lowerFast) and qty > 0
    strategy.entry("Short", strategy.short, qty=qty)
    strategy.exit("LX", "Long", stop=math.min(lowerSlow, strategy.position_avg_price - atr * riskATR))
    strategy.exit("SX", "Short", stop=math.max(upperSlow, strategy.position_avg_price + atr * riskATR))
//@version=5
strategy("Double Donchian Turtle", overlay=true, pyramiding=3, initial_capital=100_000, commission_type=strategy.commission.percent, commission_value=0.02)
// Inputs
donchianFast = input.int(20, "Fast Donchian", minval=2)
donchianSlow = input.int(55, "Slow Donchian", minval=2)
atrLen = input.int(14, "ATR length", minval=1)
riskPct = input.float(0.5, "Risk per leg (%)", minval=0.1, step=0.1)
atrStopMult = input.float(2.0, "ATR stop multiple", step=0.1)
// Channels
upperFast = ta.highest(high, donchianFast)
lowerFast = ta.lowest(low, donchianFast)
upperSlow = ta.highest(high, donchianSlow)
lowerSlow = ta.lowest(low, donchianSlow)
plot(upperFast, "Fast upper", color=color.new(color.green, 0))
plot(lowerFast, "Fast lower", color=color.new(color.green, 0))
plot(upperSlow, "Slow upper", color=color.new(color.orange, 0))
plot(lowerSlow, "Slow lower", color=color.new(color.orange, 0))
fill(plot(upperFast, display=display.none), plot(lowerFast, display=display.none), color=color.new(color.green, 95))
aTR = ta.atr(atrLen)
riskCash = strategy.equity * (riskPct * 0.01)
qty = aTR > 0 ? math.floor(riskCash / (aTR * atrStopMult)) : 0
longBreak = ta.crossover(close, upperFast)
shortBreak = ta.crossunder(close, lowerFast)
if longBreak and qty > 0
strategy.entry("Long", strategy.long, qty=qty)
if shortBreak and qty > 0
strategy.entry("Short", strategy.short, qty=qty)
if strategy.position_size > 0
stopLong = math.min(lowerSlow, strategy.position_avg_price - aTR * atrStopMult)
strategy.exit("Long Exit", "Long", stop=stopLong)
if strategy.position_size < 0
stopShort = math.max(upperSlow, strategy.position_avg_price + aTR * atrStopMult)
strategy.exit("Short Exit", "Short", stop=stopShort)
bgcolor(strategy.position_size > 0 ? color.new(color.green, 90) : strategy.position_size < 0 ? color.new(color.red, 90) : na)
var label status = na
if barstate.islast
if not na(status)
label.delete(status)
status = label.new(bar_index, close,
text="Equity: " + str.tostring(strategy.equity, "##,###.00") +
"\nOpen trades: " + str.tostring(strategy.opentrades, "0"),
style=label.style_label_left,
textcolor=color.white,
bgcolor=color.new(color.blue, 70))
Why this works.
  • Dual Donchian channels separate breakout detection (fast) from trailing exits (slow).
  • ATR-driven position sizing keeps each leg’s risk consistent as volatility changes.
  • Visual overlays (plots, fills, background) make it easy to confirm entries, exits, and pyramiding behaviour.
  • Lower the fast-channel length to generate more trades, or raise it to filter noise—slow channel should be significantly longer to avoid premature exits.
  • When pyramiding, consider limiting the maximum number of concurrent legs or scaling ATR stops tighter for late-stage entries.
  • Add filters (trend, volatility, session) if you want to avoid choppy regimes where Donchian breakouts whipsaw.
  • Always account for slippage and commission; longer-term breakouts can still suffer if costs aren’t factored in.

Reduce pyramiding or require a minimum distance from the previous entry (strategy.position_avg_price vs. current breakout level).

Add a minimum stop distance based on syminfo.mintick or allow users to cap ATR multiples with a secondary input.

How do I prevent entries during sideways ranges?

Section titled “How do I prevent entries during sideways ranges?”

Combine Donchian breakouts with volatility filters (e.g., ta.atr percentile) or only allow trades when the slow channel width exceeds a threshold.

  • Double Donchian systems pair fast breakout detection with slow trailing exits—perfect for trend following.
  • Pine Script makes it straightforward to implement both channels, pyramiding, and ATR-based risk sizing.
  • Visualise channels and annotate status to validate logic before live deployment.
  • Fine-tune channel lengths, pyramiding, and stop multiples to match the market you’re trading.

Adapted from tradingcode.net, optimised for Algo Trade Analytics users.