| Overall Statistics |
|
Total Trades 894 Average Win 2.68% Average Loss -2.16% Compounding Annual Return 1.777% Drawdown 79.000% Expectancy 0.069 Net Profit 19.157% Sharpe Ratio 0.166 Probabilistic Sharpe Ratio 0.075% Loss Rate 52% Win Rate 48% Profit-Loss Ratio 1.24 Alpha 0.038 Beta -0.028 Annual Standard Deviation 0.21 Annual Variance 0.044 Information Ratio -0.243 Tracking Error 0.257 Treynor Ratio -1.266 Total Fees $50007.88 Estimated Strategy Capacity $970000.00 Lowest Capacity Asset VIXY UT076X30D0MD |
from AlgorithmImports import *
import numpy as np
class RollContract(QCAlgorithm):
def Initialize(self):
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.SetStartDate(2013, 1, 2)
self.SetEndDate(2022,12,12)
self.SetCash(1000000)
res = Resolution.Minute
#CBOE only lists VIX Index at Daily level but can get vix options at minute level so get the options underlying price to get the minute VIX spot
ticker = 'VIX'
self.index_symbol = self.AddIndex(ticker, res).Symbol
option = self.AddIndexOption(self.index_symbol, res)
option.SetFilter(-1, 1, timedelta(0), timedelta(45))
self.option_symbol = option.Symbol
#add the front month UX futures, set to Raw
# if we dont the beginning of the futures curve in history is going to be backwards stiched at astronoimical levels and will hide the true
# shape of the vol curve at that moment in time
self.ux_1 = self.AddFuture(Futures.Indices.VIX,
dataNormalizationMode=DataNormalizationMode.Raw,dataMappingMode = DataMappingMode.OpenInterest,contractDepthOffset = 0)
#get etfs
self.spy = self.AddEquity("SPY",res).Symbol
self.vixy = self.AddEquity("VIXY",res).Symbol
self.svxy = self.AddEquity("SVXY",res).Symbol
self.SetBenchmark("SPY")
self.EnableAutomaticIndicatorWarmUp = True
def OnData(self, slice):
#create empty list for portfolio
current_port_symbols = []
# In case warming is required (for later use)
if self.IsWarmingUp:
return
if slice.OptionChains.ContainsKey(self.option_symbol) and self.spy in slice.Bars and self.vixy in slice.Bars and self.svxy in slice.Bars:
if self.Time.hour == 10 and self.Time.minute == 0:
#get basis (vix fut/vix spot -1)
vix_basis = (self.ux_1.Price/slice.OptionChains[self.option_symbol].Underlying.Price)-1
#plot basis
self.Plot("VIX Basis", "Basis",vix_basis)
#check current weight spy
current_port_symbols = [ x.Symbol.Value for x in self.Portfolio.Values if x.Invested ]
#current weight spy to later check to liquidate or not
currentweight_spy = (self.Portfolio["SPY"].Quantity * slice['SPY'].Close) /self.Portfolio.TotalPortfolioValue
self.Debug(f"current port symbols: {str(current_port_symbols)} DateTime: {self.Time}")
if vix_basis > 0:
#if not long svxy and short spy
if not ("SVXY" in current_port_symbols and currentweight_spy <0):
#if invested long vixy and long spy then
if "VIXY" in current_port_symbols and currentweight_spy > 0:
#if 100% long in spy do nothing if not set spy holdings to 100%
self.Liquidate("VIXY")
self.Liquidate("SPY")
self.SetHoldings("SPY",-.5)
self.SetHoldings("SVXY",.5)
else:
self.SetHoldings("SPY",-.5)
self.SetHoldings("SVXY",.5)
#if backwardated vol curve,
elif vix_basis < 0:
#if long SPY and vixy
if not ("VIXY" in current_port_symbols and currentweight_spy > 0):
if "SVXY" in current_port_symbols and currentweight_spy <0:
self.Liquidate("SVXY")
self.Liquidate("SPY")
self.SetHoldings("VIXY",.5)
self.SetHoldings("SPY",.5)
else:
self.SetHoldings("VIXY",.5)
self.SetHoldings("SPY",.5)
# self.Plot("option_symbol", "Price", slice.OptionChains[self.option_symbol].Underlying.Price)
# self.Plot(self.ux_1.Symbol.ID.Symbol, self.ux_1.Symbol.ID.Symbol, self.ux_1.Price)
# self.Plot("VIX Basis", "Basis",vix_basis)