Algorithmic Trading with the Keltner Channel in Python

A must-know indicator for all the traders out there



Introduction


While you’re studying technical indicators, you would definitely come across a list comprising curated indicators that are widely considered as ‘must-know’ indicators that need to be learned by you before getting your hands dirty in the real-world market. The indicator we are going to explore today adds to this list given its performance in the market. It’s none other than the Keltner Channel (KC).


In this article, we will first discuss what the Keltner Channel is all about, and the mathematics behind the indicator. Then, we will proceed to the programming part where we will use Python to build the indicator from scratch, construct a simple trading strategy based on the indicator, backtest the strategy on Intel stocks, and finally, compare the strategy returns with those of the SPY ETF (an ETF particularly designed to track the movements of the S&P 500 market index).


Average True Range (ATR)


It is essential to know what the Average True Range (ATR) is since it is involved in the calculation of the Keltner Channel.


Founded by Wilder Wiles (creator of the most popular indicator, the RSI), the Average True Range is a technical indicator that measures how much an asset moves on an average. It is a lagging indicator meaning that it takes into account the historical data of an asset to measure the current value but it’s not capable of predicting the future data points. This is not considered as a drawback while using ATR as it’s one of the indicators to track the volatility of a market more accurately. Along with being a lagging indicator, ATR is also a non-directional indicator meaning that the movement of ATR is inversely proportional to the actual movement of the market. To calculate ATR, it is requisite to follow two steps:

  • Calculate True Range (TR): A True Range of an asset is calculated by taking the greatest values of three price differences which are: market high minus marker low, market high minus previous market close, previous market close minus market low. It can be represented as follows:



MAX [ {HIGH - LOW}, {HIGH - P.CLOSE}, {P.CLOSE - LOW} ]

where,
MAX = Maximum values
HIGH = Market High
LOW = Market Low
P.CLOSE = Previous market close


  • Calculate ATR: The calculation for the Average True Range is simple. We just have to take a smoothed average of the previously calculated True Range values for a specified number of periods. The smoothed average is not just any SMA or EMA but an own type of smoothed average created by Wilder Wiles himself which is nothing but subtracting one from the Exponential Moving Average of the True Range for a specified number of periods and multiplying the difference with two. The calculation of ATR for a specified number of periods can be represented as follows:



ATR N = EMA N [ TR ] - 1 * 2

where,
ATR N = Average True Range of 'N' period
SMA N = Simple Moving Average of 'N' period
TR = True Range


While using ATR as an indicator for trading purposes, traders must ensure that they are cautious than ever as the indicator is very lagging. Now that we have an understanding of what the Average True Range is all about. Let’s now dive into the main concept of this article, the Keltner Channel.


Keltner Channel (KC)


Founded by Chester Keltner, the Keltner Channel is a technical indicator that is often used by traders to identify volatility and the direction of the market. The Keltner Channel is composed of three components: The upper band, the lower band, and the middle line. Now, let’s discuss how each of the components is calculated.


Before diving into the calculation of the Keltner Channel it is essential to know about the three important inputs involved in the calculation. First is the ATR lookback period which is nothing but the number of periods that are taken into account for the calculation of ATR. Secondly, the Keltner Channel lookback period. This input is more or less similar to the first one but here, we are determining the number of periods that are taken into account for the calculation of the Keltner Channel itself. The final input is the multiplier which is a value determined to multiply with the ATR. The typical values that are taken as inputs are 10 as the ATR lookback period, 20 as the Keltner Channel lookback period, and 2 as the multiplier. Keeping these inputs in mind, let’s calculate the readings of the Keltner Channel’s components.


The first step in calculating the components of the Keltner Channel is determining the ATR values with 10 as the lookback period and it can be calculated by following the formula discussed before.


The next step is calculating the middle line of the Keltner Channel. This component is nothing but the 20-day Exponential Moving Average of the closing price of the stock. The calculation can be represented as follows:



MIDDLE LINE 20 = EMA 20 [ C.STOCK ]

where,
EMA 20 = 20-day Exponential Moving Average 
C.STOCK = Closing price of the stock


The final step is calculating the upper and lower bands. Let’s start with the upper band. It is calculated by first adding the 20-day Exponential Moving Average of the closing price of the stock by the multiplier (two) and then, multiplied by the 10-day ATR. The lower band calculation is almost similar to that of the upper band but instead of adding, we will be subtracting the 20-day EMA by the multiplier. The calculation of both upper and lower bands can be represented as follows:



UPPER BAND 20 = EMA 20 [ C.STOCK ] + MULTIPLIER * ATR 10
LOWER BAND 20 = EMA 20 [ C.STOCK ] - MULTIPLIER * ATR 10

