Stock Trade Automation with Commodity Channel Index in Python

A step-by-step guide to making seamless stock trades by algorithmic trading with a powerful technical indicator in python



Introduction


With the increasing amount of technological inventions, the methods of stock trading have also evolved since then. When we look back to the distant past like the 1980s or even 1990s, Wall Street would look something like a ground to hustle among the traders. We could barely understand what’s going around and traders would yell and shout among themselves to buy a stock in an auction. Could you believe that stocks are bought in an auction? Thanks to the researchers and engineers who built and revolutionized the stock market division by introducing it to the world of technology.


Even though technologies like High-Frequency trading platforms were introduced over a period of time, we as humans considered primitive factors particularly emotions to influence in making trades which sometimes resulted in dramatic losses. To disguise these personal factors considered by traders, algorithmic trading was introduced. The concept was highly effective and much liked by traders. It is nothing but creating a bot to automate the process of trading stocks. This bot is created and held in control by the traders and will implement trades once the given technical conditions get satisfied. Just as an example, imagine you are creating a program to trade stocks. The condition you give to that bot is when the stock reaches a price below say $250, buy it, likewise, when the stock reaches a price above $400, sell it. This is just an example of how algorithmic trading works and actually, these types of conditions are not passed by traders given the level of efficiency.


Instead, they build their conditions or algorithms using a tool called technical indicators. There is a basket of technical indicators out there but in this article, we are going to discuss a special one called Commodity Channel Index, shortly known as CCI and how can it be implemented to trade stocks in python. Without further ado, let’s dive into the article.


Commodity Channel Index (CCI)


The CCI is a leading indicator that measures the difference between the current price and the historical average price over a specified period of time, i.e. when the value of CCI reveals extreme positive readings, then it is considered that the current price is well above the historical average. Likewise, when the value of CCI reveals extreme negative readings, then it is considered that the current price is below the historical average. By judging its name, people might think CCI is used to trade only commodities but that's not it. It can be used to trade in any form of market let it be equity or forex. The most general setting of CCI is 20 as the specified number of period. The formula to calculate CCI with 20 as the number of periods can be represented as follows:



CCI = (TP - SMA 20 OF TP) / (0.15 * MEAN DEVIATION)

where,
Typical Price (TP) = (HIGH + LOW + CLOSE) / 3
SMA 20 of TP = Typical Price / 20
Mean Deviation = Absolute values of Typical Price / 20


This indicator is unique from the rest of the leading indicators as many of the leading ones have values bound between 0 to 100 but CCI can reach extreme values acting as an unbounded oscillator. Since CCI has indefinite values, traders determine the overbought and oversold levels for individual assets by looking for extreme points of CCI where the price is reversed. For example, imagine the forex pair EURUSD (Euro/USD) which reaches an extreme CCI level of 150 and suddenly a change in trend occurs (price reversal), and hence our overbought level for EURUSD would be 150. Similarly, imagine the same pair has reached an extreme negative CCI level of -150 and suddenly a change in trend occurs, and thus our oversold level for EURUSD would -150. This way of determining overbought and oversold levels is called a Reversal Strategy.


About our trading strategy: Our trading strategy is going to be a Reversal strategy where we are going to analyze the CCI values of Facebook and determine the levels of overbought and oversold. The strategy will reveal a buy signal when the previous CCI value of Facebook is greater than the oversold level and the current CCI value is lesser than the oversold level. Likewise, the strategy will reveal a sell signal when the previous CCI value of Facebook is lesser than the overbought level and the current CCI value is greater than the overbought level. Our trading strategy can be represented as follows:



IF PREVIOUS CCI > OVERSOLD LEVEL AND CCI < COVERSOLD LEVEL = BUY
IF PREVIOUS CCI < OVERBOUGHT LEVEL AND CCI > COVERBOUGHT LEVEL = SELL


Now that we have an understanding of what CCI means and how can it be used to build a trading strategy. Let’s use Python to implement our own CCI-based trading strategy and backtest it to see how well it performs in the real-world market.


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.


Python Implementation


The coding part is classified into various steps as follows:



