Pairs Trading Issues

[This article was first published on Eran Raviv » R, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

A few words for those of you who are not familiar with the “pairs trading” concept. First you should understand that the movement of every stock is dominated not by the companies performance but by the general market movement. This is the origin of many “factor models”, the factor that drives the every stock is the market factor, which is approximated by the S&P index in most cases. So, no matter how great a company I think amazon (AMZN) is, it will not stand any large market downturn without getting chopped itself. What a conservative player (not to say coward..) such as myself might do is to “net out” this factor from the equation. I can long AMZN and short another company or the index itself in the right amount so that I have exposure “only” to the intrinsic AMZN movement. Say I did just that, bought AMZN and sold the S&P index (SPY) , if the index goes up, I am losing since I am shorting it, but I hope AMZN will go up to overcompensate me on my loss from the index. AMZN should go up once since the market went up, and once since its a good company. The reverse, the index goes down, so I win on that one since I short the index, I hope AMZN will not decline as much to eat all my profits. AMZN should decline because of the market, but go up since it’s a good company. That way, I express my views about AMZN without taking on the factor/market exposure. The term “pairs trade” is since I am long and short a pair of stocks. That was a flat explanation about what is pairs trading. It suits me just fine, I can volume up without the horrific P&L swings I used to endure when I was more stupid. I found many pairs that should co-move and went shopping with the revenues no doubt were soon to flow in. Imagine my surprise when things did not go my way, :) . Take the following pair, gold (GLD) and gold miners (GDX), a text book example (see references) for a pair that “goes together”. Basically, when price of gold is going up (GLD is up), gold miners should benefit, so GDX should also rise. Take a look:

GLD and GDX Co-movement

You can see the two ETF’s follow closely. This plots is basically what you get from google finance, they were scaled to show returns with respect to some date. Now, the plan is to long one and short the other when they drift too far apart. What’s the problem then? The bottom right plot shows the GLD has been performing much better than GDX over the last year, (252 trading days). I want to short GLD and to long GDX and to sit on it until convergence. How much should I long and how much should I short? one to one? surely wrong as the price of GDX is 52.68 and the price of GLD is 155.23. Maybe equate the amount of stocks so that I am long and short  exactly 10000 dollar in each ETF, so long 188 GDX and short 64 GLD. However, is it the case that 1% increase in one is followed by 1% in the other? Thing is, if GLD rises 1% and GDX rises 1.5% as a result, then I need to hold 1.5 times GLD to keep my spread constant, this is important. As an example, say I hold same value, short GLD 10000 and long GDX 10000, but the relation between these two is such that when GDX rises 1% GLD rises 1.5%. What happens to my P&L when they co-move upwards? I am at a loss of 0.5%, since I am short GLD which went up more than GDX… What people are doing to solve this is to estimate the relation between the two components. They do that using the regression: $$stock_a = \beta_0+\beta_1 stock_b+error$$ \( \widehat{\beta_1} \) is then the amount I need from \(stock_a \) to compensate on the move of \(stock_b \). Great, we should be up and running soon.  This approach, despite its appeal is far from “tried and true”. Firstly, should we use returns or actual prices? Academy likes the former, practitioners, the latter. It’s not the same in case you were wondering: Prices or Returns for beta estimation?The upper plot is the estimation based on prices, it shows I should long 1.82 GLD for every 1 GDX.The bottom plot shows the same estimation based on returns, here I should hold twice GDX since every percent in GDX followed on average by only 0.433% in GLD. What’s more, the aforementioned regression is infected with the underlying assumption that the right hand side variable is constant while the left hand side variable is random, it has an error term. In fact, \(stock_b \) is also random, so when we switch the variables in the regression, plugging GDX on the “Y” side we get different results: What should be on the RHS and what on the LHS?This is disturbing, the amount I should trade is determined by the order in which I plug in the variables?? Does not sound like a money machine to me. Remember, I do not care that GLD is the one dragging GDX, (gold is dragging gold miners and not the reverse), all I am saying is that GLD is not a given constant, but a random variable in its own right. To make matters more interesting, \( \widehat{\beta_1} \) is not constant over time, so I have no idea how many observation to use.Have a look: Changes in Beta over TimeThis is of course the case for returns as well, and if you reverse the order of the LHS and RHS variables. You can copy paste the code and try it yourself, it’s pretty much a stand alone code. Possible solutions are to think about your time horizon for investment, so for example if you plan to hold if for few months you can use the 365 days beta. I also tried to weight the observations such that the most recent get more weight and such other variations, did not reach any satisfactory condition to determine as to how much I should hold from each. In theory, there is a strong relation between theory and practice, but in practice there is not. I showed here few the problems in pairs trading. Firstly, we do not know which measure to use for relation estimation, prices or returns. Secondly, we do not know which time frame to use and since the relation is not constant, it does matter.Lastly, the assumptions underlying the estimation procedure are false and invalidate whatever you hoped to feel comfortable with. As always, code and references are given below. Thanks for reading.  
Quantitative Trading: How to Build Your Own Algorithmic Trading Business (Wiley Trading) (Hardcover) by Ernie Chan Price: $37.42 47 used & new available from $31.62 3.4 out of 5 stars (18 customer reviews)
When Genius Failed: The Rise and Fall of Long-Term Capital Management (Paperback) by Roger Lowenstein Price: $10.88 182 used & new available from $2.92 4.5 out of 5 stars (253 customer reviews)
Applied Quantitative Methods for Trading and Investment (The Wiley Finance Series) (Hardcover) by Price: $105.26 30 used & new available from $60.00 3.8 out of 5 stars (4 customer reviews)
Pairs Trading: Quantitative Methods and Analysis (Wiley Finance) (Hardcover) by Ganapathy Vidyamurthy Price: $74.75 39 used & new available from $57.97 3.8 out of 5 stars (16 customer reviews)
R code:
?Download download.txt