where,
EMA 20 = 20-day Exponential Moving Average 
C.STOCK = Closing price of the stock
MULTIPLIER = 2
ATR 10 = 10-day Average True Range


That’s the whole process of calculating the components of the Keltner Channel. Now, let’s analyze a chart of the Keltner Channel to build more understanding of the indicator.



The above chart is a graphical representation of Intel’s 20-day Keltner Chanel. We could notice that two bands are plotted on either side of the closing price line and those are nothing but the upper and lower band and a grey-colored line running in-between the two bands is the middle line or the 20-day EMA. The Keltner Channel can be used in an extensive number of ways but the most popular usages are identifying the market volatility and direction.


The volatility of the market can be determined by the space that exists between the upper and lower band. If the space between the bands is wider, then the market is said to be volatile or showing greater price movements. On the other hand, the market is considered to be in a state of non-volatile or consolidating if the space between the bands is narrow. The other popular usage is identifying the market direction. The market direction can be determined by following the direction of the middle line as well as the upper and lower band.


While seeing the chart of the Keltner Channel, it might resemble the Bollinger Bands. The only difference between these two indicators is the way each of them is being calculated. The Bollinger Bands use standard deviation for its calculation, whereas, the Keltner Channel utilizes ATR to calculate its readings. Now, let’s talk about the trading strategy we are going to implement in this article.


About our trading strategy: We are going to implement the most popular Keltner Channel trading strategy which is the Breakout strategy. Since the Keltner Channel is prone to revealing false signals, we are going to tune the traditional breakout strategy. Our tuned strategy will reveal a buy signal whenever the closing price line crosses from above to below the lower band and the current closing price is lesser than the next closing price of the stock. Similarly, a sell signal is revealed whenever the closing price line crosses from below to above the upper band and the current closing price is greater than the next closing price of the stock. Our trading strategy can be represented as follows:



IF C.CLOSE < C.KCLOWER AND C.CLOSE < N.CLOSE ==> BUY SIGNAL
IF C.CLOSE > C.KCUPPER AND C.CLOSE > N.CLOSE ==> SELL SIGNAL


Many other strategies can also be implemented based on the Keltner Channel indicator but just to make things simple to understand, we are going with the breakout strategy. This concludes our theory part on the Keltner Channel indicator. Now, let’s move on to the programming part where we are first going to build the indicator from scratch, build the breakout strategy which we just discussed, then, compare our strategy’s performance with the SPY ETF’s returns in Python. Let’s do some coding! Before moving on, a note on disclaimer: This article’s sole purpose is to educate people and must be considered as an information piece but not as investment advice or so.


Implementation in Python


The coding part is classified into various steps as follows:



1. Importing Packages
2. Extracting Stock Data from Twelve Data
3. Keltner Channel Calculation
4. Creating the Breakout Trading Strategy
5. Plotting the Trading Lists
6. Creating our Position
7. Backtesting
8. SPY ETF Comparison


We will be following the order mentioned in the above list and buckle up your seat belts to follow every upcoming coding part.


Step-1: Importing Packages


Importing the required packages into the python environment is a non-skippable step. The primary packages are going to be Pandas to work with data, NumPy to work with arrays and for complex functions, Matplotlib for plotting purposes, and Requests to make API calls. The secondary packages are going to be Math for mathematical functions and Termcolor for font customization (optional).


Python Implementation:



# IMPORTING PACKAGES

import requests
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from termcolor import colored as cl
from math import floor

plt.rcParams['figure.figsize'] = (20,10)
plt.style.use('fivethirtyeight')


Now that we have imported all the required packages into our python. Let’s pull the historical data of Intel with Twelve Data’s API endpoint.


Step-2: Extracting data from Twelve Data


In this step, we are going to pull the historical stock data of Intel using an API endpoint provided by twelvedata.com. Before that, a note on twelvedata.com: Twelve Data is one of the leading market data providers having an enormous amount of API endpoints for all types of market data. It is very easy to interact with the APIs provided by Twelve Data and has one of the best documentation ever. Also, ensure that you have an account on twelvedata.com, only then, you will be able to access your API key (vital element to extract data with an API).


Python Implementation:



# EXTRACTING STOCK DATA

def get_historical_data(symbol, start_date):
    api_key = 'YOUR API KEY'
    api_url = f'https://api.twelvedata.com/time_series?symbol={symbol}&interval=1day&outputsize=5000&apikey={api_key}'
    raw_df = requests.get(api_url).json()
    df = pd.DataFrame(raw_df['values']).iloc[::-1].set_index('datetime').astype(float)
    df = df[df.index >= start_date]
    df.index = pd.to_datetime(df.index)
    return df

