Debated1 min read
◆ The PatternBands set by average range instead of standard deviation, so a single outlier moves them less
Keltner Channels — Chester Keltner (1960), modernized by Linda Raschke.
Middle = EMA(20)
Upper = EMA(20) + 2 × ATR(10)
Lower = EMA(20) − 2 × ATR(10)
Upper = EMA(20) + 2 × ATR(10)
Lower = EMA(20) − 2 × ATR(10)
vs. Bollinger Bands:
• Bollinger uses σ (standard deviation) → more jagged
• Keltner uses ATR → smoother channels
• TTM Squeeze: Bollinger Bands move INSIDE Keltner Channels → extreme low volatility → explosive move imminent
• Bollinger uses σ (standard deviation) → more jagged
• Keltner uses ATR → smoother channels
• TTM Squeeze: Bollinger Bands move INSIDE Keltner Channels → extreme low volatility → explosive move imminent
Worked example
Middle line EMA(5), bands two ATR(5) away. Day 15: 102.53 ± 2 × 3.41, so 95.72 to 109.35. On the same day Bollinger’s bands are 98.21 to 105.79: the ATR bands are wider, and moved less on day 13’s drop (lower band 95.55, against Bollinger’s 98.48).
The example data: 15 days, used in every indicator here
| Day | High | Low | Close | Volume |
|---|---|---|---|---|
| 1 | 101 | 99 | 100 | 50,000 |
| 2 | 103 | 100 | 102 | 62,000 |
| 3 | 103 | 100 | 101 | 48,000 |
| 4 | 105 | 101 | 104 | 70,000 |
| 5 | 108 | 104 | 107 | 85,000 |
| 6 | 108 | 105 | 106 | 60,000 |
| 7 | 110 | 106 | 109 | 90,000 |
| 8 | 110 | 107 | 108 | 72,000 |
| 9 | 108 | 104 | 105 | 80,000 |
| 10 | 105 | 102 | 103 | 66,000 |
| 11 | 105 | 102 | 104 | 55,000 |
| 12 | 104 | 101 | 102 | 75,000 |
| 13 | 102 | 98 | 99 | 95,000 |
| 14 | 102 | 99 | 101 | 64,000 |
| 15 | 105 | 101 | 104 | 71,000 |
Where it misleads
- Band breaks are rarer than with Bollinger: fewer signals, and later ones.
- Band width comes from ATR, so one gap day widens the channel for several bars.
- Settings vary (an EMA of 20 with 2 × ATR of 10 is common; Keltner’s original used a 10-day average of the daily range), and results depend on which you pick.
In code
pc = df['close'].shift() tr = pd.concat([df['high'] - df['low'], (df['high'] - pc).abs(), (df['low'] - pc).abs()], axis=1).max(axis=1) atr = tr.ewm(alpha=1/5, adjust=False).mean() mid = df['close'].ewm(span=5, adjust=False).mean() df['kc_up'], df['kc_mid'], df['kc_lo'] = mid + 2 * atr, mid, mid - 2 * atr
Assumes import numpy as np, import pandas as pd, and a DataFrame df with columns high, low, close and volume — the 15 days above.
Sources
- C. W. Keltner, How to Make Money in Commodities, Keltner Statistical Service, 1960
- Trading Systems and Methods (5th ed.), P. J. Kaufman, Wiley, 2013
Last reviewed October 2026 · How this site checks its content · Report a mistake
Pattern bridge: EMA ± ATR multiples blend trend and volatility — like confidence intervals around a moving center.
Linked from 1