1. Importing Packages
2. Extracting Data from Alpha Vantage
3. Extracting the CCI values from Alpha Vantage
4. CCI Plot
5. Creating the Trading Strategy
6. Plotting the Trading Lists
7. Creating our Position
8. Backtesting


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:



import pandas as pd
import numpy as np
import requests
from termcolor import colored as cl
from math import floor
import matplotlib.pyplot as plt
plt.rcParams[‘figure.figsize’] = (20, 10)
plt.style.use(‘fivethirtyeight’)


Now that we have imported all the essential packages into our python environment. Let’s proceed with pulling the historical data of Facebook with Alpha Vantage’s powerful stock API.


Step-2: Extracting Data from Alpha Vantage


In this step, we are going to pull the historical data of Facebook using an API endpoint provided by Alpha Vantage. Before that, a note on Alpha Vantage: Alpha Vantage provides free stock APIs through which users can access a wide range of data like real-time updates, and historical data on equities, currencies, and cryptocurrencies. Make sure that you have an account on Alpha Vantage, only then, you will be able to access your secret API key (a crucial element for pulling data using an API).


Python Implementation:



def get_historical_data(symbol, start_date = None):
    api_key = open(r'api_key.txt')
    api_url = f'https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED&symbol={symbol}&apikey={api_key}&outputsize=full'
    raw_df = requests.get(api_url).json()
    df = pd.DataFrame(raw_df[f'Time Series (Daily)']).T
    df = df.rename(columns = {'1. open': 'open', '2. high': 'high', '3. low': 'low', '4. close': 'close', '5. adjusted close': 'adj close', '6. volume': 'volume'})
    for i in df.columns:
        df[i] = df[i].astype(float)
    df.index = pd.to_datetime(df.index)
    df = df.iloc[::-1].drop(['7. dividend amount', '8. split coefficient'], axis = 1)
    if start_date:
        df = df[df.index >= start_date]
    return df

fb = get_historical_data('FB', '2020-01-01').iloc[:,:4]
fb


Output:



Code Explanation: The first thing we did is to define a function named ‘get_historical_data’ that takes the stock’s symbol (‘symbol’) as a required parameter and the starting date of the historical data (‘start_date’) as an optional parameter. 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 Facebook from the starting of 2020 and stored it into the ‘fb’ variable.


Step-3: Extracting the CCI values


In this step, we are going to pull the Commodity Channel Index values of Facebook with the help of an API endpoint provided by Alpha Vantage. This step is almost similar to what we did in the previous step.


Python Implementation:



def get_cci(symbol, n, start_date):
    api_key = open(r'api_key.txt')
    url = f'https://www.alphavantage.co/query?function=CCI&symbol={symbol}&interval=daily&time_period={n}&apikey={api_key}'
    raw = requests.get(url).json()
    df = pd.DataFrame(raw['Technical Analysis: CCI']).T.iloc[::-1]
    df = df[df.index >= start_date]
    df.index = pd.to_datetime(df.index)
    df = df.astype(float)
    return df

fb['cci'] = get_cci('FB', 20, '2020-01-01')
fb = fb.dropna()
fb


Output:



Code Explanation: Firstly, we are defining a function named ‘get_cci’ which takes the stock’s symbol (‘symbol’), the number of periods for the CCI (‘n’), and the starting date of the data (‘start_date’) as parameters. Inside the function, we are first assigning two variables named ‘api_key’ and ‘url’ to store the API key and the API URL respectively. Using the ‘get’ function provided by the Requests package, we are calling the API and stored the response into the ‘raw’ variable. After doing some data manipulations, we are returning the CCI values. Finally, we are calling the function to extract the Commodity Channel Index values of Facebook.


Step-4: CCI Plot


In this step, we are going to plot the extracted Commodity Channel Index values of Facebook to make more sense out of it. The main aim of this part is not on the coding section but instead to observe the plot to gain a solid understanding of the Commodity Channel Index.


Python Implementation:



ax1 = plt.subplot2grid((10,1), (0,0), rowspan = 5, colspan = 1)
ax2 = plt.subplot2grid((10,1), (6,0), rowspan = 4, colspan = 1)
ax1.plot(fb['close'])
ax1.set_title('FACEBOOK SHARE PRICE')
ax2.plot(fb['cci'], color = 'orange')
ax2.set_title('FACEBOOK CCI 20')
ax2.axhline(150, linestyle = '--', linewidth = 1, color = 'black')
ax2.axhline(-150, linestyle = '--', linewidth = 1, color = 'black')
plt.show()


