| Overall Statistics |
|
Total Trades 8 Average Win 0.29% Average Loss -0.65% Compounding Annual Return -21.226% Drawdown 1.600% Expectancy -0.419 Net Profit -1.363% Sharpe Ratio -5.682 Probabilistic Sharpe Ratio 0.007% Loss Rate 60% Win Rate 40% Profit-Loss Ratio 0.45 Alpha -0.101 Beta 0.116 Annual Standard Deviation 0.036 Annual Variance 0.001 Information Ratio 3.142 Tracking Error 0.22 Treynor Ratio -1.774 Total Fees $20.00 Estimated Strategy Capacity $470000.00 Lowest Capacity Asset SPY 31BIVCUZR6WDI|SPY R735QTJ8XC9X |
from datetime import timedelta
from datetime import datetime
import math
from QuantConnect.Securities.Option import OptionPriceModels
class BullPutSpreadAlgorithm(QCAlgorithm):
ordersList = list()
def Initialize(self):
self.SetStartDate(2020,2, 10)
self.SetEndDate(2020,2, 29)
self.SetCash(600000)
self.SetWarmUp(30, Resolution.Minute)
equity = self.AddEquity("SPY", Resolution.Minute)
option = self.AddOption("SPY", Resolution.Minute)
self.symbol = option.Symbol
option.SetFilter(lambda universe: universe.WeeklysOnly().Strikes(-30, -5).Expiration(timedelta(0), timedelta(29)))
# use the underlying equity SPY as the benchmark
option.PriceModel = OptionPriceModels.CrankNicolsonFD()
self.SetBenchmark(equity.Symbol)
self.SetWarmUp(timedelta(45))
self.optionMuliplier = option.ContractMultiplier
self.Schedule.On(self.DateRules.WeekStart(), self.TimeRules.At(9,35), self.OpenWeekTrade)
def OnData(self,slice):
optionchain = slice.OptionChains
for i in slice.OptionChains:
if i.Key != self.symbol: continue
chains = i.Value
contract_list = [x for x in chains]
# if there is no contracts in this optionchain, pass the instance
if (slice.OptionChains.Count == 0) or (len(contract_list) == 0):
return
self.options_data = optionchain
def OnOrderEvent(self, orderEvent):
order = self.Transactions.GetOrderById(orderEvent.OrderId)
quantity = orderEvent.FillQuantity
fill_price = orderEvent.FillPrice
underlying = orderEvent.Symbol.Underlying
sym = orderEvent.Symbol
if order.Type == OrderType.OptionExercise:
self.Debug("Assignment: " + str(orderEvent.Symbol) + " quan: " + str(quantity) + " time: " + str(self.Time) )
self.ExerciseOnAssignment(sym)
def ExerciseOnAssignment(self, sym):
ticket = None
option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option]
s_options = sorted(option_invested, key = lambda x: x.ID.StrikePrice, reverse=True )
self.Debug("Length of s_options: " + str(len(s_options)))
for option in s_options:
if (option.Underlying == sym ):
self.Log( str(self.ExerciseOption(option, 20 )) + " : Exercised: " + str(self.Time.second ) )
self.Log("SPY Quan: " + str(self.Portfolio[sym].Quantity))
if self.Portfolio[sym].Quantity != 0:
self.Log("Exercise failed: " + str(sym) + ":" + str(self.Portfolio[option.Underlying].Quantity ) )
self.Debug("Quantity after exercise " + str(self.Portfolio[option.Underlying].Quantity))
def OpenWeekTrade(self):
for i in self.options_data:
if i.Key != self.symbol: continue
chain = i.Value
expiry = sorted(chain,key = lambda x: x.Expiry)[0].Expiry
put = [i for i in chain if i.Right == 1 and i.Greeks.Delta > -0.1 and i.Strike % 1 == 0 and (i.Expiry-self.Time).days == 3 ]
put_contracts = sorted(put,key = lambda x: x.Strike, reverse=True)
if len(put_contracts) == 0:
continue
#5 point wide spread
self.long_put = put_contracts[5]
self.short_put = put_contracts[0]
self.Order(self.short_put.Symbol, -20)
self.Order(self.long_put.Symbol, 20)