Overall Statistics |
Total Trades 50 Average Win 0% Average Loss -0.05% Compounding Annual Return -8.409% Drawdown 0.600% Expectancy -1 Net Profit -0.616% Sharpe Ratio -7.327 Probabilistic Sharpe Ratio 0.012% Loss Rate 100% Win Rate 0% Profit-Loss Ratio 0 Alpha -0.043 Beta -0.017 Annual Standard Deviation 0.008 Annual Variance 0 Information Ratio -17.106 Tracking Error 0.065 Treynor Ratio 3.629 Total Fees $48.00 Estimated Strategy Capacity $34000.00 Lowest Capacity Asset CALM WR5SUSCWO892|CALM R735QTJ8XC9X |
from clr import AddReference AddReference("System") AddReference("QuantConnect.Algorithm") AddReference("QuantConnect.Common") from decimal import Decimal from System import * from QuantConnect import * from QuantConnect.Algorithm import QCAlgorithm from QuantConnect.Data.UniverseSelection import * from QuantConnect.Securities.Option import OptionPriceModels import base64 import numpy as np import pandas as pd import requests from io import StringIO import requests from datetime import timedelta, datetime, date class EarningsAlgorithm(QCAlgorithm): def Initialize(self): self.SetStartDate(2018,1,1) self.SetEndDate(2018,1,26) self.SetCash(1000000) self.backtestSymbolsPerDay = {} self.current_universe = [] self.symbols = [] self.syms = [] self.equitiesSyms = [] self.sold = {} # Set the security initializer with the characteristics defined in CustomSecurityInitializer self.UniverseSettings.Resolution = Resolution.Minute self.UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw self.SetUniverseSelection(ScheduledUniverseSelectionModel(self.DateRules.Every(DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday),self.TimeRules.At(9, 00, 00), self.selector )) self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) self.changes = None bench = self.AddEquity("SPY", Resolution.Minute) self.SetBenchmark(bench.Symbol) self.x = 0 self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday), self.TimeRules.At(10, 0), self.reb) def CustomSecurityInitializer(self, security): security.SetDataNormalizationMode(DataNormalizationMode.Raw) def selector(self, datetime): self.current_universe = [] if len(self.backtestSymbolsPerDay) == 0: csv = self.Download("https://www.dropbox.com/s/gewbcrjrlcpslzd/er.csv?dl=1") raw_er = pd.read_csv(StringIO(csv)) self.Debug('raw_er.head : ' + str(raw_er.head())) for d in raw_er['trade_date'].unique(): i = str(d) self.backtestSymbolsPerDay[i] = (raw_er[raw_er['trade_date']== d]).symbol.tolist() index = self.Time.strftime("%Y%m%d") try: self.current_universe = self.backtestSymbolsPerDay[index] except: self.current_universe = [] equities = [] #equitiesSyms = [] self.symbols = [] for ticker in self.current_universe: equities.append(Symbol.Create(ticker, SecurityType.Equity, Market.USA)) # set a marker to only run after daily universe creation, otherwise it runs at midnight too and liquidates on open. self.x = 1 return equities def reb(self): for i in self.Portfolio.Values: self.Debug('liquidate') #self.Buy(i.Symbol, self.sold[i.Symbol]) self.Liquidate(i.Symbol) self.sold = {} def OnData(self, slice): if self.Time.hour == 13 and self.Time.minute == 1: for security in self.ActiveSecurities.Keys: self.Log(f'{self.Time} >> Security in Universe: {security.Value}') if slice.Bars.Count == 0: return if self.changes is None: return #if self.Portfolio.Invested: return if self.Time.hour < 15: return for security in self.ActiveSecurities.Keys: self.Log(f'Security in Universe: {security.Value}') self.option_data = slice self.TradeOptions(slice) #self.TradeEquities(slice) self.Debug(str(self.Time) +' '+'end OnData') def TradeOptions(self,slice): self.Debug('trading options') #for symbol in self.symbols: #if slice.OptionChains.Count == 0: return for i in slice.OptionChains: self.Debug('now chains') #if i.Key == symbol: chains = i.Value if i.Key in self.equitiesSyms: return # divide option chains into call and put options self.calls = list(filter(lambda x: x.Right == OptionRight.Call, chains)) self.puts = list(filter(lambda x: x.Right == OptionRight.Put, chains)) # if lists are empty return if not self.calls or not self.puts: return #expries should be same for put and calls so collecting only puts for now. (convinience) expiries = [i.Expiry for i in self.puts] # determine expiration date self.expiry = min(expiries, key=lambda x: abs((x.date()-self.Time.date()).days-90)) self.Debug(str(expiries)) self.Debug("we choose this expiry... " + str(self.expiry)) self.Debug(i.Key) #self.symbol = epic self.straddle() self.trade_execution(i.Key) #return def straddle(self): #strikes put_strikes = [i.Strike for i in self.puts] call_strikes = [i.Strike for i in self.calls] underlying_price = self.calls[0].UnderlyingLastPrice # determine at-the-money strike. Again doesnt matter call or put using put. strike = min(put_strikes, key=lambda x: abs(x-underlying_price)) # Set up the legs. self.atm_call = [i for i in self.calls if i.Expiry == self.expiry and i.Strike == strike] self.atm_put = [i for i in self.puts if i.Expiry == self.expiry and i.Strike == strike] self.Debug(' ...underlying is... ' + ' ...put strike...' + str(self.atm_put[0].Strike) + ' ...put delta...' + str(self.atm_put[0].Greeks.Delta)+ ' ...put atm expiry...' + str(self.atm_put[0].Expiry) + ' ...call atm strike...' + str(self.atm_call[0].Strike)+ ' ...call atm delta...' + str(self.atm_call[0].Greeks.Delta)+ ' ...call atm expiry...' + str(self.atm_call[0].Expiry)) def trade_execution(self, underlying): self.Debug("lets check the legs exist and are sensible") if self.atm_put and self.atm_call: #if self.atm_put[0].Greeks.Delta < -0.55 or self.atm_put[0].Greeks.Delta > -0.40:return #if self.atm_call[0].Greeks.Delta < 0.40 or self.atm_call[0].Greeks.Delta > 0.55:return #if self.atm_put[0].AskPrice < 0.30 :return #if self.atm_call[0].AskPrice < 0.30:return trade_cost = self.atm_put[0].AskPrice +self.atm_call[0].AskPrice self.Debug('Cost is :') self.Debug(trade_cost) if trade_cost == 0: return #set the size self.Debug(' ...atm strike...' + str(self.atm_put[0].AskPrice)+ ' ...atm strike...' + str(self.atm_call[0].AskPrice)) size = int(1000 / (trade_cost * 100)) #self.Portfolio.TotalPortfolioValue #deltas = 20000 / (self.Securities[self.symbol].Price * 100) #self.Debug(str(deltas)) #size = int(deltas) self.equitiesSyms.append(underlying) self.sold["self.atm_call[0].Symbol"] = size self.sold["self.atm_put[0].Symbol"] = size self.Buy(self.atm_call[0].Symbol, size) self.Buy(self.atm_put[0].Symbol, size) else: # no options so try tomorrow self.Debug(str(self.Time) + ' ...No optons... ' ) return def OnSecuritiesChanged(self, changes): self.changes = changes if self.x == 1: for x in changes.AddedSecurities: if x.Symbol.Value == 'SPY': continue if x.Symbol.SecurityType != SecurityType.Equity: continue option = self.AddOption(x.Symbol.Value, Resolution.Minute) option.PriceModel = OptionPriceModels.BinomialCoxRossRubinstein() option.SetFilter(self.UniverseFunc) self.symbols.append(option.Symbol) self.Log(f'{self.Time} >> {x.Symbol} and Options added to Universe') for x in changes.RemovedSecurities: if x.Symbol.Value == 'SPY': continue for symbol in self.Securities.Keys: if symbol.SecurityType == SecurityType.Option and symbol.Underlying == x.Symbol: self.RemoveSecurity(symbol) self.RemoveSecurity(x.Symbol) self.Log(f'{self.Time} >> {x.Symbol} and {symbol} removed from the Universe') self.x = 0 def UniverseFunc(self, universe): return universe.IncludeWeeklys().Strikes(-1, 1).Expiration(timedelta(2), timedelta(8))