Keltner Channels: Explained & Coded

Keltner Channels are a technical indicator that combines an exponential moving average with volatility-based envelopes set above and below the EMA at a fixed percentage of the same duration. Keltner Channels aim to identify the underlying price trend and over-extended conditions.

In this post, we’re going to dive deep into what Keltner Channels are, how they are used in strategies, and how to backtest them in Backtrader.

Keltner Channel History

In 1960, Chester Keltner introduced Keltner Channels in his famous book How to Make Money in Commodities. Initially, Keltner Channels used the 10-day simple moving averages as the centerline, and the high-low range was subtracted and added from the envelope lines.

Famed market wizard Linda Bradford Raschke modified Keltner Channels in 1980 to a volatility-baed indicator using Average True Range (ATR) to set the channel width. Today, most use Linda’s version of the Kelter Channel.

What Does the Keltner Tell Us?

Like all technical analysis indicators, Keltner Channels are a tool for traders to help understand price action – or the psychology of the market. When we understand the psychology of the market, we can more easily identify supply and demand issues and exploit them for profit.

Keltner Channels are a lagging indicator designed to identify the prevalent price trend.

The Keltner Channel midline shows the price trend. A breach of the envelope, which is a cross of the upper or lower lines surrounding the midline, can be interpreted as a price breakout or overbought/oversold conditions.

A breakout is where we expect price action to continue, and overbought/oversold conditions lead to price reverting, also known as mean reversion.

With a breach of the Keltner Channels potentially leading to two different results, how do we go about determining if the market is likely to mean revert or to continue?

We’ll go over that soon, but before we do, let’s discover how to calculate Keltner Channels.

Keltner Channel Calculation

Keltner Channels have a middle line, also known as a basis, and upper and lower channel lines collectively referred to as the envelope. The picture below shows an example of a Keltner Channel for the S&P 500 daily chart.

Keltner Channel Example The middle line is an exponential moving average. This midline conventionally uses a 20-period EMA.

The envelope lines typically are set above and below the basis by two times the Average True Range. Some calculations use a multiple of the daily high/low range, but it is more common to use the ATR.

The formulas for each component are below.

\[Middle Line (Basis) = EMA\\Upper Channel Line = EMA + 2 * ATR\\Lower Channel Line = EMA + 2 * ATR\]

Keltner Channel Limitations

Like many indicators, there’s a tug-of-war going on between signal vs. noise.

If you set the EMA too slow, the trend will be easy to see, but the channels won’t respond quickly to price changes; however, setting the EMA too short will reverse this problem. The trend will be harder to identify, but the channels will incorporate price action more quickly. See the below.

Keltner Channel Slow EMA

Keltner Channel Fast EMA

If you configure the envelopes too narrowly, the signal will occur more frequently but may be less reliable. If the envelopes are set too broad, you may not even get a signal to trade, as shown below.

Keltner Channel Low ATR

Keltner Channel High ATR

Additionally, no rule states Keltner Channels must act as support or resistance. Indicators are just tools to help the trader understand the price action.

It’s important to note that Keltner Channels use moving averages, which means it’s inherently a lagging indicator. Lagging indicators do precisely that: they lag behind price. This lag naturally means the indicator is providing delayed feedback.

With the drawbacks out of the way, let’s discuss how Keltner Channels compare to its close cousin: Bollinger Bands.

Keltner Channels vs. Bollinger Bands

Keltner Channels and Bollinger Bands are very similar. You can see them overlaid on one another below with the Keltner Channels in red and the Bollinger Bands in green.

Keltner Channel and Bollinger Band

The midline and envelopes are calculated differently in Keltner Channels and Bollinger Bands.

Bollinger Bands calculate the midline using a simple moving average, whereas Keltner Channels use an exponential moving average. This calculation difference causes Bollinger Bands to react more slowly to changes in price direction.

