S&P500 Seasonal Study + Other Commodities

We study to see if there is seasonality to the S&P500. We perform the procedure below on data from 1928 to present day (10.11.2017)

1. Calculate daily spread of closing prices
2. Group daily spread by month
3. Calculate mean of each month

We simply compute the spread of the the close to close values. We do not use the % returns here, simply close – close for every day in the series.

Next we group all days by their month. We then compute the mean for each grouped month.

The results for the S&P500 are below:

Rplot126

Rplot127

The old adage… ‘Sell In May And Go Away!’ seems to be true.

Other ETF’s:

Rplot134

DIA follows mostly the same seasonal pattern to the S&P500.

Rplot130

The best months for Crude Oil seem to be from Feb through June.

Rplot135

Natural Gas has its worst months in July and August.

Rplot131

Best months for Gold look to be Jan/Feb and August.

Rplot132

 

Silver follows a similar seasonal pattern to Gold.

Commodities tend to exhibit seasonal supply and demand flutuations which are consistently shown in the mean plots above and with a bit of googling may be explained.

In another post we will test for seasonal strategies which will attempt to exploit the above seasonal trends.

Full R Code below:

# S&P500 Seasonal Study 
# Calculate daily price spreads
# Group by month 
# Average each monthly group 

require(lubridate)
require(dplyr)
require(magrittr)
require(TTR)
require(zoo)
require(data.table)
require(xts)
require(ggplot2)
require(ggthemes)

# Data path
data.dir <- "C:/Stock Market Analysis/Market Data/MASTER_DATA_DUMP"
data.read.spx <- paste(data.dir,"$SPX.csv",sep="/")

# Read data
read.spx <- read.csv(data.read.spx,header=TRUE, sep=",",skip=0,stringsAsFactors=FALSE)

# Convert Values To Numeric 
cols <-c(3:8)
read.spx[,cols] %<>% lapply(function(x) as.numeric(as.character(x)))

# Convert Date Column [1] to Date format 
read.spx$Date <- ymd(read.spx$Date)

# Subset Date
#read.spx <- subset(read.spx, Date >= as.Date("1960-01-01") ) 

# Compute daily price differences 
# We replicate NA 1 time in order to maintain correct positioning of differences
# Within the data frame
read.spx$close.diff <- c(rep(NA, 1), diff(read.spx$Close, lag = 1, differences = 1, arithmetic = TRUE, na.pad = TRUE))

# Group each daily difference by month
group <- read.spx %>% dplyr::mutate(mymonth = lubridate::month(Date)) %>% group_by(mymonth) 
read.spx <- data.frame(read.spx,group$mymonth)
read.spx <- arrange(read.spx,group.mymonth)

# Duplicate df
for.mean <- data.frame(read.spx)

# Perform mean
mean <- for.mean %<>%
  group_by(group.mymonth) %>%
  summarise(mean=mean(close.diff,na.rm = TRUE))

# Confidence
jan <- subset(read.spx, group.mymonth  == 1)
feb <- subset(read.spx, group.mymonth  == 2)
mar <- subset(read.spx, group.mymonth  == 3)
apr <- subset(read.spx, group.mymonth  == 4)
may <- subset(read.spx, group.mymonth  == 5)
jun <- subset(read.spx, group.mymonth  == 6)
jul <- subset(read.spx, group.mymonth  == 7)
aug <- subset(read.spx, group.mymonth  == 8)
sep <- subset(read.spx, group.mymonth  == 9)
oct <- subset(read.spx, group.mymonth  == 10)
nov <- subset(read.spx, group.mymonth  == 11)
dec <- subset(read.spx, group.mymonth  == 12)
jan.t.test <- t.test(jan$close.diff, conf.level = 0.95,na.rm = TRUE)
jan.t.test$estimate

# Jan Plot 
hist(jan$close.diff,main="Jan Mean - Normal Distribution",xlab="Mean")

# Plot 
ggplot(mean, aes(group.mymonth, mean)) +
  geom_col()+
  theme_classic()+
  scale_x_continuous(breaks = seq(0, 12, by = 1))+
  ggtitle("UNG - Mean Daily Spead Per Month", subtitle = "2007 To Present") +
  labs(x="Month",y="Mean Daily Spread Per Month")+
  theme(plot.title = element_text(hjust=0.5),plot.subtitle =element_text(hjust=0.5))

ggplot(mean, aes(group.mymonth, mean)) +
  geom_line()+
  theme_bw() +
  scale_x_continuous(breaks = seq(0, 12, by = 1))+
  scale_y_continuous(breaks = seq(-0.15, 0.30, by = 0.02))+
  ggtitle("Mean Daily Spead Per Month", subtitle = "1928 To Present") +
  labs(x="Month",y="Mean Daily Spread Per Month")+
  theme(plot.title = element_text(hjust=0.5),plot.subtitle =element_text(hjust=0.5))+
  geom_rect(aes(xmin=4.5,xmax=9,ymin=-Inf,ymax=Inf),alpha=0.1,fill="#CC6666")+
  geom_rect(aes(xmin=1,xmax=4.5,ymin=-Inf,ymax=Inf),alpha=0.1,fill="#66CC99")+
  geom_rect(aes(xmin=9,xmax=12,ymin=-Inf,ymax=Inf),alpha=0.1,fill="#66CC99")

# Write output to file
write.csv(read.spx,file="C:/R Projects/seasonal.csv")


Author: Andrew Bannerman

Integrity Inspector. Quantitative Analysis is a favorite past time.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s