CodeX
Published in

CodeX

Algorithmic Trading with Stochastic Oscillator in Python

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

Photo by Chris Liverani on Unsplash

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.

Before moving on, if you want to backtest your trading strategies without any coding, there is a solution for it. It is BacktestZone. It is a platform to backtest any number of trading strategies on different types of tradeable assets for free without coding. You can use the tool right away using the link here: https://www.backtestzone.com/

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 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 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:

Image by Author

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:

Image by Author

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:

Image by Author

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 = 1)
ax1.plot(nflx['Close'], color = 'skyblue', label = 'NFLX')
ax1.plot(nflx.index, buy_price, marker = '^', color = 'green', markersize = 10, label = 'BUY SIGNAL', linewidth = 0)
ax1.plot(nflx.index, sell_price, marker = 'v', color = 'r', markersize = 10, label = 'SELL SIGNAL', linewidth = 0)
ax1.legend(loc = 'upper left')
ax1.set_title('NFLX STOCK PRICE')
ax2.plot(nflx['%k'], color = 'deepskyblue', linewidth = 1.5, label = '%K')
ax2.plot(nflx['%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('NFLX STOCH')
ax2.legend()
plt.show()

Output:

Image by Author

Code Explanation: We are plotting the Stochastic Oscillator components along with the buy and sell signals generated by the trading strategy. We can observe that whenever both the %K and %D line crosses below the lower band and the %K line crosses below the %D line, a green-colored buy signal is plotted in the chart. Similarly, whenever both the %K and %D line crosses above the upper band and the %K line crosses above the %D line, a red-colored sell signal is plotted in the chart.

Step-7: Creating our Position

In this step, we are going to create a list that indicates 1 if we hold the stock or 0 if we don’t own or hold the stock.

Python Implementation:

position = []
for i in range(len(stoch_signal)):
if stoch_signal[i] > 1:
position.append(0)
else:
position.append(1)

for i in range(len(nflx['Close'])):
if stoch_signal[i] == 1:
position[i] = 1
elif stoch_signal[i] == -1:
position[i] = 0
else:
position[i] = position[i-1]

k = nflx['%k']
d = nflx['%d']
close_price = nflx['Close']
stoch_signal = pd.DataFrame(stoch_signal).rename(columns = {0:'stoch_signal'}).set_index(nflx.index)
position = pd.DataFrame(position).rename(columns = {0:'stoch_position'}).set_index(nflx.index)

frames = [close_price, k, d, stoch_signal, position]
strategy = pd.concat(frames, join = 'inner', axis = 1)

strategy.tail()

Output:

Image by Author

Code Explanation: First, we are creating an empty list named ‘position’. We are passing two for-loops, one is to generate values for the ‘position’ list to just match the length of the ‘signal’ list. The other for-loop is the one we are using to generate actual position values. Inside the second for-loop, we are iterating over the values of the ‘signal’ list, and the values of the ‘position’ list get appended concerning which condition gets satisfied. The value of the position remains 1 if we hold the stock or remains 0 if we sold or don’t own the stock. Finally, we are doing some data manipulations to combine all the created lists into one dataframe.

From the output being shown, we can see that in the first row our position in the stock has remained 0 (since there isn’t any change in the Stochastic Oscillator signal) but our position suddenly turned to 1 as we bought the stock when the Stochastic Oscillator trading signal represents a buy signal (1). Our position will remain 1 until some changes in the trading signal occur. Now it’s time to do implement some backtesting process!

Step-8: Backtesting

Before moving on, it is essential to know what backtesting is. Backtesting is the process of seeing how well our trading strategy has performed on the given stock data. In our case, we are going to implement a backtesting process for our Stochastic Oscillator trading strategy over the Netflix stock data.

Python Implementation:

nflx_ret = pd.DataFrame(np.diff(nflx['Close'])).rename(columns = {0:'returns'})
stoch_strategy_ret = []

for i in range(len(nflx_ret)):
try:
returns = nflx_ret['returns'][i]*strategy['stoch_position'][i]
stoch_strategy_ret.append(returns)
except:
pass

stoch_strategy_ret_df = pd.DataFrame(stoch_strategy_ret).rename(columns = {0:'stoch_returns'})

investment_value = 100000
number_of_stocks = floor(investment_value/nflx['Close'][-1])
stoch_investment_ret = []

for i in range(len(stoch_strategy_ret_df['stoch_returns'])):
returns = number_of_stocks*stoch_strategy_ret_df['stoch_returns'][i]
stoch_investment_ret.append(returns)

stoch_investment_ret_df = pd.DataFrame(stoch_investment_ret).rename(columns = {0:'investment_returns'})
total_investment_ret = round(sum(stoch_investment_ret_df['investment_returns']), 2)
profit_percentage = floor((total_investment_ret/investment_value)*100)
print(cl('Profit gained from the STOCH strategy by investing $100k in NFLX : {}'.format(total_investment_ret), attrs = ['bold']))
print(cl('Profit percentage of the STOCH strategy : {}%'.format(profit_percentage), attrs = ['bold']))

Output:

Profit gained from the STOCH strategy by investing $100k in NFLX : 45001.44
Profit percentage of the STOCH strategy : 45%

Code Explanation: First, we are calculating the returns of the Netflix stock using the ‘diff’ function provided by the NumPy package and we have stored it as a dataframe into the ‘nflx_ret’ variable. Next, we are passing a for-loop to iterate over the values of the ‘nflx_ret’ variable to calculate the returns we gained from our Stochastic Oscillator trading strategy, and these returns values are appended to the ‘stoch_strategy_ret’ list. Next, we are converting the ‘stoch_strategy_ret’ list into a dataframe and stored it into the ‘stoch_strategy_ret_df’ variable.

Next comes the backtesting process. We are going to backtest our strategy by investing a hundred thousand USD into our trading strategy. So first, we are storing the amount of investment into the ‘investment_value’ variable. After that, we are calculating the number of Netflix stocks we can buy using the investment amount. You can notice that I’ve used the ‘floor’ function provided by the Math package because, while dividing the investment amount by the closing price of Netflix stock, it spits out an output with decimal numbers. The number of stocks should be an integer but not a decimal number. Using the ‘floor’ function, we can cut out the decimals. Remember that the ‘floor’ function is way more complex than the ‘round’ function. Then, we are passing a for-loop to find the investment returns followed by some data manipulations tasks.

Finally, we are printing the total return we got by investing a hundred thousand into our trading strategy and it is revealed that we have made an approximate profit of forty thousand USD in one year. That’s not bad! Now, let’s compare our returns with SPY ETF (an ETF designed to track the S&P 500 stock market index) returns.

Step-9: SPY ETF Comparison

This step is optional but it is highly recommended as we can get an idea of how well our trading strategy performs against a benchmark (SPY ETF). In this step, we are going to extract the data of the SPY ETF using the ‘get_historical_data’ function we created and compare the returns we get from the SPY ETF with our Stochastic Oscillator strategy returns on Netflix.

Python Implementation:

def get_benchmark(start_date, investment_value):
spy = get_historical_data('SPY', start_date)['Close']
benchmark = pd.DataFrame(np.diff(spy)).rename(columns = {0:'benchmark_returns'})

investment_value = investment_value
number_of_stocks = floor(investment_value/spy[-1])
benchmark_investment_ret = []

for i in range(len(benchmark['benchmark_returns'])):
returns = number_of_stocks*benchmark['benchmark_returns'][i]
benchmark_investment_ret.append(returns)

benchmark_investment_ret_df = pd.DataFrame(benchmark_investment_ret).rename(columns = {0:'investment_returns'})
return benchmark_investment_ret_df

benchmark = get_benchmark('2020-01-01', 100000)
investment_value = 100000
total_benchmark_investment_ret = round(sum(benchmark['investment_returns']), 2)
benchmark_profit_percentage = floor((total_benchmark_investment_ret/investment_value)*100)
print(cl('Benchmark profit by investing $100k : {}'.format(total_benchmark_investment_ret), attrs = ['bold']))
print(cl('Benchmark Profit percentage : {}%'.format(benchmark_profit_percentage), attrs = ['bold']))
print(cl('STOCH Strategy profit is {}% higher than the Benchmark Profit'.format(profit_percentage - benchmark_profit_percentage), attrs = ['bold']))

Output:

Benchmark profit by investing $100k : 21780.0
Benchmark Profit percentage : 21%
STOCH Strategy profit is 24% higher than the Benchmark Profit

Code Explanation: The code used in this step is almost similar to the one used in the previous backtesting step but, instead of investing in Netflix, we are investing in SPY ETF by not implementing any trading strategies. From the output, we can see that our Stochastic Oscillator trading strategy has outperformed the SPY ETF by 24%. That’s great!

Final Thoughts!

After a long process of both theory and coding parts, we finally built a Stochastic Oscillator trading strategy in python. I cannot assure that this specific strategy we built performs well in the real world market but you can expect exceptional results by following the two most important steps:

  • Strategy Tuning: Stochastic Oscillator is one such indicator that tends to reveal false signals several times. If you implement a Stochastic Oscillator trading strategy without making any tweaks to it, then the probability to face some catastrophic results is huge. How can you tune a Stochastic Oscillator strategy? The most recommended step to tune the strategy is to add an additional technical indicator. This additional indicator will act as a validatory indicator to the strategy and will help in revealing authentic trade entries and exits. We didn't cover this part as the sole purpose of this article is to just explore the Stochastic Oscillator but not to make any profitable trades using the indicator.
  • Picking Stocks: In this article, we didn't take any steps to pick stocks with specific factors instead we just went randomly and that isn't a good approach while entering into the real world market. There are a bunch of steps to pick stocks for trading purposes and ensure that you implemented one of those steps to pick the right stocks for you. This step is of paramount importance and a must-know one because you might face negative trades even though you have a wonderful trading strategy but didn't implement it in the right stock.

That’s it! If you forgot to follow any of the coding parts, don't worry. I’ve provided the full source code at the end of this article. Hope you learned something useful from this article.

Full code:

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')

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.head()

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()

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'])

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'])

ax1 = plt.subplot2grid((9, 1), (0,0), rowspan = 5, colspan = 1)
ax2 = plt.subplot2grid((9, 1), (6,0), rowspan = 3, colspan = 1)
ax1.plot(nflx['Close'], color = 'skyblue', label = 'NFLX')
ax1.plot(nflx.index, buy_price, marker = '^', color = 'green', markersize = 10, label = 'BUY SIGNAL', linewidth = 0)
ax1.plot(nflx.index, sell_price, marker = 'v', color = 'r', markersize = 10, label = 'SELL SIGNAL', linewidth = 0)
ax1.legend(loc = 'upper left')
ax1.set_title('NFLX STOCK PRICE')
ax2.plot(nflx['%k'], color = 'deepskyblue', linewidth = 1.5, label = '%K')
ax2.plot(nflx['%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('NFLX STOCH')
ax2.legend()
plt.show()

position = []
for i in range(len(stoch_signal)):
if stoch_signal[i] > 1:
position.append(0)
else:
position.append(1)

for i in range(len(nflx['Close'])):
if stoch_signal[i] == 1:
position[i] = 1
elif stoch_signal[i] == -1:
position[i] = 0
else:
position[i] = position[i-1]

k = nflx['%k']
d = nflx['%d']
close_price = nflx['Close']
stoch_signal = pd.DataFrame(stoch_signal).rename(columns = {0:'stoch_signal'}).set_index(nflx.index)
position = pd.DataFrame(position).rename(columns = {0:'stoch_position'}).set_index(nflx.index)

frames = [close_price, k, d, stoch_signal, position]
strategy = pd.concat(frames, join = 'inner', axis = 1)

strategy.tail()

nflx_ret = pd.DataFrame(np.diff(nflx['Close'])).rename(columns = {0:'returns'})
stoch_strategy_ret = []

for i in range(len(nflx_ret)):
try:
returns = nflx_ret['returns'][i]*strategy['stoch_position'][i]
stoch_strategy_ret.append(returns)
except:
pass

stoch_strategy_ret_df = pd.DataFrame(stoch_strategy_ret).rename(columns = {0:'stoch_returns'})

investment_value = 100000
number_of_stocks = floor(investment_value/nflx['Close'][-1])
stoch_investment_ret = []

for i in range(len(stoch_strategy_ret_df['stoch_returns'])):
returns = number_of_stocks*stoch_strategy_ret_df['stoch_returns'][i]
stoch_investment_ret.append(returns)

stoch_investment_ret_df = pd.DataFrame(stoch_investment_ret).rename(columns = {0:'investment_returns'})
total_investment_ret = round(sum(stoch_investment_ret_df['investment_returns']), 2)
profit_percentage = floor((total_investment_ret/investment_value)*100)
print(cl('Profit gained from the STOCH strategy by investing $100k in NFLX : {}'.format(total_investment_ret), attrs = ['bold']))
print(cl('Profit percentage of the STOCH strategy : {}%'.format(profit_percentage), attrs = ['bold']))

def get_benchmark(start_date, investment_value):
spy = get_historical_data('SPY', start_date)['Close']
benchmark = pd.DataFrame(np.diff(spy)).rename(columns = {0:'benchmark_returns'})

investment_value = investment_value
number_of_stocks = floor(investment_value/spy[-1])
benchmark_investment_ret = []

for i in range(len(benchmark['benchmark_returns'])):
returns = number_of_stocks*benchmark['benchmark_returns'][i]
benchmark_investment_ret.append(returns)

benchmark_investment_ret_df = pd.DataFrame(benchmark_investment_ret).rename(columns = {0:'investment_returns'})
return benchmark_investment_ret_df

benchmark = get_benchmark('2020-01-01', 100000)
investment_value = 100000
total_benchmark_investment_ret = round(sum(benchmark['investment_returns']), 2)
benchmark_profit_percentage = floor((total_benchmark_investment_ret/investment_value)*100)
print(cl('Benchmark profit by investing $100k : {}'.format(total_benchmark_investment_ret), attrs = ['bold']))
print(cl('Benchmark Profit percentage : {}%'.format(benchmark_profit_percentage), attrs = ['bold']))
print(cl('STOCH Strategy profit is {}% higher than the Benchmark Profit'.format(profit_percentage - benchmark_profit_percentage), attrs = ['bold']))

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Nikhil Adithyan

Nikhil Adithyan

Founder @CodeX (medium.com/codex), a medium publication connected with code and technology | Top Writer | Connect with me on LinkedIn: https://bit.ly/3yNuwCJ