Overall Statistics |
Total Trades 14 Average Win 0.28% Average Loss -0.05% Compounding Annual Return -0.149% Drawdown 0.500% Expectancy -0.056 Net Profit -0.026% Sharpe Ratio -0.181 Probabilistic Sharpe Ratio 29.491% Loss Rate 86% Win Rate 14% Profit-Loss Ratio 5.61 Alpha -0.005 Beta -0.017 Annual Standard Deviation 0.007 Annual Variance 0 Information Ratio 1.266 Tracking Error 0.204 Treynor Ratio 0.072 Total Fees $8.00 |
import decimal import datetime import pandas as pd import numpy as np from EarningDates import (earningDates) class EarningsOptionsTrade(QCAlgorithm): def Initialize(self): self.SetStartDate(2018, 1, 22) # Set Start Date self.SetEndDate(2018, 3, 26) self.SetCash(100000) # Set Strategy Cash self.earningDates = earningDates self.symbols = [] for ticker in self.earningDates.keys(): #print(ticker) equity = self.AddEquity(ticker, Resolution.Minute) equity.SetDataNormalizationMode(DataNormalizationMode.Raw) option = self.AddOption(ticker,Resolution.Minute) self.symbols.append(option.Symbol) option.SetFilter(-10, +10, timedelta(0), timedelta(30)) self.marketOrder = {} self.symbolToTrade = {} self.price = 0.05 # One Schedule function that will run all days at 12:00 to look if the current time is 2 days before earnging date self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(9,31), self.symbolDate) self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.Every(timedelta(minutes=60)), self.portfolio) def OnData(self, slice): '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. Arguments: data: Slice object keyed by symbol containing the stock data ''' for ticker in self.earningDates.keys(): if ticker not in self.symbolToTrade.keys(): self.symbolToTrade[ticker] = False for symbol in self.earningDates.keys(): if self.symbolToTrade[symbol]: self.Debug('For symbol {} current Date of {} is one day prior Earnings'.format(symbol,self.Time)) self.selectOption(slice,symbol) self.symbolToTrade[symbol] = False def symbolDate(self): ''' This function runs every day at market open, and check if current date is one day before any dates within the earningDates. If this is the case, the symbolToTrade dictionary for that symbol is equal to True, and this trigger a transaction for that symbol in the OnData function. ''' symbolDates = self.earningDates for key, val in symbolDates.items(): for date in val[0]: earningDate = datetime.datetime.strptime(date,'%m-%d-%Y').date() if earningDate.year == self.Time.year and earningDate.month == self.Time.month: if (earningDate - timedelta(days=1)) == self.Time.date() : print('One Day prior Earngings for symbol {} on Date {}'.format(key,self.Time.date())) self.symbolToTrade[key] = True else: self.symbolToTrade[key] = False # return self.symbolToTrade[symbol] def selectOption(self,slice,ticker): ''' In this function we select the right contract for the symbol that is one day prior it earning date and look for a contract with a price of 0.05 or most near to 0.05 over the option chain for that symbol. Then, send a market order to buy that contract. ''' for kvp in slice.OptionChains: if (slice.OptionChains.Count == 0): self.Debug('There are not options contracts in this chain at date %s' % self.Time) return self.Debug('ticker is %s' % ticker) self.Debug('kvp.Key.ID.Symbol %s' % kvp.Key.ID.Symbol ) if ticker == kvp.Key.ID.Symbol: #in kvp.Key.ID.Symbol: #.ToString: chain = kvp.Value # Select At the Money calls and puts # Make 2 lists called atm_calls and atm_puts otm_puts = [x for x in chain if x.Strike <= x.UnderlyingLastPrice and x.Right == 1] if len(otm_puts) == 0: self.Debug('There are not options contract that meet conditions for symbol {}'.format(ticker)) prices = [x.LastPrice for x in otm_puts] expiration = [x.Expiry for x in otm_puts] contracts = [x.Symbol.Value for x in otm_puts] self.Debug(contracts) self.Debug(expiration) self.Debug(prices) contractIndex = (np.abs(np.array(prices)- self.price)).argmin() contract = otm_puts[contractIndex] price = contract.LastPrice strike = contract.Strike expiration = contract.Expiry.date() underlying = contract.UnderlyingLastPrice symbol = contract.Symbol.Value self.contract = contract.Symbol self.Debug('Contract selected is {} with price {} expiry {} strike {} underlying {}'.format(self.contract,price,expiration,strike,underlying)) self.marketOrder[symbol] = self.Buy(self.contract,1) def portfolio(self): option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option] for contract in option_invested: optionContract = self.Securities[contract].Symbol underlying = self.Securities[contract.Underlying].Price quantity = self.Portfolio[contract].Quantity lastPrice = self.Securities[contract].Price profits = round(self.Portfolio[contract].UnrealizedProfit,0) profit_percentage = self.Portfolio[contract].UnrealizedProfitPercent # self.Debug('On Date {} Profit percentage and profit for contract {} are {} {}'.format(self.Time.date(),optionContract,profit_percentage,profits)) if (profit_percentage > 5): self.Liquidate(contract) # self.Debug('Sell contract {} with profit/loss of {} {}' % (contract, profits,profit_percentage)) def OnOrderEvent(self, orderEvent): ''' Event when the order is filled. Debug log the order fill. :OrderEvent:''' self.Log(str(orderEvent)) order = self.Transactions.GetOrderById(orderEvent.OrderId) self.Debug("{0}: {1}: {2}".format(self.Time, order.Type, orderEvent))
earningDates = {'BABA': [['10-30-2020', '08-13-2020', '05-13-2020', '01-28-2020', '11-01-2019', '08-15-2019', '05-15-2019', '01-30-2019', '11-02-2018', '08-23-2018', '05-04-2018', '02-01-2018', '11-02-2017', '08-17-2017', '05-18-2017']], 'BLMN': [['11-04-2020', '07-29-2020', '04-24-2020', '02-12-2020', '11-06-2019', '07-31-2019', '04-26-2019', '02-14-2019', '10-29-2018', '07-30-2018', '04-26-2018', '02-22-2018', '11-03-2017', '07-26-2017', '04-26-2017', '02-17-2017']], 'BZUN': [['11-19-2020', '08-19-2020', '05-27-2020', '10-04-2020', '11-21-2019', '08-21-2019', '05-29-2019', '10-06-2019', '11-21-2018', '08-14-2018', '05-17-2018', '10-06-2018', '11-21-2017', '08-21-2017', '02-21-2017']], 'EAT': [['10-28-2020', '08-11-2020', '04-28-2020', '01-29-2020', '10-30-2019', '08-13-2019', '04-30-2019', '01-29-2019', '10-30-2018', '08-14-2018', '05-01-2018', '01-30-2018', '11-01-2017', '08-10-2017', '04-25-2017']], 'HD': [['11-17-2020', '08-18-2020', '05-19-2020', '02-25-2020', '11-19-2019', '08-20-2019', '05-21-2019', '02-26-2019', '11-13-2018', '08-14-2018', '05-15-2018', '02-20-2018', '11-14-2017', '08-15-2017', '05-16-2017', '02-21-2017']], 'MCD': [['10-20-2020', '07-24-2020', '04-28-2020', '01-28-2020', '10-22-2019', '07-26-2019', '04-30-2019', '01-30-2019', '10-23-2018', '07-26-2018', '04-30-2018', '01-30-2018', '10-24-2017', '07-25-2017', '04-25-2017']], 'PLAY': [['09-08-2020', '06-09-2020', '10-31-2020', '11-11-2019', '09-10-2019', '06-11-2019', '04-02-2019', '11-11-2018', '09-14-2018', '06-12-2018', '04-04-2018', '04-03-2018', '11-07-2017', '09-05-2017', '06-08-2017', '10-28-2017']], 'PZZA': [['11-04-2020', '08-04-2020', '05-05-2020', '02-24-2020', '11-06-2019', '08-06-2019', '05-07-2019', '02-26-2019', '11-06-2018', '08-07-2018', '05-08-2018', '02-27-2018', '10-31-2017', '08-01-2017', '05-02-2017', '02-21-2017']], 'SBUX': [['10-29-2020', '07-28-2020', '04-28-2020', '01-28-2020', '10-30-2019', '07-25-2019', '04-25-2019', '01-25-2019', '11-01-2018', '07-26-2018', '04-26-2018', '01-25-2018', '11-02-2017', '07-27-2017', '04-27-2017']], 'ULTA': [['11-03-2020', '08-27-2020', '05-29-2020', '10-13-2020', '11-05-2019', '08-29-2019', '05-31-2019', '10-14-2019', '11-06-2018', '08-30-2018', '05-31-2018', '10-15-2018']], 'VIPS': [['11-11-2020', '08-12-2020', '05-20-2020', '02-19-2020', '11-13-2019', '08-14-2019', '05-22-2019', '02-21-2019', '11-15-2018', '08-13-2018', '05-14-2018', '02-12-2018', '11-20-2017', '08-16-2017', '05-15-2017', '02-20-2017']], 'WING': [['10-28-2020', '07-30-2020', '05-05-2020', '02-25-2020', '10-30-2019', '08-01-2019', '05-07-2019', '02-27-2019', '10-29-2018', '08-02-2018', '05-03-2018', '02-22-2018', '11-02-2017', '08-03-2017', '05-04-2017', '10-02-2017']], 'YUM': [['10-28-2020', '07-30-2020', '04-29-2020', '02-05-2020', '10-30-2019', '08-01-2019', '05-01-2019', '02-07-2019', '10-31-2018', '08-02-2018', '05-02-2018', '02-08-2018', '11-02-2017', '08-03-2017', '05-03-2017', '02-09-2017']], 'YUMC': [['10-27-2020', '07-28-2020', '04-27-2020', '01-29-2020', '10-29-2019', '07-30-2019', '04-29-2019', '01-31-2019', '10-30-2018', '08-01-2018', '05-01-2018', '02-05-2018', '04-05-2017', '02-07-2017']]}