Studying market reactions after consecutive gains (losses)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Arthur Charpentier used R to denote a broken record of the CAC 40 when it went 11 consecutive days with negative returns.
Question: What happens to the market after runs of positive or negative returns? Will the market tank or soar after n days of gains/losses?
First, a little dissection of historical data (S&P 500 since 1980).
library(quantmod) getSymbols("^GSPC", from='1980-01-01') y <- diff(Cl(GSPC)) # looking at direction only y[y < 0] <- -1 y[y > 0] <- 1 r <- rle(as.vector(y)) # losses l <- r$lengths[which(r$values < 0)] # gains g <- r$lengths[which(r$values > 0)] plot(as.factor(l), col='red'); title('Consecutive losing days for the S&P 500 since 1980') plot(as.factor(g), col='green'); title('Consecutive gains for the S&P 500 since 1980') |
So the record of consecutive gains is 12 days in a row, and we have a record of 9 losses in a row for the S&P 500.
# given a run index from the r table, get the day associated with the start of that particular run getDayIndex <- function(i) { sum(r$lengths[1:i-1]) } # getLossRuns(9) will give you the dates (index) of the start of 9 consecutive losing streak getLossRuns <- function(i) { n <- length(r$lengths) l <- intersect(which(r$lengths == i), which(r$values < 0)) l <- l[l < n - i - 30] unlist(lapply(l, getDayIndex)) } getGainRuns <- function(i) { n <- length(r$lengths) l <- intersect(which(r$lengths == i), which(r$values > 0)) l <- l[l < n - i - 30] unlist(lapply(l, getDayIndex)) } |
Now, you can simply write:
> GSPC[getLossRuns(8)] GSPC.Open GSPC.High GSPC.Low GSPC.Close GSPC.Volume GSPC.Adjusted 1982-08-02 107.71 109.09 107.11 108.98 53460000 108.98 1991-08-28 393.06 396.64 393.05 396.64 169890000 396.64 1996-06-07 673.03 673.31 662.48 673.31 445710000 673.31 2008-09-30 1113.78 1168.03 1113.78 1166.36 4937680000 1166.36 > GSPC[getLossRuns(8) + 8 + 30] GSPC.Open GSPC.High GSPC.Low GSPC.Close GSPC.Volume GSPC.Adjusted 1982-09-24 123.79 123.80 123.11 123.32 54600000 123.32 1991-10-22 390.02 391.20 387.40 387.83 194160000 387.83 1996-08-01 639.95 650.66 639.49 650.02 439110000 650.02 2008-11-21 755.84 801.20 741.02 800.03 9495900000 800.03 |
to get the data on the start of 8-day losing streaks since 1980, and their data 30 days after the end of such streaks.
getAvgReturnsLoss <- function(i) { d2 <- as.vector(Cl(GSPC[getLossRuns(i) + i + 30])) d1 <- as.vector(Cl(GSPC[getLossRuns(i)])) (d2 - d1) / d1 } boxplot(lapply(1:9, getAvgReturnsLoss)) getAvgReturnsGain <- function(i) { d2 <- as.vector(Cl(GSPC[getGainRuns(i) + i + 30])) d1 <- as.vector(Cl(GSPC[getGainRuns(i)])) (d2 - d1) / d1 } boxplot(lapply(1:12, getAvgReturnsGain)) |
Each box in the boxplot represents the different returns after 30 days. For example, in the boxplot for returns after losing streak, the box labeled ’7′ represents the different returns of the S&P 500, 30 days following any run of 7 days with negative returns.
So far, this is just an exploration. One could determine whether the returns deviate significantly. One can also play with the number of days after the given run: analyze what happens to returns 15 days after such runs, etc. The amplitude of runs could also be considered in the analysis.
Photograph used with permission from mylittleshoebox.ca
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.