Algorithmic Trading with Stochastic Oscillator in Python

Learn to implement and backtest one of the most popular trading indicators with python



There are a bunch of technical indicators that can be considered for research and analysis but the one we are going to discuss today is one of the most popular indicators used among traders for trading purposes. It’s none other than the Stochastic Oscillator technical indicator. In this article, we will use python to create a Stochastic Oscillator-based trading strategy and backtest the strategy to see how well it performs in the real-world market. Additionally, we will also compare our trading results to the SPY ETF (an ETF specifically designed to track the S&P 500 market index) as a method to validate our strategy. Without further ado, let’s jump into the article.


Stochastic Oscillator


Stochastic Oscillator is a momentum-based leading indicator that is widely used to identify whether the market is in the state of overbought or oversold. This leads to our next question. What is overbought and oversold in a concerning market? A stock is said to be overbought when the market’s trend seems to be extremely bullish and bound to consolidate. Similarly, a stock reaches an oversold region when the market’s trend seems to be extremely bearish and has the tendency to bounce.


The values of the Stochastic Oscillator always lie between 0 to 100 due to its normalization function. The general overbought and oversold levels are considered as 80 and 20 respectively but it could vary from one person to another. The Stochastic Oscillator comprises two main components:

  • %K Line: This line is the most important and core component of the Stochastic Oscillator indicator. It is otherwise known as the Fast Stochastic indicator. The sole purpose of this line is to express the current state of the market (overbought or oversold). This line is calculated by subtracting the lowest price the stock has reached over a specified number of periods from the closing price of the stock and this difference is then divided by the value calculated by subtracting the lowest price the stock has reached over a specified number of periods from the highest stock price. The final value is arrived at by multiplying the value calculated from the above-mentioned steps by 100. The way to calculate the %K line with the most popular setting of 14 as the number of periods can be represented as follows:



%K = 100 * ((14 DAY CLOSING PRICE - 14 DAY LOWEST PRICE) - (14 DAY HIGHEST PRICE - 14 DAY LOWEST PRICE))


  • %D Line: Otherwise known as the Slow Stochastic Indicator, is nothing but the moving average of the %K line for a specified period. It is also known as the smooth version of the %K line as the line graph of the %D line will look smoother than the %K line. The standard setting of the %D line is 3 as the number of periods.

Now that we have an understanding of what the Stochastic Oscillator actually is. Let’s gain some intuitions about our trading strategy based on the indicator.


Stochastic Oscillator trading strategy: Our trading strategy will reveal a buy signal when:

  • The %K line is below 20

  • The %D line is below 20

  • The %K line is below %D line

Likewise, our strategy will reveal a sell signal when:

  • The %K line is above 80

  • The %D line is above 80

  • The %K line is above %D line

As you can see, three conditions must get satisfied to either reveal a buy signal or a sell signal. Our trading strategy can be represented as follows:



IF %K LINE < 20 AND %D LINE < 20 AND %K LINE < %D LINE => BUY
IF %K LINE > 80 AND %D LINE > 80 AND %K LINE > %D LINE => SELL


This concludes our theory part on the Stochastic Oscillator and our trading strategy. Let’s now code our trading strategy in python to see some exciting results. 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 Data from Alpha Vantage
3. Extracting the Stochastic Oscillator values
4. Stochastic Oscillator Plot
5. Creating the Trading Strategy
6. Plotting the Trading Lists
7. Creating our Position
8. Backtesting
9. 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:



import pandas as pd
import numpy as np
import requests
from termcolor import colored as cl
from math import floor
import matplotlib.pyplot as pltplt.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 Netflix 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 Netflix 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

nflx = get_historical_data('NFLX', '2020-01-01')
nflx


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 Netflix from the starting of 2020 and stored it into the ‘nflx’ variable.


Step-3: Extracting the Stochastic Oscillator values


In this step, we are going to pull the Stochastic Oscillator values of Netflix 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_stoch(symbol, k_period, d_period, start_date):
    api_key = open(r'api_key.txt')
    url = f'https://www.alphavantage.co/query?function=STOCH&symbol={symbol}&interval=daily&fastkperiod={k_period}&slowdperiod={d_period}&apikey={api_key}'
    raw = requests.get(url).json()
    df = pd.DataFrame(raw['Technical Analysis: STOCH']).T.iloc[::-1]
    df = df[df.index >= start_date]
    df.index = pd.to_datetime(df.index)
    df = df.astype(float)
    return df['SlowK'], df['SlowD']

