# Original paper

**Abstract**

We use unique regulatory data to examine open positions and activity in both listed and OTC volatility derivatives. Gross vega notional outstanding for index variance swaps is over USD 2 billion, with dealers short vega in order to supply the long vega demand of asset managers. For maturities less than one year, VIX futures are far more actively traded and have a higher notional amount outstanding than S&P 500 variance swaps. To the extent that dealers take on risk when facilitating trades, we estimate that the long volatility bias of asset managers puts upward pressure on VIX futures prices. Hedge funds have offset this potential impact by actively taking a net short position in nearby contracts. In our 2011‐2014 sample, the net impact added less than half a volatility point, on average, to nearby VIX futures contracts but added between one and two volatility points for contracts in less liquid, longer‐dated parts of the curve. We find no evidence that this price impact forces VIX futures outside no‐arbitrage bounds.

**Keywords:** Variance swap, VIX futures, options, demand pressure, buying pressure

# Trading rules

- Engage in trades using VIX futures, and employ the E-mini S&P 500 for hedging.
- When in contango and the daily roll > 0.10 points, sell the nearest VIX futures that still have over 10 business days until maturity.
- When in backwardation and the daily roll < -0.10 points, buy the nearest VIX futures that have more than 10 trading days left to maturity.
- Hold the position for a span of 5 business days and use corresponding E-mini S&P 500 positions to hedge against fluctuations in the spot VIX.
- Calculate daily roll as (front VIX futures price - VIX) / number of business days until settlement.
- Determine hedge ratios using regression analysis of VIX futures price changes and E-mini S&P 500 percentage changes.

# Python code

## Backtrader

```
import backtrader as bt
import numpy as np
from sklearn.linear_model import LinearRegression
class VIXFuturesStrategy(bt.Strategy):
def __init__(self):
self.vix = self.datas[0]
self.vix_futures = self.datas[1]
self.es = self.datas[2]
self.order = None
self.hold_days = 0
def next(self):
if self.order:
return
if self.hold_days > 0:
self.hold_days -= 1
return
days_to_maturity = self.vix_futures.days_to_maturity() # Implement this in your data feed
if days_to_maturity < 10:
return
daily_roll = (self.vix_futures[0] - self.vix[0]) / days_to_maturity
if daily_roll > 0.10:
position_size = self.broker.getvalue() * 0.9 / self.vix_futures # Adjust based on your risk management
self.sell(data=self.vix_futures, size=position_size)
hedge_ratio = self.calculate_hedge_ratio()
self.buy(data=self.es, size=position_size * hedge_ratio)
self.hold_days = 5
elif daily_roll < -0.10:
position_size = self.broker.getvalue() * 0.9 / self.vix_futures # Adjust based on your risk management
self.buy(data=self.vix_futures, size=position_size)
hedge_ratio = self.calculate_hedge_ratio()
self.sell(data=self.es, size=position_size * hedge_ratio)
self.hold_days = 5
def calculate_hedge_ratio(self):
vix_futures_returns = np.diff(np.log(self.vix_futures.get(size=252))) # 1-year lookback
es_returns = np.diff(np.log(self.es.get(size=252))) # 1-year lookback
lr = LinearRegression()
lr.fit(es_returns.reshape(-1, 1), vix_futures_returns)
return -lr.coef_[0]
def notify_order(self, order):
if order.status in [order.Submitted, order.Accepted]:
return
if order.status in [order.Completed]:
if order.isbuy():
self.log(f'BUY EXECUTED, {order.executed.price}')
elif order.issell():
self.log(f'SELL EXECUTED, {order.executed.price}')
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log('Order Canceled/Margin/Rejected')
self.order = None
```