| 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))