Overall Statistics |
Total Trades 2 Average Win 0% Average Loss 0% Compounding Annual Return 45.152% Drawdown 40.000% Expectancy 0 Net Profit 2.300% Sharpe Ratio 2.201 Probabilistic Sharpe Ratio 50.307% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 4.215 Beta 4.002 Annual Standard Deviation 1.322 Annual Variance 1.747 Information Ratio 3.134 Tracking Error 1.032 Treynor Ratio 0.727 Total Fees $10.50 |
from QuantConnect.Securities.Option import OptionPriceModels class TransdimensionalResistanceReplicator(QCAlgorithm): #sell calls def Initialize(self): self.SetStartDate(2020, 6, 9) # Set Start Date self.SetCash(100000) # Set Strategy Cash self.SetEndDate(2020, 7, 1) # Set End Date self.equityVxx = self.AddEquity("VXX", Resolution.Minute) self.equitySpy = self.AddEquity("SPY", Resolution.Minute) self.symbols = [] for ticker in ["VXX", "SPY"]: option = self.AddOption(ticker) self.symbols.append(option.Symbol) option.SetFilter(TimeSpan.FromDays(15),TimeSpan.FromDays(38)) option.PriceModel = OptionPriceModels.CrankNicolsonFD() #vxxOptions = self.AddOption("VXX") #vxxOptions.SetFilter(TimeSpan.FromDays(15),TimeSpan.FromDays(38)) #vxxOptions.PriceModel = OptionPriceModels.CrankNicolsonFD() #spyOptions = self.AddOption("SPY") #spyOptions.SetFilter(TimeSpan.FromDays(15),TimeSpan.FromDays(38)) #spyOptions.PriceModel = OptionPriceModels.CrankNicolsonFD() #cash buffer self.Settings.FreePortfolioValuePercentage = 0.02 #dict of limit orders open self.__openLimitOrders = [] self.SetWarmUp(30, Resolution.Daily) def OnData(self, slice): if self.IsWarmingUp: return option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option] if self.HourMinuteIs(10, 00): self.underlyingPriceVxx = self.Securities[self.equityVxx.Symbol].Price self.underlyingPriceSpy = self.Securities[self.equitySpy.Symbol].Price #self.Debug("Current " + str(self.Securities[self.equityVxx.Symbol]) + ", " + str(self.underlyingPriceVxx) + ", " + str(self.Securities[self.equitySpy.Symbol]) + ", " + str(self.underlyingPriceSpy) + ", at " + str(self.Time)) for symbol in self.symbols: #checking to see if there is already an open position in the ticker invested = [option for option in option_invested if option.Underlying == symbol.Underlying] if len(invested) > 0: return for chain in slice.OptionChains: if str(chain.Key) == "?VXX": self.optionchain = [contract for contract in chain.Value if contract.Right is 0 and contract.Strike - self.underlyingPriceVxx > 1] if len(self.optionchain) == 0: self.Debug("no chain options") continue self.sortedVxx = sorted(self.optionchain, key=lambda k : k.Expiry, reverse=False) self.greekVxx = [contract for contract in self.sortedVxx if contract.Greeks.Delta >= .25 and contract.Greeks.Delta <= .35 ] self.popVxx = sorted(sorted(self.greekVxx, \ key=lambda k: k.Greeks.Delta, reverse=False), key=lambda k: k.OpenInterest, reverse=True) #for contract in self.popVxx: #self.Debug(str(contract.Expiry) + ", " + str(contract.Strike) + ", " + str(contract.UnderlyingSymbol) + ", " + str(contract.Right) + ", " + str(contract.Greeks.Delta) + ", " + str(contract.OpenInterest)) #generally want to buy on a wednesday. self.liquidContract = self.popVxx[0] #self.Debug("Selling this contract: ") #self.Debug(str(self.liquidContract.Expiry) + ", " + str(self.liquidContract.Strike) + ", " + str(self.liquidContract.UnderlyingSymbol) + ", " + str(self.liquidContract.Right) + ", " + str(self.liquidContract.Greeks.Delta) + ", " + str(self.liquidContract.OpenInterest)) #use criterion to choose how many options to sell quantityVxx = self.CalculateOrderQuantity(self.liquidContract.Symbol, 0.05) #self.Debug("quantity of VXX contracts to sell " + str(-1 * (quantityVxx)) + ", at limit " + str(self.liquidContract.AskPrice) ) newTicket = self.LimitOrder(self.liquidContract.Symbol, -1 * (quantityVxx), round(self.liquidContract.AskPrice, 2)) self.__openLimitOrders.append(newTicket) self.Debug("# limit orders " + str(len(self.__openLimitOrders))) if len(self.__openLimitOrders) == 1: self.openOrders = self.__openLimitOrders #vxxOrder = self.openOrders[0] #orderId = vxxOrder.OrderId #newTicketId = self.newTicket.OrderId #self.Debug("newTicket status " + str(self.newTicket.Status)) #self.Debug("order status " + str(OrderStatus.Filled)) #self.Debug("order id " + str(vxxOrder.OrderId)) #check if order got filled #filled = self.OnOrderEvent(vxxOrder) #self.Debug("filled : " + str(filled)) #if self.newTicket.Status == OrderStatus.Filled: #if filled == 0: #self.Debug("Order Filled") #self.__openLimitOrders = [] #if it didn't get filled, do more reasonable limit #elif vxxOrder.Status != OrderStatus.Filled: #elif filled == 1: #self.newLimit = round(vxxOrder.Get(OrderField.LimitPrice) - 0.01, 2) #self.Debug("Updating limits - Price " + str(self.newLimit)) #updateSettings = UpdateOrderFields() #updateSettings.LimitPrice = self.newLimit #vxxOrder.Update(updateSettings) def HourMinuteIs(self, hour, minute): return self.Time.hour == hour and self.Time.minute == minute def OnOrderEvent(self, orderEvent): order = self.Transactions.GetOrderById(orderEvent.OrderId) if orderEvent.Status == OrderStatus.Filled: self.Debug("{0}: {1}: {2}".format(self.Time, order.Type, orderEvent))