Additionally, while Keltner Channels use the Average True Range (ATR) to calculate the envelope lines, Bollinger Bands use standard deviation. Standard deviation is often abbreviated SD and expresses the variability of a population. If you’re interested, you can learn more about standard deviation.

Without getting too technical, Keltner Channels are smoother than Bollinger bands as standard deviation is more volatile than the Average True Range.

Keltner Channel Trading Strategies

Prices are either trending or not. The key to using Keltner Channels is to understand if there is a trend and what that underlying trend is.

Strong Trend, Breakout

During a clearly defined trend, a cross of the channel can signify strength. To see this in action, look at the Shopify weekly chart for an example demonstrating a breakout.

Keltner Channel Strength

Strong Trend, Pullback

Weeks later, Shopify pulls back to the basis line. With a strong trend in place, this is often an excellent time to buy. See the Shopify weekly chart a profitable pullback.

Keltner Channel Strength

And while Shopify and the market’s trend was up, the mirror is also true. A breakdown of the lower Keltner Channel while in a downtrend can be a profitable short. The same goes for a pullback.

Sideways Market, False Breakout

Price action exhibits different behavior in markets that are trending and markets that are not. When a market isn’t trending, the Keltner Channels are more prone to be overbought or oversold conditions.

Keltner Channel Strength

Sideways Market, Volatility Breakout

Volatility breakouts are a style of short-term trading designed to capture the next move. When prices contract and then make a significant move to the upside or downside, the odds favor the immediate momentum.

The Bitcoin chart below demonstrates prices contracting and then a meaningful move up, relative to recent history, with continued momentum.

Keltner Channel Strength

While Keltner Channels are useful at understanding price action, they can be combined with other indicators on multiple timeframes to improve their signal.

Remember, when analyzing price action, we’re trying to profit from supply and demand imbalances.

Keltner Channels Coded

Let’s create Keltner Channels in Python using Backtrader now that we understand how this indicator works and when to use it.

class KeltnerChannel(bt.Indicator):
    lines = ('mid', 'upper', 'lower')
    params = dict(

    plotinfo = dict(subplot=False)  # plot along with data
    plotlines = dict(
        mid=dict(ls='--'),  # dashed line
        upper=dict(_samecolor=True),  # use same color as prev line (mid)
        lower=dict(_samecolor=True),  # use same color as prev line (upper)

    def __init__(self):
        self.l.mid = bt.ind.EMA(period=self.p.ema)
        self.l.upper = self.l.mid + bt.ind.ATR(period=self.p.ema) * self.p.atr
        self.l.lower = self.l.mid - bt.ind.ATR(period=self.p.ema) * self.p.atr

The code is pretty easy to understand. We set the parameters to a 20-period EMA and a 2 ATR. I want the Keltner Channels to appear on the same graph as the price, so I set subplot=false. I also configure the plotlines as desired. After that, I create all three lines in __init__ based on the math we covered previously.

Now that we’ve created the Keltner Channel indicator, let’s get it to graph overtop of SPY. I won’t cover the code as it’s already been covered in Backtrader: Getting Started Backtesting Strategies

class Strategy(bt.Strategy):

    def __init__(self):
        self.keltner = KeltnerChannel()

    def next(self):
        if self.keltner.l.lower[0] >[0]:
        elif self.keltner.l.upper[0] <[0]:

if __name__ == '__main__':
    # Create cerebro instance
    cerebro = bt.Cerebro()

    # Add Benchmark
    benchmark = get_security_data(BENCHMARK_TICKER, START, END)
    benchdata = bt.feeds.PandasData(dataname=benchmark, name='SPY', plot=True)

    print('Starting Portfolio Value: %.2f' %

    # Add Strategy
    results =

    print('Final Portfolio Value: %.2f' %


Backtrader will use Matplotlib to create something similar to the following if everything is setup correctly.

Keltner Channel in Backtrader


Leo Smigel

Based in Pittsburgh, Analyzing Alpha is a blog by Leo Smigel exploring what works in the markets.