VIX Central
VIX Central Contango
Introduction
The VIX Central Contango dataset by VIX Central tracks VIX Futures (VX) contango data. The data covers 12 Futures contracts closest to expiry/maturity, starts in June 2010, and is delivered on a daily frequency. The dataset is created by QuantConnect downloading data from VIX Central website, which collects and analyses VIX and VX (VIX Futures) data.
Contango and Backwardation are terms used to describe if participants in the Futures market are overpaying or underpaying relative to the "spot" price of the underlying commodity when trading a Futures contract ("spot" price is the price of the actual commodity/asset at a given moment in time). Contango and backwardation can be used to determine forward-looking expectations of the commodity's spot price by the time the Future has expired/matured and is set to be delivered by participants of the Futures market. As Futures near their expiration/maturity date, contango and backwardation curves tend to converge on the spot price of the commodity at the time of expiration.
For more information about the VIX Central Contango dataset, including CLI commands and pricing, see the dataset listing.
About the Provider
VIX Central was founded by Eli Mintz in 2012 with goal of displaying historical VIX term structures in a simple and intuitive interface. VIX Central provides access to real-time and historical VIX data for individual investors.
Requesting Data
To add VIX Central Contango data to your algorithm, call the AddDataadd_data method. Save a reference to the dataset Symbol so you can access the data later in your algorithm.
class VixCentralContangoAlgorithm(QCAlgorithm):
def initialize(self) -> None:
self.set_start_date(2014, 1, 1)
self.set_end_date(2018, 1, 1)
self.set_cash(25000)
self.dataset_symbol = self.add_data(VIXCentralContango, "VX", Resolution.DAILY).symbol
public class VixCentralContangoAlgorithm : QCAlgorithm
{
private Symbol _datasetSymbol;
public override void Initialize()
{
SetStartDate(2014, 1, 1);
SetEndDate(2018, 1, 1);
SetCash(25000);
_datasetSymbol = AddData<VIXCentralContango>("VX", Resolution.Daily).Symbol;
}
}Accessing Data
To get the current VIX Central Contango data, index the current Slice with the dataset Symbol. Slice objects deliver unique events to your algorithm as they happen, but the Slice may not contain data for your dataset at every time step. To avoid issues, check if the Slice contains the data you want before you index it.
def on_data(self, slice: Slice) -> None:
if slice.contains_key(self.dataset_symbol):
data_point = slice[self.dataset_symbol]
self.log(f"{self.dataset_symbol} front month at {slice.time}: {data_point.front_month}") public override void OnData(Slice slice)
{
if (slice.ContainsKey(_datasetSymbol))
{
var dataPoint = slice[_datasetSymbol];
Log($"{_datasetSymbol} front month at {slice.Time}: {dataPoint.FrontMonth}");
}
}
Historical Data
To get historical VIX Central Contango data, call the Historyhistory method with the dataset Symbol. If there is no data in the period you request, the history result is empty.
# DataFrame history_df = self.history(self.dataset_symbol, 100, Resolution.DAILY) # Dataset objects history_bars = self.history[VIXCentralContango](self.dataset_symbol, 100, Resolution.DAILY)
var history = History<VIXCentralContango>(_datasetSymbol, 100, Resolution.Daily);
For more information about historical data, see History Requests.
Example Applications
The VIX Central Contango dataset enables you to explore VIX Future contracts pricing data. Examples include the following strategies:
- Determining forward-looking expectations by Futures market participants of the underlying commodity's spot price by the time of expiration/maturity
- Creating cash-and-carry arbitrage strategies by trading the spread/convergence of the contango/backwardation curves as a Future nears expiration/maturity
Classic Algorithm Design
The following example algorithm buys SPY when the percentage change between contract F2 and F1 (Contango_F2_Minus_F1) is positive. Otherwise, it remains in cash.
from AlgorithmImports import *
class VixCentralContangoAlgorithm (QCAlgorithm):
def initialize(self) -> None:
self.set_start_date(2024, 9, 1)
self.set_end_date(2024, 12, 31)
self.set_cash(25000)
# SPY as market representative for macroeconomy indicator trading
self.spy = self.add_equity("SPY", Resolution.DAILY).symbol
# Request VIX Contango data for trade signal generation
self.contango = self.add_data(VIXCentralContango, "VX", Resolution.DAILY).symbol
def on_data(self, slice: Slice) -> None:
# Trade base on the updated VIX contango data
if self.contango not in slice:
return
contango_data = slice.get(VIXCentralContango, self.contango)
ratio = contango_data.contango_f_2_minus_f_1 if contango_data else 0
# Bet the market will go up if F2 - F1 price percentage change is positive, meaning the near-term market volatility is expected to be low
if not self.portfolio.invested and ratio > 0:
self.set_holdings(self.spy, 1)
# Liqudiate otherwise to avoid excessive market volatility
elif ratio < 0:
self.liquidate()
public class VixCentralContangoAlgorithm : QCAlgorithm
{
private Symbol _spy, _contango;
public override void Initialize()
{
SetStartDate(2024, 9, 1);
SetEndDate(2024, 12, 31);
SetCash(25000);
// SPY as market representative for macroeconomy indicator trading
_spy = AddEquity("SPY", Resolution.Daily).Symbol;
// Request VIX Contango data for trade signal generation
_contango = AddData<VIXCentralContango>("VX", Resolution.Daily).Symbol;
}
public override void OnData(Slice slice)
{
// Trade base on the updated VIX contango data
if (!slice.ContainsKey(_contango))
{
return;
}
var contangoData = slice.Get<VIXCentralContango>(_contango);
var ratio = contangoData?.Contango_F2_Minus_F1 ?? 0;
// Bet the market will go up if F2 - F1 price percentage change is positive, meaning the near-term market volatility is expected to be low
if (!Portfolio.Invested && ratio > 0)
{
SetHoldings(_spy, 1);
}
// Liqudiate otherwise to avoid excessive market volatility
else if(ratio < 0)
{
Liquidate();
}
}
}Framework Algorithm Design
The following example algorithm buys SPY when the percentage change between contract F2 and F1 (Contango_F2_Minus_F1) is positive. Otherwise, it remains in cash.
from AlgorithmImports import *
class VixCentralContangoAlgorithm (QCAlgorithm):
def initialize(self) -> None:
self.set_start_date(2024, 9, 1)
self.set_end_date(2024, 12, 31)
self.set_cash(25000)
self.universe_settings.resolution = Resolution.DAILY
# Include SPY as market representative for macroeconomy indicator trading
symbols = [Symbol.create("SPY", SecurityType.EQUITY, Market.USA)]
self.add_universe_selection(ManualUniverseSelectionModel(symbols))
# Custom alpha model that emit insights base on VIX contango data
self.add_alpha(ContangoAlphaModel(self))
# Equal weighting investment to evenly dissipate the capital concentration risk on non-systematic risky event
self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel())
class ContangoAlphaModel(AlphaModel):
def __init__(self, algorithm: QCAlgorithm) -> None:
self.symbols = []
# Request VIX Contango data for trade signal generation
self.contango = algorithm.add_data(VIXCentralContango, "VX", Resolution.DAILY).symbol
# Historical data
history = algorithm.history(VIXCentralContango, self.contango, 60, Resolution.DAILY)
algorithm.debug(f"We got {len(history.index)} items from our history request")
def update(self, algorithm: QCAlgorithm, slice: Slice) -> List[Insight]:
insights = []
# Trade base on the updated VIX contango data
if self.contango not in slice:
return []
contango_data = slice.get(VIXCentralContango, self.contango)
ratio = contango_data.contango_f_2_minus_f_1 if contango_data else 0
# Bet the market will go up if F2 - F1 price percentage change is positive, meaning the near-term market volatility is expected to be low
if not algorithm.portfolio.invested and ratio > 0:
for symbol in self.symbols:
insights += [Insight.price(symbol, Expiry.ONE_MONTH, InsightDirection.UP)]
# Liqudiate otherwise to avoid excessive market volatility
elif ratio < 0:
for symbol in self.symbols:
insights += [Insight.price(symbol, Expiry.ONE_MONTH, InsightDirection.FLAT)]
return insights
def on_securities_changed(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None:
for symbol in [x.symbol for x in changes.removed_securities]:
if symbol in self.symbols:
self.symbols.pop(symbol)
self.symbols += [x.symbol for x in changes.added_securities]
public class VixCentralContangoAlgorithm : QCAlgorithm
{
public override void Initialize()
{
SetStartDate(2024, 9, 1);
SetEndDate(2024, 12, 31);
SetCash(25000);
UniverseSettings.Resolution = Resolution.Daily;
// Include SPY as market representative for macroeconomy indicator trading
var symbols = new[] {QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA)};
AddUniverseSelection(new ManualUniverseSelectionModel(symbols));
// Custom alpha model that emit insights base on VIX contango data
AddAlpha(new ContangoAlphaModel(this));
// Equal weighting investment to evenly dissipate the capital concentration risk on non-systematic risky event
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
}
}
public class ContangoAlphaModel : AlphaModel
{
private Symbol _contango;
private List<Symbol> _symbols;
public ContangoAlphaModel(QCAlgorithm algorithm)
{
_symbols = new List<Symbol>();
// Request VIX Contango data for trade signal generation
_contango = algorithm.AddData<VIXCentralContango>("VX", Resolution.Daily).Symbol;
// Historical data
var history = algorithm.History<VIXCentralContango>(_contango, 60, Resolution.Daily);
algorithm.Debug($"We got {history.Count()} items from our history request");
}
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice slice)
{
var insights = new List<Insight>();
// Trade base on the updated VIX contango data
if (!slice.ContainsKey(_contango))
{
return insights;
}
var contangoData = slice.Get<VIXCentralContango>(_contango);
var ratio = contangoData?.Contango_F2_Minus_F1 ?? 0;
// Bet the market will go up if F2 - F1 price percentage change is positive, meaning the near-term market volatility is expected to be low
if (!algorithm.Portfolio.Invested && ratio > 0)
{
foreach (var symbol in _symbols)
{
insights.Add(Insight.Price(symbol, Expiry.OneMonth, InsightDirection.Up));
}
}
// Liqudiate otherwise to avoid excessive market volatility
else if (ratio < 0)
{
foreach (var symbol in _symbols)
{
insights.Add(Insight.Price(symbol, Expiry.OneMonth, InsightDirection.Flat));
}
}
return insights;
}
public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
foreach (var symbol in changes.RemovedSecurities.Select(x=> x.Symbol))
{
_symbols.Remove(symbol);
}
_symbols.AddRange(changes.AddedSecurities.Select(x=> x.Symbol));
}
}