| Overall Statistics |
|
Total Trades 4 Average Win 0.36% Average Loss 0% Compounding Annual Return 322.145% Drawdown 0.200% Expectancy 0 Net Profit 0.726% Sharpe Ratio 11.225 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 100% Profit-Loss Ratio 0 Alpha 0 Beta 0.097 Annual Standard Deviation 0.046 Annual Variance 0.002 Information Ratio -11.225 Tracking Error 0.425 Treynor Ratio 5.283 Total Fees $4.00 |
from datetime import timedelta
class BullCallSpreadAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019, 11, 7)
self.SetEndDate(2019, 11, 12)
self.SetCash(100000)
#self.long= False
#stocks
equity = self.AddEquity("SHOP", Resolution.Minute)
equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
self.SetBenchmark(equity.Symbol)
#options
option = self.AddOption("SHOP", Resolution.Minute)
self.symbol = option.Symbol
option.SetFilter(self.UniverseFunc)
# Start of day bar
self.Consolidate("SHOP", timedelta(minutes=3), self.OnDataConsolidated)
self.openingBar = None
#self.Schedule.On(self.DateRules.EveryDay() , self.TimeRules.At(9, 37), Action(self.TradeOptions(chains)))
# self.Schedule.On(self.DateRules.EveryDay("SHOP"), self.TimeRules.At(11, 00), self.ClosePositions)
#self.Debug('end of initialization')
def UniverseFunc(self, universe):
return universe.IncludeWeeklys().Expiration(TimeSpan.FromDays(0),
TimeSpan.FromDays(6)).Strikes(0,0)
def OnData(self, slice):
if self.openingBar is None: #wait for the first 3min candle
#self.Debug('Opening bar is none')
return
for i in slice.OptionChains:
chains = i.Value
#Entries
if not self.Portfolio.Invested and self.long == False and self.short==False:
# for i in slice.OptionChains:
# chains = i.Value
if slice["SHOP"].Close > self.openingBar.Open:
# self.entryprice= self.MarketOrder("SHOP", 100)
self.avgfill = slice['SHOP'].Close
self.long = True
self.Debug(str(self.Time) + " Entry Long - Open was: " + str(self.openingBar.Open) + " SHOP is: " + str(self.avgfill))
self.TradeOptions(chains)
elif slice["SHOP"].Close < self.openingBar.Open:
self.avgfill = slice['SHOP'].Close
# self.entryprice= self.MarketOrder("SHOP", -100)
# self.avgfill = self.entryprice.AverageFillPrice
self.short=True
self.Debug(str(self.Time) + " Entry Short- Open was: " + str(self.openingBar.Open) + " SHOP is: " + str(self.avgfill))
self.TradeOptions(chains)
#Exits Profit taking
if self.Portfolio.Invested:
callBid = self.Securities[self.call.Symbol].BidPrice
callAsk = self.Securities[self.call.Symbol].AskPrice
putBid = self.Securities[self.put.Symbol].BidPrice
putAsk = self.Securities[self.put.Symbol].AskPrice
callUnderlying = self.Securities[self.call.Symbol].Underlying.Close
putUnderlying = self.Securities[self.put.Symbol].Underlying.Close
if self.long== True and slice["SHOP"].Close > (self.openingBar.Open*1.035):
self.Debug("Long Profit target hit, exit at " + str(slice["SHOP"].Close))
self.Debug('Call tracking price' + 'Bid: ' + str(callBid)+ 'Ask: ' + str(callAsk))
self.Debug('Shop at: ' + str(callUnderlying) + ' Stop Hit, expect Selling : At Bid ' + str(callBid) + ' and Ask is: ' + str(callAsk))
self.Sell(self.call.Symbol,1)
self.long=False
self.openingBar = None
elif self.short== True and slice["SHOP"].Close < (self.openingBar.Open*0.965):
self.Debug("Short Profit target hit, exit at " + str(slice["SHOP"].Close))
self.Debug('Shop at: ' + str(putUnderlying) + ' Stop Hit, expect Selling : At Bid ' + str(putBid) + ' and Ask is: ' + str(putAsk))
#self.ClosePositions
self.short=False
self.Sell(self.put.Symbol,1)
self.openingBar = None
#Exits Stop Loss
elif self.long== True and slice["SHOP"].Close < (self.avgfill*0.985):
self.Debug("Long stop loss, exit at " + str(slice["SHOP"].Close))
self.Debug('Call tracking price' + str(callBid) + str(callAsk))
self.Debug('Call tracking price' + 'Bid: ' + str(callBid)+ 'Ask: ' + str(callAsk))
#self.ClosePositions
self.long=False
self.Sell(self.call.Symbol,1)
self.openingBar = None
elif self.short== True and slice["SHOP"].Close > (self.avgfill*1.015):
self.Debug("Short stop loss, exit at " + str(slice["SHOP"].Close))
self.Debug('Shop at: ' + str(putUnderlying) +' Stop Hit, expect Selling : At Bid ' + str(putBid) + ' and Ask is: ' + str(putAsk))
#self.ClosePositions
self.short=False
self.Sell(self.put.Symbol,1)
self.openingBar = None
elif self.CloseTradeBar is True:
self.Debug('CloseTradeBar : time: ' + str(self.Time))
self.Debug('Attempt to retreive latest options price : ')
self.UpdateOptions(chains)
if self.long==True:
self.Sell(self.call.Symbol,1)
self.Debug('Call tracking price' + 'Bid: ' + str(callBid)+ 'Ask: ' + str(callAsk))
#self.OptionChainProvider.GetOptionContractList(self.call,self.Time)
#self.long=False
elif self.short==True:
self.Sell(self.put.Symbol,1)
#self.OptionChainProvider.GetOptionContractList(self.put,self.Time)
self.Debug('Shop at: ' + str(putUnderlying) + ' Stop Hit, expect Selling : At Bid ' + str(putBid) + ' and Ask is: ' + str(putAsk))
self.CloseTradeBar= False
#self.short=False
# else:
# self.Debug('Something went wrong at 11am close position trigger' + str(self.Time))
# self.Debug(str(self.long) + str(self.short))
# self.openingBar = None
#Options trade
def TradeOptions(self,chains):
# sorted the optionchain by expiration date and choose the furthest date
expiry = sorted(chains,key = lambda x: x.Expiry, reverse=True)[0].Expiry
# filter the call and put contract
call = [i for i in chains if i.Expiry == expiry and i.Right == OptionRight.Call]
put = [i for i in chains if i.Expiry == expiry and i.Right == OptionRight.Put]
# sorted the contracts according to their strike prices
call_contracts = sorted(call,key = lambda x: x.Strike)
if len(call_contracts) == 0: return
self.call = call_contracts[0]
#self.Debug(str(self.call.Symbol))
#self.Debug('ATM call is ' + str(self.call.Symbol.Value))
for i in put:
if i.Strike == self.call.Strike:
self.put = i
#self.Debug(str(self.Time) + ' ATM put is :' + str(self.put.Symbol) + ' and ' + 'ATM call is ' + str(self.call.Symbol)) #'SHOP Entry Price is: ' + str(slice['SHOP'].Close) +
putUnderlying = self.Securities[self.put.Symbol].Underlying.Close
if self.long== True:
#self.Buy(self.call.Symbol, 1)
self.Buy(self.call.Symbol, 1)
self.AddOptionContract(self.call.Symbol, Resolution.Minute)
#self.Debug(str(self.entryTime))
self.Debug('Shop at: ' + str(putUnderlying) + ' Call Ask Price: ' + str(self.Securities[self.call.Symbol].AskPrice))
elif self.short==True:
#self.Buy(self.put.Symbol, 1)
self.Buy(self.put.Symbol, 1)
self.AddOptionContract(self.put.Symbol, Resolution.Minute)
self.Debug('Shop at: ' + str(putUnderlying) + ' Put Ask Price: ' + str(self.Securities[self.put.Symbol].AskPrice))
#Update Options price
def UpdateOptions(self,chains):
# # sorted the optionchain by expiration date and choose the furthest date
# expiry = sorted(chains,key = lambda x: x.Expiry, reverse=True)[0].Expiry
# # filter the call and put contract
# call = [i for i in chains if i.Expiry == expiry and i.Right == OptionRight.Call]
# put = [i for i in chains if i.Expiry == expiry and i.Right == OptionRight.Put]
# # sorted the contracts according to their strike prices
# call_contracts = sorted(call,key = lambda x: x.Strike)
# if len(call_contracts) == 0: return
if self.long==True:
self.Debug(str(self.call.Symbol) + str(self.Securities[self.call.Symbol].BidPrice) + str(self.Securities[self.call.Symbol].AskPrice) + str(self.Securities[self.call.Symbol].Underlying.Close))
if self.short==True:
self.Debug('Contract: ' + str(self.put.Symbol) + ' Bid: ' + str(self.Securities[self.put.Symbol].BidPrice) + ' ASK: ' + str(self.Securities[self.put.Symbol].AskPrice) + ' Underlying price: ' + str(self.Securities[self.put.Symbol].Underlying.Close))
#self.Debug(str(self.call.Symbol))
#self.Debug('ATM call is ' + str(self.call.Symbol.Value))
# create a 3min candle at open
def OnDataConsolidated(self, bar):
if bar.Time.hour == 9 and bar.Time.minute == 30:
self.long= False
self.short= False
self.openingBar = bar
self.CloseTradeBar= False
#self.Debug('doing the 3min bar thing')
if bar.Time.hour == 11 and bar.Time.minute == 00:
self.CloseTradeBar = True
#self.Debug('doing the 3min bar thing')
# def ClosePositions(self):
# if self.Portfolio.Invested:
# # if self.long==True:
# # self.Sell(self.call.Symbol,1)
# # self.openingBar = None
# # self.long=False
# # self.Debug('Selling :' + str(self.call.Symbol) + ' At Bid ' + str(self.call.BidPrice) + ' Ask is: '+ str(self.call.AskPrice) + 'Long is: ' + str(self.long))
# # elif self.short==True:
# # self.Sell(self.put.Symbol,1)
# # self.openingBar = None
# # self.short=False
# # self.Debug('Selling :' + str(self.put.Symbol) + ' At Bid ' + str(self.put.BidPrice) + ' Ask is: ' + str(self.put.AskPrice) + 'Short is: ' + str(self.short))
# #else: return
# self.Liquidate()
# self.Debug('11am Liquidate function called')
# self.openingBar = None
def OnOrderEvent(self, orderEvent):
self.Log(str(orderEvent))