Overall Statistics |
Total Trades 32 Average Win 1.83% Average Loss -1.50% Compounding Annual Return 1.274% Drawdown 3.100% Expectancy 0.111 Net Profit 2.387% Sharpe Ratio 0.436 Loss Rate 50% Win Rate 50% Profit-Loss Ratio 1.22 Alpha -0.039 Beta 2.978 Annual Standard Deviation 0.025 Annual Variance 0.001 Information Ratio -0.234 Tracking Error 0.025 Treynor Ratio 0.004 Total Fees $32.00 |
# Your New Python File #import requests #from bs4 import BeautifulSoup #import datetime #url_to_scrape = 'https://finance.yahoo.com/calendar/earnings?symbol=aapl' #Load html's plain data into a variable #plain_html_text = requests.get(url_to_scrape) #soup = BeautifulSoup(plain_html_text.text, 'html.parser') #table = soup.find('table', attrs={'class':'W(100%)'}) #table_rows = table.find_all('tr') #earning_dates = [] #for tr in table_rows: # td = tr.find_all('td') # row = [tr.text for tr in td] # if row == []: # pass # else: # earning_dates.append(row[2][:-9]) # #earnings_dates_clean = [] #for i in earning_dates: # earnings_dates_clean.append((i.replace("'","").replace(",",""))) #earn = 'Jan 31 2017' #earn_2 = 'Oct 25 2016' #earnings_dates_clean.append(earn) #earnings_dates_clean.append(earn_2) #def month_to_number(item): # if item[:3] == 'Apr': # item = item.replace('Apr','04') # if item[:3] == 'Oct': # item = item.replace('Oct','10') # if item[:3] == 'Nov': # item = item.replace('Nov','11') # if item[:3] == 'Jan': # item = item.replace('Jan','01') # if item[:3] == 'Feb': # item = item.replace('Feb','02') # if item[:3] == 'Mar': # item = item.replace('Mar','10') # if item[:3] == 'Jun': # item = item.replace('Jun','06') # if item[:3] == 'Jul': # item = item.replace('Jul','07') # if item[:3] == 'Aug': # item = item.replace('Aug','08') # if item[:3] == 'Sep': # item = item.replace('Sep','09') # if item[:3] == 'May': # item = item.replace('May','05') # if item[:3] == 'Dec': # item = item.replace('Dec','11') # return item # dates = [month_to_number(earnings_dates_clean[i]) for i in range(0,len(earnings_dates_clean))] #dates_obj = [datetime.datetime.strptime(dates[i], "%m %d %Y") for i in range(0,len(dates))]
import numpy as np from datetime import datetime from datetime import timedelta import decimal import time import pandas as pd from pandas.tseries.offsets import BDay from QuantConnect.Algorithm import * from QuantConnect.Data import * from QuantConnect.Securities.Option import OptionPriceModels #from earnings_dates import dates class MultidimensionalHorizontalShield(QCAlgorithm): def Initialize(self): self.SetStartDate(2017,1,10) # Set Start Date self.SetEndDate(2018,11,20) # Set End Date self.SetCash(30000) # Set Strategy Cash equity = self.AddEquity("AAPL", Resolution.Minute) equity.SetDataNormalizationMode(DataNormalizationMode.Raw) self.equity = equity.Symbol self.openTransaction = None self.closeByExpiration = True self.closeByProfitLoss = False self.maxOpenPositions = 5 self.limitOrders = [] # self.earningsDates is a list with AAPL earnings dates. The code to get these dates is # in the file earnings_dates # Is possible to do this approach with other stocks self.earningsDates = [datetime(2020, 4, 28),datetime(2020, 1, 27),datetime(2019, 10, 30), datetime(2019, 7, 29), datetime(2019, 4, 30), datetime(2019, 1, 29), datetime(2018, 11, 1), datetime(2018, 7, 31), datetime(2018, 5, 1), datetime(2018, 2, 1), datetime(2017, 11, 2), datetime(2017, 8, 1), datetime(2017, 5, 2), datetime(2017, 1, 31), datetime(2016, 10, 25)] option = self.AddOption("AAPL", Resolution.Minute) self.option_symbol = option.Symbol # The default setFilter is with monthly expiration. I comment this to use weekly expiration # option.SetFilter(-30, +30, timedelta(0), timedelta(30)) # Select contract by weekly expiration option.SetFilter(lambda universe: universe.WeeklysOnly().Strikes(-10,+10).Expiration(timedelta(0), timedelta(30))) # This is the Pricing model to calculate the Delta for each contract option.PriceModel = OptionPriceModels.CrankNicolsonFD() # Pricing model to gets delta # Warm up period self.SetWarmUp(TimeSpan.FromDays(10)) # 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(12,0), self.ActivateTransaction) # Schudele function to run the conditions to sell. Will run all days at 9:45 am self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(9, 45), self.CloseTrade) 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 ''' if(self.IsWarmingUp): return # At 15:45 each day if self.openTransaction is True, look for options contracts to buy if self.Time.hour ==15 and self.Time.minute ==45 and self.openTransaction==True: options_info = self.select_options(slice) if options_info is not None: call , midPriceCall, put, midPricePut = options_info self.Debug('call contract is %s' % call) CallPrice = round(midPriceCall + 0.04,2) PutPrice = round(midPricePut + 0.04,2) # Buy Limit Orders for put and call Callticket = self.LimitOrder(call,1,CallPrice) Putticket = self.LimitOrder(put,1,PutPrice) self.Debug('ticket is %s' % Callticket) self.limitOrders.append(Callticket) self.limitOrders.append(Putticket) # append the order ticket in the limitOrders list self.openTransaction = False # Set self.openTransaction to false in order to stop buying in the current day else: self.Debug('Cannot processing options information') def ActivateTransaction(self): ''' This function look if the current date is 2 business days before the earnings date. If this is the case the flag self.openTransaction is equal to True and the algo is ready to make orders ''' # if self.Time.date().isoweekday() ==1: self.Debug(self.Time) # If current date is two days before earnings date and if is weekday, set self.openTransaction # to True. This means to allow orders. two_days_ahead = (self.Time.date() + BDay(2)).date() for date in self.earningsDates: if (two_days_ahead) == date.date() and self.Time.date().isoweekday() <=5: self.Debug('Two days before earning release %s %s ' % (two_days_ahead, date.date())) self.openTransaction = True def select_options(self,slice): if (slice.OptionChains.Count == 0): self.Debug('There are not options contracts in this chain at date %s' % self.Time.date()) return for kvp in slice.OptionChains: chain = kvp.Value # Select At the Money calls and puts # Make 2 lists called atm_calls and atm_puts atm_calls = [x for x in chain if x.Strike <= x.UnderlyingLastPrice and x.Right == 0 and (x.Expiry.date() - self.Time.date()).days <= 20] atm_puts = [x for x in chain if x.Strike >= x.UnderlyingLastPrice and x.Right == 1 and (x.Expiry.date() - self.Time.date()).days <= 20] # Debugging messages that are comment to prevent flooding the screen #self.Debug('Deltas for call contracts are %s' % deltasCall) #self.Debug('Deltas for put contracts are %s' % deltasPut) deltasCall = [x.Greeks.Delta for x in atm_calls] deltasPut = [x.Greeks.Delta for x in atm_puts] # Find the neares delta to 0.5 for both put and call nearCallDelta = (np.abs(np.array(deltasCall)-0.5)).argmin() nearPutDelta = (np.abs(np.array(deltasPut)+0.5)).argmin() # The method argmin() return the index with the delta nearest to 0.5. Then we use that # index to lookup atm_calls and atm_puts call = atm_calls[nearCallDelta] put = atm_puts[nearPutDelta] self.Debug('Nearest call delta to 0.5 is %s' % call.Greeks.Delta) self.Debug('Nearest put delta to -0.5 is %s' % put.Greeks.Delta) callbid = call.BidPrice callask = call.AskPrice self.midPriceCall = round((callbid + callask)/2,2) putbid = put.BidPrice putask = put.AskPrice self.midPricePut = round((putbid + putask)/2,2) self.call = call.Symbol self.put = put.Symbol self.Debug('Underlying is %s' % self.Securities[self.equity].Price) self.Debug('Call contract is %s delta %s expiration %s strike %s' % (call.Symbol,call.Greeks.Delta,call.Expiry,call.Strike)) self.Debug('Put contract is %s delta %s expiration %s strike %s' % (put.Symbol, put.Greeks.Delta,put.Expiry,put.Strike)) return self.call, self.midPriceCall , self.put, self.midPricePut def CloseTrade(self): # Get all orders by calling the limitOrders list which have all order tickets orders = self.limitOrders # self.Transactions.GetOrders() if len(orders) == 0: return # Use BDay(5) to substract 5 days to current date five_days_ahead = (self.Time.date() - BDay(5)).date() # The logic is the following: is self.closeByExpiration is set to True in Initialize, # loop over orders and if current date is 5 days after order date and order status is filled # sell the contract using order.Symbol by the QuantityFilled method. if self.closeByExpiration: for order in orders: if (five_days_ahead == order.Time.date()) and (order.Status == OrderStatus.Filled): self.Sell(order.Symbol,order.QuantityFilled) self.Debug('sell %s after 5 days of order date' % order.Symbol) self.openTransaction = False option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option] option_invested_values = [x.Value for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option] # If self.closeByProfitLoss is set to True in Initialize, loop over contract in Portfolio and # get the current profit percentage of each contrct. If this profit percentage is greater than # 50% or lower than -11%, Liquidate(sell) the contract. if self.closeByProfitLoss: for contract in option_invested: self.Debug(self.Securities[contract].Symbol) underlying = self.Securities[self.equity].Price quantity = self.Portfolio[contract].Quantity lastPrice = self.Securities[contract].Price profits = round(self.Portfolio[contract].UnrealizedProfit,0) profit_percentage = self.Portfolio[contract].UnrealizedProfitPercent if (profit_percentage > 0.5) or (profit_percentage < -0.11): self.Liquidate(contract) self.Debug('Sell contract %s with profit/loss of %s' % (contract, profit_percentage)) #self.Debug("Contract: " + str(contract) + " - Underlying Price: " + str(underlying) + " - Quantity: " + str(quantity) + " - Last Price: " + str(lastPrice)) #self.Debug('Unrealized profits and profit percentage at date %s for contract %s are %s and %s' % (self.Time.date(), contract, profits,"{0:.0%}".format(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))