tckr<-c("GLD", "GDX")
seq1 = c(30,90,180,365)
end<-format(Sys.Date() ,"%Y-%m-%d")
Tickers = array(dim =c(260,4,2) )
Tickersret = array(dim =c(260,4,2) )
for (j in 1:2){
for (i in seq1){
ind =  match(i,seq1)
start[ind] <-format(Sys.Date() - (i) ,"%Y-%m-%d")
dat0 = (getSymbols(tckr[j], src="yahoo", from=start[ind], to=end, auto.assign = FALSE))
ret = (as.vector(dat0[2:NROW(dat0),4]) - as.vector(dat0[1:(NROW(dat0)-1),4]) )/ dat0[1:(NROW(dat0)-1),4]
Tickers[1:(NROW(dat0)),ind,j] =  as.numeric( (dat0[,4]+dat0[,1]+(dat0[,2] + dat0[,3])/2)/3 ) # average price
Tickersret[1:(NROW(dat0)-1),ind,j] = as.numeric(ret)
## Plot of prices:
par(mfrow = c(2,2))
for (i in 1:4){
plot(na.omit(Tickers[,i,1])/na.omit(Tickers[1,i,1]) , ty = "b", ylim = c(.65,1.35),
 main = paste('Last', seq1[i], 'days'), ylab = "Return", xlab = "Time")
points(na.omit(Tickers[,i,2])/na.omit(Tickers[1,i,2]), ty = "b", col = 2)
legend('topright',legend = c(paste(tckr[1]), paste(tckr[2])), bty = "n", col = c(1:2), pch = 1)
## Plot of Beta return vs prices:
i = 4
par(mfrow = c(2,1))
plot(na.omit(Tickers[,i,2]) ~ na.omit(Tickers[,i,1]), ty = "p", main =
  paste('Beta for the last', seq1[i], 'days',
"=", format(as.numeric(lm(na.omit(Tickers[,i,2]) ~ na.omit(Tickers[,i,1]))$coef[2]),digits = 3) )
, ylab = paste(tckr[2]), xlab = paste(tckr[1]) )
abline(lm(na.omit(Tickers[,i,2]) ~ na.omit(Tickers[,i,1])  ), col = 2, lwd = 3)

plot(na.omit(Tickersret[,i,2]) ~ na.omit(Tickersret[,i,1]), ty = "p", main =
  paste('Beta for the last', seq1[i], 'days',
"=", format(as.numeric(lm(na.omit(Tickersret[,i,2]) ~ na.omit(Tickersret[,i,1]))$coef[2]),digits = 3) )
, ylab = paste(tckr[2]), xlab = paste(tckr[1]) )
abline(lm(na.omit(Tickersret[,i,2]) ~ na.omit(Tickersret[,i,1])  ), col = 2, lwd = 3)

## Plots of beta over time:
par(mfrow = c(2,2))
for (i in 1:4){
plot(na.omit(Tickers[,i,1]) ~ na.omit(Tickers[,i,2]), ty = "p", main =
  paste('Beta for the last', seq1[i], 'days',
"=", format(as.numeric(lm(na.omit(Tickers[,i,1]) ~ na.omit(Tickers[,i,2]))$coef[2]),digits = 3) )
, ylab = paste(tckr[1]), xlab = paste(tckr[2]) )
abline(lm(na.omit(Tickers[,i,1]) ~ na.omit(Tickers[,i,2])  ), col = 2, lwd = 3)

To leave a comment for the author, please follow the link and comment on their blog: Eran Raviv » R. 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.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)