Quant BuffetRelax, Not Over Thinking

Contrarian VIX strategy

Log in to collect

Academic paper

Do Not Fear the Fear Index: Evidence from the US, UK and European Markets

AuthorsPankaj Chandorkar; Janusz Brzeszczyński

Institute
  • Northumbria University
  • ?University of Northumbria at Newcastle
  • ?Newcastle Business School (NBS), Northumbria University, Newcastle upon Tyne, United Kingdom

Strategy in a nutshell

The strategy trades the SPDR S&P 500 ETF (SPY). One day after the VIX spikes three standard deviations above its mean, the strategy goes long SPY for one month (22 trading days).

Economic rationale

Extreme VIX jumps indicate heightened market fear, which often triggers looser monetary policy and higher expected returns. The strategy exploits this mean-reversion effect by buying after periods of extreme volatility, providing a systematic equity entry signal.

Backtest performance

Annualised return10.8%
Volatility5.59%
Beta0.405
Sharpe ratio1.93
Sortino ratio-0.036
Maximum drawdown-3.61%
Win rate62%

Full Python code

from AlgorithmImports import *
# endregion

class ContrarianVIXstrategy(QCAlgorithm):

def Initialize(self):
self.SetStartDate(2000, 1, 1)
self.SetCash(100000)

self.market:Symbol = self.AddEquity("SPY", Resolution.Daily).Symbol

# Subscribe to VIX index data
self.vix:Symbol = self.AddData(CBOE, "VIX").Symbol
 
self.period:int = 120 * 21
self.min_period:int = 12 * 21
self.std_multiplier:int = 2
self.buy_date:DateTime = None

history:DataFrame = self.History(CBOE, self.vix, self.period, Resolution.Daily)['close']
self.close_list:List[float] = history.values.tolist()

self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
self.SetExecution(ImmediateExecutionModel())

def OnData(self, data:Slice) -> None:
if self.vix in data and data[self.vix]:
    # store vix value
    self.close_list.append(data[self.vix].Close)

    if len(self.close_list) >= self.min_period:
        vix_mean:float = np.mean(self.close_list[:-1])
        vix_std:float = np.std(self.close_list[:-1])
        vix_yesterday:float = self.close_list[-2]
        
        if not self.Portfolio.Invested and vix_yesterday >= vix_mean + self.std_multiplier * vix_std:
            self.EmitInsights(Insight.Price(self.market, timedelta(days=22), InsightDirection.Up))