Stock Seasonality in Python - A Tutorial

A Python script that evaluates seasonal investing

Stock Seasonality in Python - A Tutorial
Photo by David Clode / Unsplash

Normally I'd add this to my Python Tutorial page but sometimes these small scripts are better found (and indexed) by Google if they're in their own post. After writing my article on Seasonal Trading and Investing Strategies, I decided to port Eric's R code to Python.

While Eric's code in R is very compact, the Python version feels more expressive and easier to deduce. I spent an hour or so trying to figure out the various methods that were called from the PerformanceAnalytics library and the ROC function from the xts library. As a machine learning guy, ROC means something completely different than the xts library method.

mport pandas as pd
import numpy as np
import yfinance as yf
import matplotlib.pyplot as plt
import datetime as dt

# Get the stock ticker
tickers ='NVDA'

# Set the start date, ending date is today
end =

# Download stock data,start,end) #['Adj Close']

# Renaming to humane column names
assets.rename(columns={'Adj Close': 'Adj_Close'}, inplace=True)

# Checking what the data looks like

# Compute daily returns using pandas pct_change()
assets['daily_returns'] = assets['Adj_Close'].pct_change()

# Skip first row with NA 
#assets = assets['daily_returns'][1:]
assets = assets[1:]

# Do a plot to check time series

# Break time series into first and second half of the year

first_half = assets[assets.index.month.isin([1,2,3,4,11,12])]
second_half = assets[assets.index.month.isin([5,6,7,8,9,10])]

# Check first half data

# Calculate the cumulative daily returns for first half of year
first_half['FH_Culm_Return'] = (1 + first_half['daily_returns']).cumprod() - 1

# Plot first half data transform for sanity check

# Calculate the cumulative daily returns for second half of year
second_half['SH_Culm_Return'] = (1 + second_half['daily_returns']).cumprod() - 1

# Plot first half data transform for sanity check

# Prepare series for concatentation
s1 = first_half['FH_Culm_Return']
s2 = second_half['SH_Culm_Return']

# Fill NaN with last value
s1.fillna(method='ffill', inplace=True)
s2.fillna(method='ffill', inplace=True)

# Concat series together and set to out df
out = pd.concat([s1, s2], axis=1)

# Fill NaN with last value
out.fillna(method ='ffill', inplace=True)

# This step is optional, you can resample to 1 month or leave as-is
#out = out.resample('1M').asfreq().ffill()

# Plot the final results of the two series. 
plt.title(tickers+" Seasonal Performance")
plt.ylabel('Culmulative Perf')
plt.plot(out.FH_Culm_Return, color = "black", label='Nov-Apr')
plt.plot(out.SH_Culm_Return, color = "red", label='May-Oct')

I did spend time on Stackoverflow piecing together some data munging requirements. While you can do anything in Python, R's handling of data was a bit more elegant. Still, I prefer Python over R any day.

This is what the MSFT looks like from the year 2000 on in R.

MSFT Seasonality Investing in R code, (c)

And this is what MSFT looks like from the year 2000 in Python.

MSFT Seasonality Investing in Python code, (c)

Granted I need to add the drawdown and the daily return part to the Python code, but the hard nut has been cracked.

Read more Python tutorials

Python Tutorials
A comprehensive list of my Python Tutorials for SEO, plain work, and other fun stuff.