Structural “Arbitrage”: a Working Long-History Backtest

[This article was first published on QuantStrat TradeR » 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.

For this post, I would like to give my sincere thanks to Mr. Helmuth Vollmeier, for providing the long history daily data of XIV. It is tremendously helpful. Also, I put arbitrage in quotations now, for reasons we’ll see in this post.

To begin, here’s a script I wrote to create this backtest.

require(downloader)
download("https://dl.dropboxusercontent.com/s/jk6der1s5lxtcfy/XIVlong.TXT",
         destfile="longXIV.txt")
XIV <- read.csv("longXIV.txt", header=TRUE, stringsAsFactors=FALSE)
head(XIV)
XIV <- xts(XIV[,2:5], order.by=as.Date(XIV$Date))
XIVrets <- Return.calculate(Cl(XIV))
getSymbols("TLT", from="1990-01-01")
TLTrets <- Return.calculate(Cl(TLT))
adTltRets <- Return.calculate(Ad(TLT))
both <- merge(XIVrets, TLTrets, join='inner')
bothAd <- merge(XIVrets, adTltRets, join='inner')
stratTest <- Return.rebalancing(both, weights=c(.4, 1.8),
                                rebalance_on="weeks", geometric=FALSE)
adStratTest <- Return.rebalancing(bothAd, weights=c(.4, 1.8),
                                  rebalance_on="weeks", geometric=FALSE)
bothStrats <- merge(stratTest, adStratTest)
colnames(bothStrats) <- c("Close TLT", "Adjusted TLT")
getSymbols("SPY", from="1990-01-01")
ClSPY <- Return.calculate(Cl(SPY))
AdSPY <- Return.calculate(Ad(SPY))
SPYs <- cbind(ClSPY, AdSPY)
stratsAndBMs <- merge(bothStrats, SPYs, join='inner')
charts.PerformanceSummary(stratsAndBMs)

First of all, in order to download files that start off with the https stem, users will need to install the “downloader” package from CRAN. So a simple

install.packages("downloader")

will work just fine, and a thank you to Winston Chang for this package.

Beyond this, the way to turn a data frame to an xts (xts objects are the foundation of almost all serious financial analysis in R) is to pass in a data frame object along with a recognized format for a date. The default date format in R is “yyyy-mm-dd”, while something like 02/20/2014 would be “%mm/%dd/%yyyy”.

After this point, the syntax is the standard fare for computing returns, joining return series, and creating a summary chart. I used both the close and the adjusted price of 3x leveraged TLT (not an absolute replication of TMF, but conceptually very similar), in order to satisfy both the close-price and adjusted-price camps when dealing with return data. I myself prefer close prices, rather than making assumptions about dividend reinvestment, though sometimes splits force the issue.

Here’s a quick glance at the performance comparisons.

While the equity curves for the strategies look good (adjusted in red, close in black), what concerns me more is the drawdown plot. As can be seen, this strategy would have resulted in a protracted and severe drawdown from 2007 through 2010, hitting around 50% total drawdown, which should be far beyond the risk tolerance of…just about anyone. In short, this is far from any arbitrage. From a hypothesis standpoint, if someone were indeed to say “short volatility”, one would expect to see drawdowns in some form in the financial crisis. However, the drawdowns for this strategy are on par with that of the S&P 500 itself, which is to say, pretty bad.

Here’s a closer look at 2007-2010 for the strategies and the corresponding S&P 500 (close returns in green, adjusted in blue):

Basically, the performance is barely distinguishable form the S&P 500 at its worst, which makes this far from an effective strategy at its worst.

Here are the risk/return metrics for the strategies with the benchmarks for comparison:

> Return.annualized(stratsAndBMs)
                  Close.TLT Adjusted.TLT  SPY.Close SPY.Adjusted
Annualized Return 0.2328424    0.3239631 0.05336649    0.0748746
> SharpeRatio.annualized(stratsAndBMs)
                                Close.TLT Adjusted.TLT SPY.Close SPY.Adjusted
Annualized Sharpe Ratio (Rf=0%) 0.8780168     1.226562 0.2672673    0.3752571
> maxDrawdown(stratsAndBMs)
               Close.TLT Adjusted.TLT SPY.Close SPY.Adjusted
Worst Drawdown 0.5040189    0.4256037 0.5647367    0.5518672

Here are the return, drawdown, and Sharpe ratio statistics by year:

> apply.yearly(stratsAndBMs, Return.cumulative)
             Close.TLT Adjusted.TLT    SPY.Close SPY.Adjusted
2004-12-31  0.43091127   0.53673252  0.073541167   0.09027015
2005-12-30  0.38908539   0.50726218  0.030115000   0.04834811
2006-12-29  0.20547671   0.30869571  0.137418681   0.15843582
2007-12-31 -0.12139177  -0.04277199  0.032410676   0.05142241
2008-12-31  0.02308329   0.10593220 -0.382805554  -0.36791039
2009-12-31 -0.15364860  -0.09427527  0.234929078   0.26344690
2010-12-31  0.64545635   0.76914182  0.128409907   0.15053339
2011-12-30  0.37738081   0.47880348 -0.001988072   0.01897321
2012-12-31  0.55343030   0.62319271  0.134741036   0.15991238
2013-12-31  0.01191596   0.06800805  0.296889263   0.32309145
2014-10-01  0.38674137   0.44448550  0.052303861   0.06697777
> apply.yearly(stratsAndBMs, maxDrawdown)
           Close.TLT Adjusted.TLT  SPY.Close SPY.Adjusted
2004-12-31 0.1626657    0.1508961 0.07304589   0.06961279
2005-12-30 0.1578365    0.1528919 0.07321443   0.06960143
2006-12-29 0.2504912    0.2297468 0.07593123   0.07592093
2007-12-31 0.3289898    0.3006318 0.09924591   0.09921458
2008-12-31 0.4309851    0.4236635 0.48396143   0.47582236
2009-12-31 0.3833131    0.3668421 0.27131700   0.27123750
2010-12-31 0.1270308    0.1219816 0.16098842   0.15703744
2011-12-30 0.1628584    0.1627968 0.19423880   0.18608682
2012-12-31 0.1123245    0.1054862 0.09686971   0.09686039
2013-12-31 0.2840916    0.2782082 0.06047736   0.05550422
2014-10-01 0.1065488    0.1023469 0.05696031   0.05698600
> apply.yearly(stratsAndBMs, SharpeRatio.annualized)
             Close.TLT Adjusted.TLT    SPY.Close SPY.Adjusted
2004-12-31  2.90726854    3.7072225  0.893324847   1.10342092
2005-12-30  1.96324189    2.5862100  0.291120531   0.46836705
2006-12-29  0.95902528    1.4533427  1.369071018   1.58940411
2007-12-31 -0.47792925   -0.1693763  0.205060111   0.32457756
2008-12-31  0.07389051    0.3388196 -0.925155310  -0.88807262
2009-12-31 -0.45741108   -0.2815325  0.879806802   0.98927701
2010-12-31  2.31270808    2.7875988  0.714706742   0.83968381
2011-12-30  1.29489799    1.6371371 -0.008639479   0.08243543
2012-12-31  2.12645653    2.3967509  1.061570060   1.26650058
2013-12-31  0.04205873    0.2408626  2.667267167   2.91640716
2014-10-01  2.54201473    2.9678436  0.683911514   0.88274606

In short, when the strategy is good, it’s terrific. But when it’s bad, it’s terrible. Furthermore, even in good years, the drawdowns are definitely eye-popping, on the order of 10-15% when things are going smoothly, and anywhere between 25%-43% drawdown when they don’t, and those may not paint the whole story, either, as those are single-year max drawdowns, when one drawdown could have spanned years (which it did, in the financial crisis), getting worse than 50%. Indeed, far from an arbitrage, this strategy seems to be a bet on substantial returns usually, with painful drawdowns when incorrect.

For the record, here is the correlation table between the strategy and the benchmark:

> cor(stratsAndBMs)
             Close.TLT Adjusted.TLT SPY.Close SPY.Adjusted
Close.TLT    1.0000000    0.9970102 0.2366392    0.2378570
Adjusted.TLT 0.9970102    1.0000000 0.2384042    0.2395180
SPY.Close    0.2366392    0.2384042 1.0000000    0.9987201
SPY.Adjusted 0.2378570    0.2395180 0.9987201    1.0000000

Of course, this does not mean that the strategy is pure alpha due to the low correlation with the S&P 500, just that the S&P may not be the greatest benchmark to measure it against–after all, this strategy carries a massive amount of risk in its raw form as posted by Harry Long on Seeking Alpha.

Thanks for reading.


To leave a comment for the author, please follow the link and comment on their blog: QuantStrat TradeR » R.

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.

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)