| Overall Statistics |
|
Total Trades 222 Average Win 0.01% Average Loss -0.02% Compounding Annual Return -0.526% Drawdown 0.200% Expectancy -0.016 Net Profit -0.037% Sharpe Ratio -0.551 Loss Rate 38% Win Rate 62% Profit-Loss Ratio 0.59 Alpha 0.02 Beta -0.033 Annual Standard Deviation 0.008 Annual Variance 0 Information Ratio -11.014 Tracking Error 0.067 Treynor Ratio 0.128 Total Fees $270.00 |
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
from datetime import timedelta, datetime, date
class EarningsAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2018,1,1)
self.SetEndDate(2018,1,26)
self.SetCash(2000000)
self.backtestSymbolsPerDay = {}
self.current_universe = []
self.symbols = []
self.syms = []
# Set the security initializer with the characteristics defined in CustomSecurityInitializer
self.SetSecurityInitializer(self.CustomSecurityInitializer)
self.UniverseSettings.Resolution = Resolution.Hour
#self.AddUniverse("my-dropbox-universe",Resolution.Daily, self.selector)
# time set here realises at 2pm US
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(11, 00, 00), Action(self.reb))
def selector(self, datetime):
self.current_universe = []
if len(self.backtestSymbolsPerDay) == 0:
url = "https://www.dropbox.com/s/u5s56xlhk5ukcyo/er.csv?dl=1"
raw_er = pd.read_csv(url)
self.Debug(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()
self.Debug(self.backtestSymbolsPerDay)
index = self.Time.strftime("%Y%m%d")
self.Debug(index)
try:
self.current_universe = self.backtestSymbolsPerDay[index]
except:
self.current_universe = []
self.Debug(self.Time)
self.Debug(self.current_universe)
#
equities = []
self.symbols = []
for ticker in self.current_universe:
equities.append(Symbol.Create(ticker, SecurityType.Equity, Market.USA))
#bench = self.AddEquity("SPY", Resolution.Minute)
#self.SetBenchmark(bench.Symbol)
# 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):
#sells all trades.
self.Debug(str(self.Time) +' '+'liquidating')
self.Liquidate()
def OnData(self, slice):
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
# 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(symbol)
#self.symbol = epic
self.straddle()
self.trade_execution()
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):
#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.Sell(self.atm_call[0].Symbol, size)
self.Sell(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
self.Log("{}: {}".format(self.Time, changes))
if self.x == 1:
for x in changes.AddedSecurities:
if x.Symbol.Value == 'SPY': continue
if x.Symbol.SecurityType != SecurityType.Equity: continue
x.SetDataNormalizationMode(DataNormalizationMode.Raw)
option = self.AddOption(x.Symbol.Value, Resolution.Minute)
option.PriceModel = OptionPriceModels.BinomialCoxRossRubinstein()
option.SetFilter(self.UniverseFunc)
self.symbols.append(option.Symbol)
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.x = 0
def UniverseFunc(self, universe):
#the option chain
return universe.IncludeWeeklys().Strikes(-1, 1).Expiration(timedelta(2), timedelta(8))
def CustomSecurityInitializer(self, security):
'''Initialize the security with raw prices and zero fees
Args:
security: Security which characteristics we want to change'''
security.SetDataNormalizationMode(DataNormalizationMode.Raw)
#security.SetFeeModel(ConstantFeeModel(0))
def OnEndOfAlgorithm(self):
self.Log('End captured')