In a previous post, we discussed ideas generated by a Timely Portfolio post about Linear Models on Stock.

I wanted to see if there was a relationship between the window length of the running mean of the linear regression slope estimate and the running mean of the correlation between fitted and observed values.

The parameters are:

  • daily closing values since 2008 for the S&P 500
  • Linear Regression done on periods of 16 data points
  • If running mean of the last n slope coefficients is greater than 0, and running mean of correlation coefficients of fitted vs observed values is greater than 0.25, go long on the index
  • Otherwise, sit aside and wait

Vary n, and see how total return behaves (now that I think of it, I should want to change the size of the data points per linear regression). Results are below, and we have a peak at n = 5 days. The information captured by the linear model seems to be lost as n grows, since we don’t have better return than the index itself at large values of n.

It shouldn’t hard to change the different time period to test the same idea on various historical periods. Alternatively, one could parametrize how far in the past one wants to test this. Here’s the code, in R as usual. I will come back to this with improvements when I get bored.



require(ggplot2)
require(PerformanceAnalytics)
require(quantmod)

getSymbols("^GSPC",from="2008-01-01",to=Sys.Date())


#GSPC <- to.weekly(GSPC)[,4]
GSPC <- GSPC[,4]

width = 16
for (i in (width+1):NROW(GSPC)) {
        linmod <- lm(GSPC[((i-width):i),1]~index(GSPC[((i-width):i)]))
        ifelse(i==width+1,signal <- coredata(linmod$residuals[length(linmod$residuals)]),
                signal <- rbind(signal,coredata(linmod$residuals[length(linmod$residuals)])))
        ifelse(i==width+1,signal2 <- coredata(linmod$coefficients[2]),
                signal2 <- rbind(signal2,coredata(linmod$coefficients[2])))
        ifelse(i==width+1,signal3 <- cor(linmod$fitted.values,GSPC[((i-width):i),1]),
                signal3 <- rbind(signal3,cor(linmod$fitted.values,GSPC[((i-width):i),1])))
}
signal <- as.xts(signal,order.by=index(GSPC[(width+1):NROW(GSPC)]))
signal2 <- as.xts(signal2,order.by=index(GSPC[(width+1):NROW(GSPC)]))
signal3 <- as.xts(signal3,order.by=index(GSPC[(width+1):NROW(GSPC)]))

price_ret_signal <- merge(GSPC,lag(signal,k=1),
        lag(signal2,k=1),lag(signal3,k=1),
        ROC(GSPC,type="discrete",n=1))
price_ret_signal[,2] <- price_ret_signal[,2]/price_ret_signal[,1]
price_ret_signal[,3] <- price_ret_signal[,3]/price_ret_signal[,1]


getTotalReturn <- function(i) {
        p <- ifelse(runMean(price_ret_signal[,3],n=i) > 0 & runMean(price_ret_signal[,4],n=i) > 0.25, 1, 0)
        p <- 1+(na.omit(p * price_ret_signal[,5]))
        Reduce("*", coredata(p))
}
qplot(1:30, unlist(lapply(1:30, getTotalReturn)), geom="line", xlab="x", ylab="total return")