| Overall Statistics |
|
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $0.00 |
import math
from datetime import timedelta
from QuantConnect.Securities.Option import OptionPriceModels
from QuantConnect.Orders import OrderStatus
class BullCallSpreadAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2017, 1, 1)
self.SetEndDate(2017, 2, 1)
self.SetCash(10000)
self.equity = self.AddEquity("SPY", Resolution.Minute)
self.option = self.AddOption("SPY", Resolution.Minute)
self.symbol = self.option.Symbol
# set our strike/expiry filter for this option chain
self.option.SetFilter(-20, 1, timedelta(15), timedelta(45))
self.option.PriceModel = OptionPriceModels.CrankNicolsonFD()
self.SetWarmUp(TimeSpan.FromDays(4))
# use the underlying equity SPY as the benchmark
self.SetBenchmark(self.equity.Symbol)
self.Schedule.On(self.DateRules.EveryDay(self.symbol),
self.TimeRules.BeforeMarketClose(self.symbol, 30),
self.TradeOptions)
self.risk_factor = 0.5
def OnData(self,slice):
if self.equity.Symbol in self.Portfolio and self.Portfolio[self.equity.Symbol].Quantity != 0:
self.Sell(self.equity.Symbol, self.Portfolio[self.equity.Symbol].Quantity)
optionchain = slice.OptionChains
valid = False
for i in slice.OptionChains:
if i.Key != self.symbol:
continue
if i.Value.Contracts.Count != 0:
valid = True
break
else:
self.Log("Chain is empty")
if not valid:
self.optionchain = None
return
self.optionchain = optionchain
def TradeOptions(self):
if self.IsWarmingUp:
return
if self.Portfolio.Invested:
return
if not self.optionchain:
self.Log("No chain")
return
chain = None
for i in self.optionchain:
if i.Key != self.symbol:
continue
chain = i.Value
break
if chain is None:
self.Log("Chain not found")
return
if chain.Contracts.Count == 0:
self.Log("Chain empty")
return
expiry = sorted(chain, key = lambda x: x.Expiry, reverse=True)[0].Expiry
self.Log("Expiry is {}".format(expiry))
puts = [i for i in chain if i.Expiry == expiry and i.Right == OptionRight.Put]
if not puts:
self.Log("No contracts for given expiry")
return
puts_by_delta = sorted(puts, key=lambda x: x.Greeks.Delta, reverse=True)
low_put = None
high_put = None
for contract in puts_by_delta:
if abs(contract.Greeks.Delta) > 0.40 and low_put is None:
low_put = contract
if abs(contract.Greeks.Delta) > 0.45 and high_put is None:
high_put = contract
break
if high_put and low_put:
self.Log("Low Put: {}, High Put: {}".format(low_put.Greeks.Delta, high_put.Greeks.Delta))
else:
self.Log("Lowest Put: {}, Highest Put: {}".format(puts_by_delta[0].Greeks.Delta, puts_by_delta[-1].Greeks.Delta))
return
spread_risk = float(high_put.Strike - low_put.Strike) * 100.0
if spread_risk == 0:
self.Log("Strikes are the same.")
return
amount_to_invest = float(self.Portfolio.Cash) * self.risk_factor
num_shares = math.floor(amount_to_invest / float(spread_risk))
self.Log("Spread risk: {}, amount_to_invest: {}, num_shares: {}".format(spread_risk, amount_to_invest, num_shares))
if num_shares > 0:
if self.Sell(high_put.Symbol, num_shares).Status != OrderStatus.Filled:
self.Log("Couldn't fill sell order")
return
if self.Buy(low_put.Symbol, num_shares).Status != OrderStatus.Filled:
self.Log("Couldn't fill buy order, reversing sell order")
self.Buy(high_put.Symbol, num_shares)
return
self.Schedule.On(self.DateRules.On(expiry.year, expiry.month, expiry.day),
self.TimeRules.BeforeMarketClose(self.symbol, 15),
self.CloseIfOTMNearExpiry)
def CloseIfOTMNearExpiry(self):
if self.Portfolio.TotalUnrealizedProfit < 0:
for i in self.Portfolio:
symbol = i.Key
security = i.Value
if security.Quantity == 0:
continue
if security.IsLong:
self.Sell(symbol, security.Quantity)
else:
self.Buy(symbol, security.Quantity)
def OnOrderEvent(self, orderEvent):
self.Log(str(orderEvent))