I recently enrolled in the QuantInsti Executive Programme in Algorithmic Trading and one of the areas in quantitative finance that interests me greatly is the analysis of financial time series. During the course we will take on a massive project to build our own trading strategy with the help of a mentor, and in attempt to familiarize myself with the work, I built this simple strategy using the HoltWinters exponential smoothing.

I hope that others may find this useful. I learnt a great deal from writing the following blog post:

- Build an indicator to forcast a share 1 day into the future using the HoltWinters Exponential Smoothing method.
- Backtest the strategy and show performance metrics

### About HoltWinters exponential smoothing

“The Holt-Winters method was suggested by Holt (1957) and Winters (1960), who were working in the School of Industrial Administration at Carnegie Institute of Technology, and uses exponentially weighted moving averages to update estimates of the seasonally adjusted mean (called the level ), slope, and seasonals. The” (Introductory Time Series with R, By Paul S.P. Cowpertwait, Andrew V. Metcalfe)

### Getting Starterd

We will make use of the following packages

require ( quantmod ) require ( fArma ) require ( PerformanceAnalytics )

Get closing price data for the S&P500 from Yahoo Finance

getSymbols( "^GSPC", from="2000-01-01" ) ## [1] "GSPC" ClosingPrices = Cl(GSPC) head(ClosingPrices) ## GSPC.Close ## 2000-01-03 1455.22 ## 2000-01-04 1399.42 ## 2000-01-05 1402.11 ## 2000-01-06 1403.45 ## 2000-01-07 1441.47 ## 2000-01-10 1457.60

Set up the function to predict the returns one day forward and return 1 for a long and -1 for a short

HWPredictDaily = function(data){ #Check that there are enough data if(length(data) < 501){ return("Need at least 501 data points, days") } http://www.r-bloggers.com/arma-models-for-trading/ # Model the daily returns instead of the prices. There are multiples reasons: # 1. this way financial series usually becomes stationary, we need some way to "normalize" a series, etc. # 2. We use the diff and log function to compute the daily returns instead of percentages. # 3. Not only this is a standard practice in statistics, but it also provides a damn good approximation to the discrete returns. dailyReturns = diff( log( as.ts(data) ) ) #Format the data coming in as a time series timeSeries = ts(dailyReturns, frequency = 250) #Finding the Optimal Values #Automatically picks the model with the lowest SSE and returns the predicted value predictedValue <- as.numeric(predict( HoltWinters(timeSeries), n.ahead= 1)) #Set the trading signal to 1 if the predicted value is greater than 0 and -1 if not if(predictedValue >= 0){ answer = 1 return (answer) } else if (predictedValue < 0){ answer = -1 return (answer) } }

### Backtest

Generate a List of signals for the closing price data

#This is our result set signalList <- c() #Generate signals for the entire dataset, Returns a List for(i in 1:length(ClosingPrices)){ #Check that there are enough data points if(i > 501){ #counter to make sure we only optimise for 500 datapoints counter <- (i-500) #Generate signal signal <- HWPredictDaily(ClosingPrices[counter:i]) #Add signal to signalList signalList <-c(signalList, signal) } else { #Hold no position (signal = 0) signal <- 0 #Add signal to signalList signalList <-c(signalList, signal) } }

Calculate the Change in Price for the underlying Asset which is the S&P500 in this case

#Let the first element by a 0% price change due to there not being a price change on t = 0 underlyingReturns <- c(0) #Generate underlying assets daily returns. Returns a List for(i in 2:length(ClosingPrices)){ pctChange <- (as.numeric(ClosingPrices[i]) / as.numeric(ClosingPrices[i-1])) - 1 underlyingReturns <- c(underlyingReturns, pctChange) }

Next calculate the daily returns for our portfolio

#Let the first element by a 0% price change in equity because I cant trade on the first day #Due to lagging the indicator dailyReturns <- c(0) #Generate the equity curve, Returns a List for(i in 2:length(ClosingPrices)){ #Here we lag the signal returns by one day and multiply it by the underlyings daily return dayReturn <- as.numeric(signalList[i-1]) * as.numeric(underlyingReturns[i]) #Add to dailyReturns dailyReturns <- c(dailyReturns, dayReturn) }

Strategy Reporting

#Get the dates from the index of the S&P500 Closing Prices dates <- index(ClosingPrices) #Create an xts object to use in the reporting of the portfolio performance <- as.xts(dailyReturns, order.by = dates) performance <- setNames(performance, 'returns') #Total Returns Return.cumulative(performance) ## returns ## Cumulative Return 5.745615 #Equity curve, Daily returns, and Drawdowns charts.PerformanceSummary(performance)

#A table of the top 10 drawdowns table.Drawdowns(performance, top = 10) ## From Trough To Depth Length To Trough Recovery ## 1 2008-12-08 2009-04-15 2010-05-21 -0.3957 366 88 278 ## 2 2004-02-12 2008-02-07 2008-09-29 -0.2928 1166 1004 162 ## 3 2012-06-25 2013-09-19 2015-09-08 -0.2599 806 311 495 ## 4 2003-03-20 2003-04-23 2003-07-25 -0.1440 89 24 65 ## 5 2002-10-09 2003-01-24 2003-03-17 -0.1397 109 74 35 ## 6 2008-09-30 2008-10-06 2008-10-09 -0.1195 8 5 3 ## 7 2011-09-26 2011-11-03 2011-12-08 -0.1185 53 29 24 ## 8 2008-10-13 2008-10-13 2008-10-22 -0.1158 8 1 7 ## 9 2008-11-17 2008-11-19 2008-11-21 -0.0944 5 3 2 ## 10 2002-02-22 2002-03-07 2002-04-10 -0.0934 33 10 23

### To the Readers:

If you are looking to learn more, I recommend the following book: