# Volatility Stat-Arb Shenanigans

This post deals with an impossible-to-implement statistical arbitrage strategy using VXX and XIV. The strategy is simple: if the average daily return of VXX and XIV was positive, short both of them at the close. This strategy makes two assumptions of varying dubiousness: that one can “observe the close and act on the close”, and that one can short VXX and XIV.

So, recently, I decided to play around with everyone’s two favorite instruments on this blog–VXX and XIV, with the idea that “hey, these two instruments are diametrically opposed, so shouldn’t there be a stat-arb trade here?”

So, in order to do a lick-finger-in-the-air visualization, I implemented Mike Harris’s momersion indicator.

```momersion <- function(R, n, returnLag = 1) {
momentum <- sign(R * lag(R, returnLag))
momentum[momentum < 0] <- 0
momersion <- runSum(momentum, n = n)/n * 100
colnames(momersion) <- "momersion"
return(momersion)
}
```

And then I ran the spread through it.

```

xivRets <- Return.calculate(Cl(xiv))
vxxRets <- Return.calculate(Cl(vxx))

```

In other words, this spread is certainly mean-reverting at just about all times.

And here is the code for the results from 2011 onward, from when the XIV and VXX actually started trading.

```#both sides
charts.PerformanceSummary(longShort['2011::'], main = 'long and short spread')

sig[sig < 0] <- 0
charts.PerformanceSummary(longOnly['2011::'], main = 'long spread only')

sig[sig > 0] <- 0
charts.PerformanceSummary(shortOnly['2011::'], main = 'short spread only')

threeStrats <- na.omit(cbind(longShort, longOnly, shortOnly))["2011::"]
colnames(threeStrats) <- c("LongShort", "Long", "Short")
rbind(table.AnnualizedReturns(threeStrats), CalmarRatio(threeStrats))
```

Here are the equity curves:

Long-short:

Long-only:

Short-only:

With the following statistics:

```                          LongShort      Long    Short
Annualized Return          0.115400 0.0015000 0.113600
Annualized Std Dev         0.049800 0.0412000 0.027900
Annualized Sharpe (Rf=0%)  2.317400 0.0374000 4.072100
Calmar Ratio               1.700522 0.0166862 7.430481
```

In other words, the short side is absolutely amazing as a trade–except for the one small fact of having it be impossible to actually execute, or at least as far as I’m aware. Anyhow, this was simply a for-fun post, but hopefully it served some purpose.

NOTE: I am currently contracting and am looking to network in the Chicago area. You can find my LinkedIn here.

## 25 thoughts on “Volatility Stat-Arb Shenanigans”

1. You may be able to implement that strategy in practice if you semd the order a few seconds before the close. Now, if you add borrow costs, plus transaction costs, plus bid ask spread, not sure you will have such a return. If you do 100 trades per year, and the total cost per transaction is 5bps, your return will go to 1.5%…

I believe what you are actually capturing here is variations of the price of the ETF vs their NAV, which is naturally readjusted the following day? Then you can do a similar trade with two different ETF that track the same index: long one and short the other. If there is a return that day in one direction, take the oposite direction the following day, and here you have another strategy with great Sharpe ratio… You go to bed thinking you are a future millionaire, and then you remember to add the costs… Damn it!

2. uiop says:

Hi,

Judging (only) by a one line remark in the following article, it looks like this might be the exact strategy that blew up
Spruce Alpha in August:

“The Spruce Alpha Fund seeks to generate high alpha, low beta, and low correlation returns
by identifying daily-resetting, highly-levered ETFs experiencing volatility decay, and shorting
them in bull and bear pairs,” the fund’s performance reports state.”

One possible explanation is that, during peak chaos in the August 24 premarket/just-after-open/maybe-later, for whichever vix long/short etf pair they were double-shorting, the etf autorized participants weren’t able to arbitrage them into line (at least with each other), which caused Spruce Alpha’s double unrealized P&L to become a large enough loss that their maximum risk and/or loss limits were triggered, and they liquidated at a loss.

This pdf from BlackRock goes into details about how and why many etfs went way out of whack at various points on Aug24. Basically, all the halts, heavy market order pressure (stops, panic, etc), and illiquidity converged to cause chaos in various etfs for nontrivial periods of time. The pdf:

