Overall Statistics
Total Trades
127
Average Win
2.99%
Average Loss
-1.16%
Compounding Annual Return
10.588%
Drawdown
19.000%
Expectancy
0.822
Net Profit
225.287%
Sharpe Ratio
0.895
Probabilistic Sharpe Ratio
28.597%
Loss Rate
49%
Win Rate
51%
Profit-Loss Ratio
2.59
Alpha
0.085
Beta
0.056
Annual Standard Deviation
0.103
Annual Variance
0.011
Information Ratio
-0.229
Tracking Error
0.178
Treynor Ratio
1.654
Total Fees
$287.10
Estimated Strategy Capacity
$150000000.00
Lowest Capacity Asset
VIXY UT076X30D0MD

# The portfolio holds positions in the S&P 500 Index and constant maturity VIX futures. 
# weightings == of their risk contribution to portfolio, which is estimated by the GARCH(1,1) model lagged by one day.
# Long (Short) position in VIX futuresis determined by the shape of the VIX premium.
# The portfolio is rebalanced daily.
# The VIX premium is used as a one-day lagged indicator for trade execution of the VIX futures
# The positive (negative) value of VIX premium indicates to hold the short (long) position in
# VIX futures on the next day after calculation of VIX premium.

from collections import deque
from QuantConnect.Python import PythonQuandl
import numpy as np

class VIXPremium(QCAlgorithm):

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

        self.symbols = ['VIXY', 'SPY']

        # Daily price data.
        period = 20
        self.data = {}
        
        for symbol in self.symbols:
            self.AddEquity(symbol, Resolution.Daily)
            self.data[symbol] = deque(maxlen = period)
            
        # VIX and VIX3M filter.       
        self.vix = self.AddData(QuandlVix, 'CBOE/VIX', Resolution.Daily).Symbol
        self.vix3M = self.AddData(Quandl, 'CBOE/VXV', Resolution.Daily).Symbol
        
    def OnData(self, data):
        # Store daily price.
        for symbol in self.symbols:
            if symbol in data and data[symbol]:
                price = data[symbol].Value
                self.data[symbol].append(price)
        
        if self.vix in data and data[self.vix] and self.vix3M in data and data[self.vix3M]:
            # Data is ready.
            if len(self.data['VIXY']) == self.data['VIXY'].maxlen and len(self.data['SPY']) == self.data['SPY'].maxlen:
                vix = data[self.vix].Value
                vix3m = data[self.vix3M].Value

                vix_volatility = Volatility(self.data['VIXY'])
                market_volatility = Volatility(self.data['SPY'])
                total_volatility = 1/vix_volatility + 1/market_volatility
                
                w = (1.0 / vix_volatility) / total_volatility
                
                # Rebalance only on signal change.
                if vix3m >= vix:
                    # Contango -> short vixy.
                    if not self.Portfolio['VIXY'].IsShort:
                        self.SetHoldings('VIXY', -w)
                else:
                    # Backwardation -> long vixy.
                    if not self.Portfolio['VIXY'].IsLong:
                        self.SetHoldings('VIXY', w)

class QuandlVix(PythonQuandl):
    def __init__(self):
        self.ValueColumnName = "close"

def Volatility(values):
    values = np.array(values)
    returns = (values[1:] - values[:-1]) / values[:-1]
    return np.std(returns)