intc = get_historical_data('INTC', '2020-01-01')
intc.tail()


Output:



Code Explanation: The first thing we did is to define a function named ‘get_historical_data’ that takes the stock’s symbol (‘symbol’) and the starting date of the historical data (‘start_date’) as parameters. Inside the function, we are defining the API key and the URL and stored them into their respective variable. Next, we are extracting the historical data in JSON format using the ‘get’ function and stored it into the ‘raw_df’ variable. After doing some processes to clean and format the raw JSON data, we are returning it in the form of a clean Pandas dataframe. Finally, we are calling the created function to pull the historic data of Intel from the starting of 2020 and stored it into the ‘intc’ variable.


Step-3: Keltner Channel Calculation


In this step, we are going to calculate the components of the Keltner Channel indicator by following the methods we discussed before.


Python Implementation:



# KELTNER CHANNEL CALCULATION

def get_kc(high, low, close, kc_lookback, multiplier, atr_lookback):
    tr1 = pd.DataFrame(high - low)
    tr2 = pd.DataFrame(abs(high - close.shift()))
    tr3 = pd.DataFrame(abs(low - close.shift()))
    frames = [tr1, tr2, tr3]
    tr = pd.concat(frames, axis = 1, join = 'inner').max(axis = 1)
    atr = tr.ewm(alpha = 1/atr_lookback).mean()
    
    kc_middle = close.ewm(kc_lookback).mean()
    kc_upper = close.ewm(kc_lookback).mean() + multiplier * atr
    kc_lower = close.ewm(kc_lookback).mean() - multiplier * atr
    
    return kc_middle, kc_upper, kc_lower
    
intc = intc.iloc[:,:4]
intc['kc_middle'], intc['kc_upper'], intc['kc_lower'] = get_kc(intc['high'], intc['low'], intc['close'], 20, 2, 10)
intc.tail()


Output:



Code Explanation: We are first defining a function named ‘get_kc’ that takes a stock’s high (‘high’), low (‘low’), and closing price data (‘close’), the lookback period for the Keltner Channel (‘kc_lookback’), the multiplier value (‘multiplier), and the lookback period for the ATR (‘atr_lookback’) as parameters. The code inside the function can be separated into two parts: ATR calculation, and the Keltner Channel calculation.


ATR calculation: To determine the readings of the Average True Range, we are first calculating the three differences and stored them into their respective variables. Then we are combining all three differences into one dataframe using the ‘concat’ function and took the maximum values out of the three collective differences to determine the True Range. Then, using the ‘ewm’ and ‘mean’ functions, we are taking the customized Moving Average of True Range for a specified number of periods to get the ATR values.


Keltner Channel calculation: Utilizing the previously calculated ATR values, we are first calculating the middle line of the Keltner Channel by taking the EMA of ATR for a specified number of periods. Then comes the calculation of both the upper and lower bands. We are substituting the ATR values into the upper and lower bands formula we discussed before to get the readings of each of them. Finally, we are returning and calling the created function to get the Keltner Channel values of Intel.


Step-4: Creating the trading strategy


In this step, we are going to implement the discussed Keltner Channel indicator breakout trading strategy in python.


Python Implementation:



# KELTNER CHANNEL STRATEGY

def implement_kc_strategy(prices, kc_upper, kc_lower):
    buy_price = []
    sell_price = []
    kc_signal = []
    signal = 0
    
    for i in range(len(prices)):
        if prices[i] < kc_lower[i] and prices[i+1] > prices[i]:
            if signal != 1:
                buy_price.append(prices[i])
                sell_price.append(np.nan)
                signal = 1
                kc_signal.append(signal)
            else:
                buy_price.append(np.nan)
                sell_price.append(np.nan)
                kc_signal.append(0)
        elif prices[i] > kc_upper[i] and prices[i+1] < prices[i]:
            if signal != -1:
                buy_price.append(np.nan)
                sell_price.append(prices[i])
                signal = -1
                kc_signal.append(signal)
            else:
                buy_price.append(np.nan)
                sell_price.append(np.nan)
                kc_signal.append(0)
        else:
            buy_price.append(np.nan)
            sell_price.append(np.nan)
            kc_signal.append(0)
            
    return buy_price, sell_price, kc_signal

buy_price, sell_price, kc_signal = implement_kc_strategy(intc['close'], intc['kc_upper'], intc['kc_lower'])


Code Explanation: First, we are defining a function named ‘implement_kc_strategy’ which takes the stock prices (‘prices’), and the components of the Keltner Channel indicator (‘kc_upper’, and ‘kc_lower’) as parameters.


Inside the function, we are creating three empty lists (buy_price, sell_price, and kc_signal) in which the values will be appended while creating the trading strategy.