Quant BuffetRelax, Not Over Thinking

Timing VIX ETNs

Log in to collect

Academic paper

Understanding ETNs on VIX Futures

AuthorsCarol Alexander; Dimitris Korovilas

Institute
  • University of Sussex
  • HSBC Holdings
  • Peking University
  • ?Peking University HSBC Business School
  • ?University of Sussex Business School
  • University of Reading
  • ICMA Centre
  • ?University of Reading - ICMA Centre

Strategy in a nutshell

: Daily VIX Curve Timing via XVIX-XVZ Rotation

The strategy trades XVIX and XVZ ETNs daily based on the VIX futures term structure. When the 30-day VIX divided by the 93-day VXV is below 1 (contango), XVIX is favored; when above 1 (backwardation), XVZ is favored. The portfolio is rebalanced daily, exploiting the complementary performance of the ETNs during different market volatility regimes.

Economic rationale

XVIX thrives in contango markets, while XVZ outperforms during steep backwardation, typically in market crashes. The strategy leverages these opposing dynamics, capturing volatility-driven returns while minimizing exposure to losses in the alternate ETN.

Backtest performance

Annualised return30.8%
Volatility23.49%
Beta0.448
Sharpe ratio1.14
Sortino ratio0.402
Win rate45%

Full Python code

from AlgorithmImports import *
#endregion
class TimingVIXETNs(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2012, 1, 1)
self.SetCash(100000)

self.symbols = ['SVXY', 'VIXM', 'XVZ']
for symbol in self.symbols:
    data = self.AddEquity(symbol, Resolution.Daily)
    data.SetLeverage(5)
self.vix = self.AddData(CBOE, 'VIX', Resolution.Daily).Symbol
self.vxv = self.AddData(CBOE, 'VIX3M', Resolution.Daily).Symbol
self.settings.daily_precise_end_time = False
def OnData(self, data):
if not all(x in data for x in self.symbols): 
    self.Liquidate()
    return

if self.vix in data and self.vxv in data:
    vix_price = data[self.vix].Value
    vxv_price = data[self.vxv].Value
    
    if vix_price != 0 and vxv_price != 0:
        ratio = float(vix_price / vxv_price)
        
        if ratio < 1:
            if not self.Portfolio['SVXY'].IsLong and not self.Portfolio['VIXM'].IsLong:
                self.Liquidate('XVZ')
                if data['SVXY'].Close != 0 and data['VIXM'].Close != 0:
                    self.SetHoldings('SVXY', 1)
                    self.SetHoldings('VIXM', 1)
        else:
            if not self.Portfolio['XVZ'].IsLong:
                self.Liquidate('SVXY')
                self.Liquidate('VIXM')
                if data['XVZ'].Close != 0:
                    self.SetHoldings('XVZ', 1)
else:
    self.Liquidate()