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)