Output:



The above chart is divided into two panels: The above panel representing the closing prices of Facebook and the lower panel with the CCI values. Being a leading indicator, CCI cannot be plotted on the same panel where the closing price is plotted as the values of the indicator and the closing price vary a lot. So, it is plotted apart from the closing price (below the closing price in our case). As you can see, the values of CCI are so indefinite and reached extreme values at times. You could see two dotted lines above and below the CCI plot which is nothing but the overbought and oversold levels. It’s our choice to determine the band levels and in our case, we set the overbought level to 150 and the oversold level to -150, i.e. the stock is considered to be in the state of overbought when the CCI crosses above 150, and similarly, the market is considered to be in the state of oversold when the CCI goes below -150. We will be using these same levels to build our trading strategy.


Step-5: Creating the trading strategy


In this step, we are going to implement the discussed CCI trading strategy in python with the overbought and oversold levels as 150 and -150 respectively.


Python Implementation:



def implement_cci_strategy(prices, cci):
    buy_price = []
    sell_price = []
    cci_signal = []
    signal = 0
    
    lower_band = (-150)
    upper_band = 150
    
    for i in range(len(prices)):
        if cci[i-1] > lower_band and cci[i] < lower_band:
            if signal != 1:
                buy_price.append(prices[i])
                sell_price.append(np.nan)
                signal = 1
                cci_signal.append(signal)
            else:
                buy_price.append(np.nan)
                sell_price.append(np.nan)
                cci_signal.append(0)
                
        elif cci[i-1] < upper_band and cci[i] > upper_band:
            if signal != -1:
                buy_price.append(np.nan)
                sell_price.append(prices[i])
                signal = -1
                cci_signal.append(signal)
            else:
                buy_price.append(np.nan)
                sell_price.append(np.nan)
                cci_signal.append(0)
                
        else:
            buy_price.append(np.nan)
            sell_price.append(np.nan)
            cci_signal.append(0)
            
    return buy_price, sell_price, cci_signal

buy_price, sell_price, cci_signal = implement_cci_strategy(fb['close'], fb['cci'])


Code Explanation: First, we are defining a function named ‘implement_cci_strategy’ which takes the stock prices (‘price), and the CCI values (‘cci’) as parameters.


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


After that, we are implementing the trading strategy through a for-loop. Inside the for-loop, we are passing certain conditions, and if the conditions are satisfied, the respective values will be appended to the empty lists. If the condition to buy the stock gets satisfied, the buying price will be appended to the ‘buy_price’ list, and the signal value will be appended as 1 representing to buy the stock. Similarly, if the condition to sell the stock gets satisfied, the selling price will be appended to the ‘sell_price’ list, and the signal value will be appended as -1 representing to sell the stock.


Finally, we are returning the lists appended with values. Then, we are calling the created function and stored the values into their respective variables. The list doesn’t make any sense unless we plot the values. So, let’s plot the values of the created trading lists.


Step-6: Plotting the trading signals


In this step, we are going to plot the created trading lists to make sense out of them.


Python Implementation:



ax1 = plt.subplot2grid((10,1), (0,0), rowspan = 5, colspan = 1)
ax2 = plt.subplot2grid((10,1), (6,0), rowspan = 4, colspan = 1)
ax1.plot(fb['close'], color = 'skyblue', label = 'FB')
ax1.plot(fb.index, buy_price, marker = '^', markersize = 12, linewidth = 0, label = 'BUY SIGNAL', color = 'green')
ax1.plot(fb.index, sell_price, marker = 'v', markersize = 12, linewidth = 0, label = 'SELL SIGNAL', color = 'r')
ax1.set_title('FACEBOOK SHARE PRICE')
ax1.legend()
ax2.plot(fb['cci'], color = 'orange')
ax2.set_title('FACEBOOK CCI 20')
ax2.axhline(150, linestyle = '--', linewidth = 1, color = 'black')
ax2.axhline(-150, linestyle = '--',