Master these dynamic volatility envelopes in TradingView's Pinescript for identifying trend direction, anticipating breakouts, and understanding market volatility.
Keltner Channels (KC) are volatility-based envelopes plotted on either side of a central moving average. Originally developed by Chester Keltner in the 1960s and later updated by Linda Bradford Raschke, they are similar to Bollinger Bands but use the Average True Range (ATR) to set their width, rather than standard deviation. This makes Keltner Channels slightly less reactive to extreme price spikes than Bollinger Bands, often providing a smoother channel.
Keltner Channels consist of three lines:
The calculation of Keltner Channels involves a moving average and the Average True Range (ATR):
//@version=5
indicator("My Keltner Channels", overlay=true) // overlay=true to plot directly on the price chart
// Inputs for Keltner Channels parameters
length = input.int(20, title="KC Length (EMA/ATR)", minval=1)
atrMultiplier = input.float(2.0, title="ATR Multiplier", minval=0.1, step=0.1)
source = input(close, title="Source") // Common sources: close, hlc3
// Calculate Keltner Channels using the built-in function
// ta.keltner returns the Middle, Upper, and Lower channel lines
[middleLine, upperChannel, lowerChannel] = ta.keltner(source, length, atrMultiplier)
// Plot the Middle Line
plot(middleLine, title="Middle Line", color=color.blue, linewidth=2)
// Plot the Upper and Lower Channel Lines
plot(upperChannel, title="Upper Channel", color=color.red, linewidth=1)
plot(lowerChannel, title="Lower Channel", color=color.green, linewidth=1)
// Fill the area between the channels for visual appeal
fill(upperChannel, lowerChannel, color.new(color.blue, 90), title="KC Background")
Keltner Channels use ATR, which is a robust measure of volatility that accounts for gaps, making them potentially more stable than standard deviation-based bands in certain markets.
//@version=5
strategy("Keltner Channel Breakout Strategy", overlay=true)
length = input.int(20, title="KC Length", minval=1)
atrMultiplier = input.float(2.0, title="ATR Multiplier", minval=0.1, step=0.1)
source = input(close, title="Source")
[middleLine, upperChannel, lowerChannel] = ta.keltner(source, length, atrMultiplier)
plot(middleLine, "Middle Line", color.blue)
plot(upperChannel, "Upper Channel", color.red)
plot(lowerChannel, "Lower Channel", color.green)
fill(upperChannel, lowerChannel, color.new(color.blue, 90))
// Conditions for a bullish breakout
longCondition = close > upperChannel and close[1] <= upperChannel[1] // Current close above upper, previous below or equal
// Conditions for a bearish breakout
shortCondition = close < lowerChannel and close[1] >= lowerChannel[1] // Current close below lower, previous above or equal
if (longCondition)
strategy.entry("Long Breakout", strategy.long)
if (shortCondition)
strategy.entry("Short Breakout", strategy.short)
// Example exits: close on touch of opposite channel or Middle Line, or based on fixed stop/target
strategy.exit("Long Exit", from_entry="Long Breakout", stop=middleLine) // Exit if price returns to middle
strategy.exit("Short Exit", from_entry="Short Breakout", stop=middleLine)
//@version=5
strategy("Keltner Channel Mean Reversion", overlay=true)
length = input.int(20, title="KC Length", minval=1)
atrMultiplier = input.float(1.5, title="ATR Multiplier (for range)", minval=0.1, step=0.1) // Smaller multiplier for ranging
source = input(close, title="Source")
[middleLine, upperChannel, lowerChannel] = ta.keltner(source, length, atrMultiplier)
plot(middleLine, "Middle Line", color.blue)
plot(upperChannel, "Upper Channel", color.red)
plot(lowerChannel, "Lower Channel", color.green)
fill(upperChannel, lowerChannel, color.new(color.blue, 90))
// A simple way to detect ranging: check if price has been mostly inside bands recently
// Or use an external indicator like Choppiness Index for ranging conditions.
isRanging = close > lowerChannel and close < upperChannel and (upperChannel - lowerChannel) / middleLine * 100 < 5.0 // Bands not too wide
// Buy when price bounces off Lower Channel
longReversion = isRanging and close > lowerChannel and close[1] <= lowerChannel[1]
// Sell when price bounces off Upper Channel
shortReversion = isRanging and close < upperChannel and close[1] >= upperChannel[1]
if (longReversion)
strategy.entry("Buy Reversion", strategy.long)
if (shortReversion)
strategy.entry("Sell Reversion", strategy.short)
// Exit at Middle Line (primary target) or if price breaks out of the range
strategy.close("Buy Reversion", when=close > middleLine or close < lowerChannel) // Close on middle or if it breaks down
strategy.close("Sell Reversion", when=close < middleLine or close > upperChannel) // Close on middle or if it breaks up
//@version=5
indicator("BB-KC Squeeze Detection", overlay=true)
// Keltner Channel settings
kcLength = input.int(20, title="KC Length", minval=1)
kcAtrMultiplier = input.float(2.0, title="KC ATR Multiplier", minval=0.1, step=0.1)
kcSource = input(close, title="KC Source")
// Bollinger Bands settings
bbLength = input.int(20, title="BB Length", minval=1)
bbStdDevMultiplier = input.float(2.0, title="BB StdDev Multiplier", minval=0.1, step=0.1)
bbSource = input(close, title="BB Source")
// Calculate Keltner Channels
[kcMiddle, kcUpper, kcLower] = ta.keltner(kcSource, kcLength, kcAtrMultiplier)
// Calculate Bollinger Bands
[bbMiddle, bbUpper, bbLower] = ta.bb(bbSource, bbLength, bbStdDevMultiplier)
// Plot Keltner Channels
plot(kcMiddle, "KC Middle", color.blue, linewidth=2)
plot(kcUpper, "KC Upper", color.purple, linewidth=1, style=plot.style_linebr)
plot(kcLower, "KC Lower", color.purple, linewidth=1, style=plot.style_linebr)
// Plot Bollinger Bands
plot(bbUpper, "BB Upper", color.orange, linewidth=1)
plot(bbLower, "BB Lower", color.orange, linewidth=1)
// Detect squeeze: BBs are inside KCs (i.e., BB_Upper < KC_Upper AND BB_Lower > KC_Lower)
isSqueeze = bbUpper < kcUpper and bbLower > kcLower
// Highlight squeeze periods
bgcolor(isSqueeze ? color.new(color.yellow, 80) : na, title="Squeeze Detected")
alertcondition(isSqueeze, "BB-KC Squeeze", "Bollinger Bands are squeezing inside Keltner Channels.")
To get the most from Keltner Channels in Pinescript:
Keltner Channels are generally smoother due to using ATR, making them more suitable for identifying sustained trends and breakouts. Bollinger Bands, with standard deviation, are more reactive to single bar extremes and better for detecting short-term overextensions and squeezes.
Keltner Channels are a robust and versatile technical analysis tool in Pinescript for TradingView. By providing dynamic price envelopes based on Average True Range, they offer traders a clear visual representation of price volatility and trend boundaries. Whether you are looking to capitalize on strong trend continuations, identify potential breakouts, or execute mean-reversion strategies, understanding and effectively applying Keltner Channels, ideally in conjunction with other indicators and sound risk management, can significantly enhance your trading decisions and overall performance. They provide a vital context for discerning trend strength and potential turning points in various market conditions.
Get a high-performance Pinescript analysis tool for actionable market insights, designed for traders on the move.
This strategy runs in live mode on TradingView, helping you identify potential opportunities.
Get Pinescript Strategy