Trading Strategy

Keltner Channels Strategy

A volatility-based trading strategy using Keltner Channels (ATR-based bands) to identify momentum breakouts and trend strength.

ATR-Based Volatility Bands

Keltner Channels are volatility-based bands placed around an EMA, using Average True Range (ATR) instead of standard deviation (unlike Bollinger Bands). This strategy identifies momentum breakouts when price closes beyond the outer bands, combined with a 200 EMA trend filter and RSI confirmation for higher probability trades.

Volatility Type
4h Chart Timeframe
Intermediate Complexity
Trending Best Market

Signal Logic

Long (Buy)

Price breaks above upper Keltner Channel while above 200 EMA, with RSI above 50 for momentum confirmation.

Short (Sell)

Price breaks below lower Keltner Channel while below 200 EMA, with RSI below 50 for momentum confirmation.

Implementation

//@version=6
strategy("Keltner Channels Strategy", overlay=true, initial_capital=1000000, default_qty_type=strategy.percent_of_equity, default_qty_value=100)

// ==========================================
// 🔹 INPUTS
// ==========================================
// Group: Keltner Channel Settings
grp_kc = "Keltner Channel Settings"
ema_len   = input.int(20, "EMA Length", minval=1, group=grp_kc)
atr_len   = input.int(10, "ATR Length", minval=1, group=grp_kc)
mult      = input.float(2.0, "ATR Multiplier", step=0.1, group=grp_kc)

// Group: Trend Filter
grp_trend = "Trend Filter"
use_trend = input.bool(true, "Use Trend Filter (EMA 200)", group=grp_trend)
ema200_len = input.int(200, "Trend EMA Length", minval=1, group=grp_trend)

// Group: Confirmation
grp_confirm = "Confirmation"
use_momentum = input.bool(true, "Use RSI Confirmation", group=grp_confirm)
rsi_len = input.int(14, "RSI Length", minval=1, group=grp_confirm)

// Group: Risk Management
grp_risk = "Risk Management"
tp_ratio = input.float(2.0, "Risk:Reward Ratio", step=0.1, group=grp_risk)

// ==========================================
// 🔹 CALCULATIONS
// ==========================================
// Keltner Channel - EMA ± ATR multiplier
ema_val = ta.ema(close, ema_len)
atr_val = ta.atr(atr_len)
upper_band = ema_val + (mult * atr_val)
lower_band = ema_val - (mult * atr_val)

// Trend EMA
ema200_val = ta.ema(close, ema200_len)

// RSI for momentum confirmation
rsi_val = ta.rsi(close, rsi_len)

// Trend conditions
trend_up = use_trend ? close > ema200_val : true
trend_down = use_trend ? close < ema200_val : true

// Channel breakout conditions
price_breaks_above_upper = close > upper_band[1] and close[1] <= upper_band[1]
price_below_lower = close < lower_band[1] and close[1] >= lower_band[1]

// ==========================================
// 🔹 STRATEGY LOGIC
// ==========================================
// Long Entry: Price breaks above upper Keltner Channel (bullish momentum)
long_signal = price_breaks_above_upper and trend_up

if use_momentum
    long_signal := long_signal and rsi_val > 50

// Short Entry: Price breaks below lower Keltner Channel (bearish momentum)
short_signal = price_below_lower and trend_down

if use_momentum
    short_signal := short_signal and rsi_val < 50

// ==========================================
// 🔹 EXECUTION & RISK MANAGEMENT
// ==========================================

if long_signal
    strategy.entry("Long", strategy.long, comment="L | KC Breakout")

if short_signal
    strategy.entry("Short", strategy.short, comment="S | KC Breakout")

// Risk management
if strategy.position_size > 0
    stop_level = lower_band
    profit_level = strategy.position_avg_price + (strategy.position_avg_price - stop_level) * tp_ratio
    strategy.exit("Exit Long", "Long", stop=stop_level, limit=profit_level, comment_loss="SL", comment_profit="TP")

if strategy.position_size < 0
    stop_level = upper_band
    profit_level = strategy.position_avg_price - (stop_level - strategy.position_avg_price) * tp_ratio
    strategy.exit("Exit Short", "Short", stop=stop_level, limit=profit_level, comment_loss="SL", comment_profit="TP")

// ==========================================
// 🔹 VISUALS
// ==========================================
// Plot Keltner Channel bands
plot(upper_band, "Upper Band", color=color.new(color.red, 0), linewidth=1)
plot(ema_val, "Middle EMA", color=color.new(color.blue, 0), linewidth=2)
plot(lower_band, "Lower Band", color=color.new(color.green, 0), linewidth=1)

// Plot Trend EMA
plot(use_trend ? ema200_val : na, "Trend EMA", color=color.new(color.orange, 0), linewidth=2)

// Plot Signals
plotshape(long_signal, title="Long Signal", location=location.belowbar, color=color.green, style=shape.labelup, text="BUY", textcolor=color.white)
plotshape(short_signal, title="Short Signal", location=location.abovebar, color=color.red, style=shape.labeldown, text="SELL", textcolor=color.white)

// Fill between bands
fill(plot(upper_band), plot(lower_band), color=color.new(color.blue, 95))