nflx['%k'], nflx['%d'] = get_stoch('NFLX', 14, 3, '2020-01-01')
nflx = nflx.dropna()
nflx.head()


Output:



Code Explanation: Firstly, we are defining a function named ‘get_stoch’ which takes the stock’s symbol (‘symbol’), number of periods for the %K line (‘k_period’), number of periods for the %D line (‘d_period’), 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 both the %K values and %D values. Finally, we are calling the function to extract the Stochastic Oscillator values of Netflix.


Step-4: Stochastic Oscillator Plot


In this step, we are going to plot the extracted Stochastic Oscillator values of Netflix 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 Stochastic Oscillator.


Python Implementation:



def plot_stoch(symbol, price, k, d):
    ax1 = plt.subplot2grid((9, 1), (0,0), rowspan = 5, colspan = 1)
    ax2 = plt.subplot2grid((9, 1), (6,0), rowspan = 3, colspan = 1)
    ax1.plot(price)
    ax1.set_title(f'{symbol} STOCK PRICE')
    ax2.plot(k, color = 'deepskyblue', linewidth = 1.5, label = '%K')
    ax2.plot(d, color = 'orange', linewidth = 1.5, label = '%D')
    ax2.axhline(80, color = 'black', linewidth = 1, linestyle = '--')
    ax2.axhline(20, color = 'black', linewidth = 1, linestyle = '--')
    ax2.set_title(f'{symbol} STOCH')
    ax2.legend()
    plt.show()
    
plot_stoch('NFLX', nflx['Close'], nflx['%k'], nflx['%d'])


Output:



The plot is sub-divided into two panels: The upper panel and the lower panel. The upper panel represents the line plot of the closing price of Netflix. The lower panel comprises the components of the Stochastic Oscillator. Being a leading indicator, the stochastic oscillator cannot be plotted alongside the closing price 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). The components %K line and %D line we discussed before are plotted in blue and orange respectively. You can also notice two additional black dotted lines above and below the %K and %D line. It is an additional component of the Stochastic Oscillator known as Bands. These bands are used to highlight the region of overbought and oversold. If both the %K and %D line crosses above the upper band, then the stock is considered to be overbought. Likewise, when both the %K and %D line crosses below the lower band, the stock is considered to be oversold.


Step-5: Creating the trading strategy


In this step, we are going to implement the discussed Stochastic Oscillator trading strategy in python.


Python Implementation:



def implement_stoch_strategy(prices, k, d):    
    buy_price = []
    sell_price = []
    stoch_signal = []
    signal = 0

    for i in range(len(prices)):
        if k[i] < 20 and d[i] < 20 and k[i] < d[i]:
            if signal != 1:
                buy_price.append(prices[i])
                sell_price.append(np.nan)
                signal = 1
                stoch_signal.append(signal)
            else:
                buy_price.append(np.nan)
                sell_price.append(np.nan)
                stoch_signal.append(0)
        elif k[i] > 80 and d[i] > 80 and k[i] > d[i]:
            if signal != -1:
                buy_price.append(np.nan)
                sell_price.append(prices[i])
                signal = -1
                stoch_signal.append(signal)
            else:
                buy_price.append(np.nan)
                sell_price.append(np.nan)
                stoch_signal.append(0)
        else:
            buy_price.append(np.nan)
            sell_price.append(np.nan)
            stoch_signal.append(0)
            
    return buy_price, sell_price, stoch_signal
            
buy_price, sell_price, stoch_signal = implement_stoch_strategy(nflx['Close'], nflx['%k'], nflx['%d'])


Code Explanation: First, we are defining a function named ‘implement_stoch_strategy’ which takes the stock prices (‘price), and the %K (‘k’) and %D line value (‘d’) as parameters.


Inside the function, we are creating three empty lists (buy_price, sell_price, and stoch_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((9, 1), (0,0), rowspan = 5, colspan = 1)
ax2 = plt.subplot2grid((9, 1), (6,0), rowspan = 3, colspan =