Skip to content

Free TradingView indicator

Keltner Channel Breakout

EMA and ATR Keltner Channel that marks closes outside the channel, with an optional slope filter and alerts.

Breakoutv1.0TradingView (Pine Script v6) Non-repainting signals Alerts

What it does

The Keltner Channel wraps an exponential moving average with bands set a fixed number of Average True Ranges away. Because the width comes from ATR rather than standard deviation, the channel reacts smoothly to changes in volatility and is less jumpy than Bollinger Bands.

This version marks the bar that closes outside the channel. A close above the upper line is a bullish breakout, a close below the lower line is a bearish breakout. The channel fill takes the color of the most recent breakout, so you can see at a glance which side last broke.

How it works

  1. Basis = EMA of the source over EMA length bars (a moving average that weights recent prices more).
  2. ATR = Average True Range over ATR length bars.
  3. Upper = basis + multiplier × ATR. Lower = basis − multiplier × ATR.
  4. A raw bullish breakout occurs when the close is above the upper line and the previous close was at or below the previous upper line. A raw bearish breakout mirrors this below the lower line.
  5. Optional slope filter: the basis must be higher (for longs) or lower (for shorts) than it was Slope lookback bars ago.
  6. With "Only first breakout per side" on, a second bullish breakout is ignored until a bearish breakout has happened, and vice versa.
  7. All signals are evaluated on closed bars only.

How to use it

A close outside the Keltner Channel says price has moved further than its recent average range would suggest. Trend followers often read that as momentum; mean-reversion traders treat the same event as stretched. This tool is written for the first reading, so it works best when the market has a reason to trend, for example after a range on the higher timeframe.

Practical ideas:

  • Use the slope filter to avoid breakouts against the prevailing direction of the EMA.
  • Combine with a higher-timeframe trend or support and resistance map so you are not buying straight into a known ceiling.
  • The basis line can act as a trailing reference. Some traders exit when price closes back on the other side of the EMA.

Place a stop-loss where the breakout idea is clearly wrong, often back inside the channel or beyond the basis, and check the risk-reward ratio before entering.

Settings

InputDefaultWhat it changes
Basis sourceclosePrice used for the EMA.
EMA length20Smoothness of the center line.
ATR length10Smoothness of the channel width.
ATR multiplier2.0Wider channel = fewer, stronger breakouts.
Require EMA slopeoffFilters breakouts against the EMA direction.
Slope lookback (bars)3Bars compared for the slope filter.
Only first breakout per sideonRemoves repeated same-side signals.
Fill channelonVisual only.

Limitations

  • Breakouts fail often in ranging markets. The indicator does not know whether the market is trending.
  • The EMA and ATR both lag, so the channel adjusts after volatility changes, not before.
  • Spikes around news releases can close outside the channel and reverse on the next bar.
  • With "Only first breakout per side" on, a valid continuation breakout after a pullback will not be marked unless the opposite side broke in between.
  • Signals appear only when the bar closes, which is later than an intrabar touch.

Pine Script source

In TradingView open Pine Editor, paste the code, click Save and then Add to chart.

FXP_KeltnerChannelBreakout.pine

60 lines

// © FXPIPS ONLINE — https://fxpips.online/tradingview-indicators/keltner-channel-breakout/
// License: MIT. Educational tool — not financial advice. Trading involves substantial risk.
//@version=6
indicator("FXP Keltner Channel Breakout", shorttitle = "FXP Keltner", overlay = true)

// ── Inputs ─────────────────────────────────────────────────────────────
grpKC     = "Keltner Channel"
src       = input.source(close, "Basis source", group = grpKC)
emaLen    = input.int(20, "EMA length", minval = 1, group = grpKC)
atrLen    = input.int(10, "ATR length", minval = 1, group = grpKC)
atrMult   = input.float(2.0, "ATR multiplier", minval = 0.1, step = 0.1, group = grpKC)

grpSig    = "Signals"
useSlope  = input.bool(false, "Require EMA slope in breakout direction", group = grpSig)
slopeBars = input.int(3, "Slope lookback (bars)", minval = 1, group = grpSig)
oncePerSide = input.bool(true, "Only first breakout per side", group = grpSig, tooltip = "Ignore repeat breakouts in the same direction until the opposite side breaks.")

grpVis    = "Display"
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 ────────────────────────────────────────────────────────
basis = ta.ema(src, emaLen)
atr   = ta.atr(atrLen)
upper = basis + atrMult * atr
lower = basis - atrMult * atr

bool slopeUp = basis > basis[slopeBars]
bool slopeDn = basis < basis[slopeBars]

bool rawBull = close > upper and close[1] <= upper[1] and (not useSlope or slopeUp)
bool rawBear = close < lower and close[1] >= lower[1] and (not useSlope or slopeDn)

// Last confirmed breakout direction: 1 = up, -1 = down, 0 = none yet
var int lastDir = 0
bool bullBreak = false
bool bearBreak = false
if barstate.isconfirmed
    if rawBull and (not oncePerSide or lastDir != 1)
        bullBreak := true
        lastDir := 1
    else if rawBear and (not oncePerSide or lastDir != -1)
        bearBreak := true
        lastDir := -1

// ── Plots ──────────────────────────────────────────────────────────────
color stateCol = lastDir == 1 ? bullCol : lastDir == -1 ? bearCol : color.gray
plot(basis, "Basis (EMA)", color = color.new(stateCol, 20))
pU = plot(upper, "Upper channel", color = color.new(bullCol, 30))
pL = plot(lower, "Lower channel", color = color.new(bearCol, 30))
fill(pU, pL, color = showFill ? color.new(stateCol, 92) : 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 Keltner breakout", "FXP Keltner: close above upper channel on {{ticker}} {{interval}} at {{close}}")
alertcondition(bearBreak, "Bearish Keltner breakout", "FXP Keltner: close below lower channel on {{ticker}} {{interval}} at {{close}}")

Key inputs

Key inputs of Keltner Channel Breakout
InputDefaultDescription
EMA length20Length of the exponential moving average at the center of the channel.
ATR length10Bars used for the Average True Range.
ATR multiplier2.0Channel half-width in multiples of ATR.
Require EMA slope in breakout directionfalseOnly count breakouts when the EMA is rising (long) or falling (short).
Only first breakout per sidetrueSuppress repeat signals in the same direction until the opposite side breaks.

Educational tools, not advice. Indicators and Expert Advisors describe price; they do not predict it, and past behaviour does not guarantee future results. Test everything on a demo account first and never risk money you cannot afford to lose. See our disclaimer.

Keep exploring

Related tradingview indicators