Skip to content
Open RaamTrade

KeltnerChannels — Keltner Channels

An EMA centreline with bands a multiple of ATR away. Against Bollinger: ATR is gap-aware and smoother than a standard deviation of closes, so Keltner bands don’t balloon on one outlier close. The squeeze setup (Bollinger inside Keltner) needs both.

Signature

KeltnerChannels(period, atr_period, multiplier, on=<source>)
Argument Type Required Notes
period int Param or literal Yes EMA length. Default 20, bounds 1–400.
atr_period int Param or literal Yes ATR length. Default 10, bounds 1–100.
multiplier float Param or literal Yes Band width in ATRs. Default 2.0, bounds 0.1–10.0.
on= symbol No Source symbol. Defaults to the trade symbol. Reads high, low, close.

Formula

$$ \text{mid} = \text{EMA}(C, n), \quad \text{upper/lower} = \text{mid} \pm m,\text{ATR}(n_{atr}) $$

Warmup

The EMA seeds from the first close; the ATR seeds as a cumulative average over its first atr_period bars, then Wilder smoothing. Both converge over roughly 3n bars.

Reading the value

kc.upper
kc.mid
kc.lower
self.trade.close > kc.upper

Multi-value: cannot be chained onto or crossed.

Example

class KeltnerRide(Strategy):
"""Enter on a close above the upper channel; exit at the midline."""
trade = Symbol()
sizing = FixedCapital()
def execute(self):
kc = KeltnerChannels(20, 10, 2.0, on=self.trade)
if self.trade.close > kc.upper and self.trade.is_flat:
self.buy(self.trade, reason="Keltner breakout")
if self.trade.close < kc.mid and self.trade.is_long:
self.sell(self.trade, self.trade.position, reason="Back to midline")

Notes

  • Chester Keltner’s channel in the modern EMA+ATR form (Linda Raschke’s variant).
  • Proven by an assert-via-trade run on SPY daily (midline and band width converged to an independent EMA/ATR replication within 0.05 once warm; zero alarm trades).
  • The band is symmetric by construction: upper − mid == mid − lower.
  • The recursion seeds from the first bar rather than from a warm-up window, so early values are not comparable with TA-Lib EMA(20) ± 2 × ATR(10), which seeds from an average of the first n; measured on a 300-bar tape the two agree to 1e-6 from bar 111 onward.