Overall Statistics |
Total Trades 397 Average Win 1.33% Average Loss -0.63% Compounding Annual Return -31.632% Drawdown 98.000% Expectancy -0.186 Net Profit -97.664% Sharpe Ratio -0.049 Probabilistic Sharpe Ratio 0.004% Loss Rate 74% Win Rate 26% Profit-Loss Ratio 2.11 Alpha 0.269 Beta -3.072 Annual Standard Deviation 0.724 Annual Variance 0.524 Information Ratio -0.164 Tracking Error 0.82 Treynor Ratio 0.012 Total Fees $2162.42 Estimated Strategy Capacity $260000.00 Lowest Capacity Asset VIXY Y5BMQ7C65TD2|VIXY UT076X30D0MD |
# The investment universe consists of a stock/bond portfolio with a proportion of 60-percent stocks and 40-percent bonds. # Stocks are represented by the SPDR S&P 500 ETF Trust (SPY) and bonds by the iShares 7-10 Year Treasury Bond ETF (IEF). # The strategy firstly invests 0-100 basis points (bsp) in the desired VIX call option, then allocates 60 percent of the # portfolio to the SPY and the remaining 40 percent to the IEF. The option is bought at the level of 135% of the moneyness # of the underlying VIX futures price. The strategy is systematically purchasing an equal amount in one-month, two-month, # three-month and four-month VIX call options on VIX futures. If the VIX Index is between 15 and 30, the weight of VIX calls # in the portfolio is 1%. If the VIX Index is between 30 and 50, the weight in the portfolio is 0.5%. If the VIX Index is over # 50 or under 15, then the weight of options in the portfolio is 0%. Each month, on the day before expiration, the options are # rolled to the appropriate expiry. VIX call options are purchased at the offer and sold at the bid to keep the assumptions # conservative. The options are held to maturity and closed the Tuesday afternoon before the Wednesday morning of VIX futures # and options expiration. If the contracts have any intrinsic value, they are sold at the bid price, and the cash is used at # the end of the month to rebalance the stock/bond portion of the portfolio. from AlgorithmImports import * class PortfolioHedgingUsingVIXOptions(QCAlgorithm): def Initialize(self): self.SetStartDate(2013, 1, 1) self.SetCash(1000000) data = self.AddEquity("SPY", Resolution.Daily) data.SetLeverage(5) self.spy = data.Symbol data = self.AddEquity("IEF", Resolution.Daily) data.SetLeverage(5) self.ief = data.Symbol data = self.AddEquity("VIXY", Resolution.Daily) data.SetLeverage(5) self.vix = data.Symbol option = self.AddOption('VIXY', Resolution.Daily) #option = self.AddOption('SPY', Resolution.Daily) self.SetWarmUp(30, Resolution.Daily) #public void SetFilter(int minStrike, int maxStrike, TimeSpan minExpiry, TimeSpan maxExpiry) # By default weekly options are excluded from options expiry so we get only monthly options. option.SetFilter(-20, 20, 0, 180) self.Debug("yolo") # Print to the console def OnData(self,slice): # OptionChains is a collection of OptionChain keyed by the option's underlying symbol. # The elements in Slice.OptionChains have properties Key(the underlying symbol object) and Value(the option chain). if self.IsWarmingUp: return for i in slice.OptionChains: chains = i.Value # If there are max of 2 positions open - spy and ief - that means option expired. invested = [x.Key for x in self.Portfolio if x.Value.Invested] #invested = ['SPX','VIXoption','Bond'] if len(invested) < 6: # Get the right being purchased x.Right = 1 call option[right to buy] # x.Right = 0 put option[right to sell] calls = list(filter(lambda x: x.Right == OptionRight.Call, chains)) if not calls: return underlying_price = self.Securities[self.vix].Price expiries = list(set([i.Expiry for i in calls])) #expiries = ['Dec', 'Jan', etc] strikes = [i.Strike for i in calls] # Determine out-of-the-money strike. otm_strike = min(strikes, key = lambda x:abs(x - (float(1.35) * underlying_price))) #otm_call = [i for i in calls if i.Expiry == expiry and i.Strike == otm_strike] otm_call = [i for i in calls if (j for j in expiries if j==i.Expiry) and i.Strike == otm_strike] if len(otm_call)==4: self.Debug("yolo1") # Option weighting. weight = 0.0 opt_price_1 = self.Securities[otm_call[0].Symbol].Price opt_price_2 = self.Securities[otm_call[1].Symbol].Price opt_price_3 = self.Securities[otm_call[2].Symbol].Price opt_price_4 = self.Securities[otm_call[3].Symbol].Price if underlying_price >= 15 and underlying_price <= 30: weight = 0.01 w1=0.01/4 w2=0.01/4 w3=0.01/4 w4=0.01/4 elif underlying_price > 30 and underlying_price <= 50: weight = 0.005 w1 = 0.005/4 w2 = 0.005/4 w3 = 0.005/4 w4 = 0.005/4 if weight != 0: if opt_price_1!=0: options_q1 = int((self.Portfolio.MarginRemaining * weight) / (opt_price_1 * 100)) else: options_q1=0 if opt_price_2!=0: options_q2 = int((self.Portfolio.MarginRemaining * weight) / (opt_price_2 * 100)) else: options_q2=0 if opt_price_3!=0: options_q3 = int((self.Portfolio.MarginRemaining * weight) / (opt_price_3 * 100)) else: options_q3=0 if opt_price_4!=0: options_q4 = int((self.Portfolio.MarginRemaining * weight) / (opt_price_4 * 100)) else: options_q4=0 # Set max leverage. self.Securities[otm_call[0].Symbol].MarginModel = BuyingPowerModel(5) # Sell out-the-money call. if options_q1: self.Buy(otm_call[0].Symbol, options_q1) if options_q2: self.Buy(otm_call[1].Symbol, options_q2) if options_q3: self.Buy(otm_call[2].Symbol, options_q3) if options_q4: self.Buy(otm_call[3].Symbol, options_q4) self.SetHoldings(self.spy, 0.6) self.SetHoldings(self.ief, 0.4)