So finally, my comment to you is, it would be very interesting to see the PerformanceSummary(longShort) at 1m (or whatever is needed) resolution, AND that uses the low values (instead of close). Not sure if you have this data, and maybe some pairs (when i say pair, i mean a long/short vix etf pair) had more divergence than others on Aug24, so not sure if VXX/XIV was the one they (Spruce Capital) was in (maybe UVXY/SVXY, etc).

Maybe it would be possible to see if this is how they blew up? If the max drawdown is >=-48% for some bar, that just might be Spruce Capital getting the chop.

3. uiop says:

Oh wait right, there’s no need for higher resolution data if this hypothetical event occurred during normal market hours. Just using the “low” rather than “close” data in the return ohlc data would suffice.

4. uiop says:

Wow so I sucked it up and did it, the UVXY/SVXY pair could be how it happened. Here is adaptation of your code for UVXY/SVXY, and only plotting the “longShort” (Spruce Alpha’s double short position).

Just under -50% drawdown across the +/- 1 week window round Augut 24.

require(quantmod)
require(PerformanceAnalytics)
UVXY <- getSymbols("UVXY", from="2015-08-01", to="2015-09-01", auto.assign=FALSE)
SVXY <- getSymbols("SVXY", from="2015-08-01", to="2015-09-01", auto.assign=FALSE)
UVXYRets <- Return.calculate(Cl(UVXY))
SVXYRets <- Return.calculate(Cl(SVXY))
charts.PerformanceSummary(longShort, main = 'long and short spread')

• Not sure that was the pair, since it was always horrible historically. If you take that strategy and use the adjusted prices, you’ll see that it gets chopped up for basically no returns over time.

But yes, any given pair can certainly come unglued–and usually, it’s not just one pair at once, if many people follow similar models.

• uiop says:

True, I just realized to use the adjusted price. It doesn’t look close to as desirable now.

5. uiop says:

Update, using UVXY\$UVXY.Adjusted and similar for SVXY, because Close is messed up before 2015-05-20, but the huge drawdown is unchanged using Adjusted rather than close.

The previously linked to plot is unchanged.

(plot) http://i.imgur.com/EGydfFt.png (from 2015-01-01 to now)
(src) http://sprunge.us/RJdI

6. uiop says:

Aargh wait, I made a mistake here.

SVXY is only a 1x ETF, not 2x like UVXY.

So taking that into account only leads to a -10% drawdown, rather than a -50%, across the end of August.

7. uiop says:

For completeness, plot and src just multiplying SVXY returns by 2:

• mg says:

Plenty of borrows available on these tickers if you know where to look.

8. mg says:

I don’t follow. Why is this strategy impossible to execute?

• because there are either no shares to borrow or you have to pay a large fee to borrow them

9. joe minden says:

These days, going long VIX is betting against policies of central banks. Selling vix can help raise equity prices (inline with some central banks’ policy makers’ views). Gone are the days of relatively good price discovery…

10. Pingback: Best Links of the Week | Quantocracy

11. Hi Ilya,

Thank you for an alternative implementation of momersion. There is one discrepancy though:

If we take the original definition of Momersion as
Mc = Count of all r(i) × r(i-1) > 0
MRc = Count of all r(i) × r(i-1) < 0
Momersion(n) = 100 × Mc/(Mc+MRc)

And compare it to your implementation
momentum <- sign(R * lag(R, returnLag))
momentum[momentum < 0] <- 0
momersion <- runSum(momentum, n = n)/n * 100

We can see that in origial version if r(i) × r(i-1) == 0 we do NOT count it, while in your implementation it does count. Not a huge difference though and it does converge to original version quickly.

• Since when is return EXACTLY zero at daily resolution?

• mg says:

just because it happens infrequently doesn’t mean you should ignore that case.

• You are right regarding the frequency of such even at daily resolution, but once you start looking at higher frequency data, these events happen quite often. The general idea is great regardless of the data timeframe

12. Fabrizio Maccallini says:

You can replicate the strategy with a rolling basket of futures. Assuming the futures trade at \$20 (average) it requires a minimum notional of \$20 * 30 futures * 1,000 multiplier = \$600,000 per basket. As the strategy can go in your face for some time, say 10 baskets, and futures can climb say to \$60, you may need a max capital of \$18,000,000.
You can perhaps reduce the basket to 5 futures, increasing further your tracking error.

• Fabrizio Maccallini says:

Actually I was incorrect, it is a real systematic leak of performance from XIV in replicating the short.