| Overall Statistics |
|
Total Orders 124554 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Start Equity 5000 End Equity 5000 Net Profit 0% Sharpe Ratio 0 Sortino Ratio 0 Probabilistic 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 -2 Tracking Error 0.104 Treynor Ratio 0 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset Portfolio Turnover 0% |
from AlgorithmImports import *
class BullCreditSpread(QCAlgorithm):
def initialize(self):
self.set_start_date(2024, 1, 1)
self.set_end_date(2024, 11, 1)
self.set_cash(5000)
self.spy = self.add_equity("SPY", Resolution.HOUR).symbol
self.spy_option = self.add_option("SPY")
self.spy_option.set_filter(self.weekly_filter)
self.sma = self.sma(self.spy, 50, Resolution.HOUR)
self.has_position = False
self.spy_price = None
self.tickets = []
self.open_symbols = []
self.schedule.on(self.date_rules.every(DayOfWeek.MONDAY), self.time_rules.at(10, 0), self.trade_options)
def weekly_filter(self, universe):
return universe.include_weeklys().strikes(-5, 5).expiration(0, 7)
def on_data(self, slice: Slice) -> None:
if not self.sma.is_ready:
return
if self.securities.contains_key(self.spy):
self.spy_price = self.securities[self.spy].price
if any([self.portfolio[symbol].invested for symbol in self.open_symbols]):
return
chain = slice.option_chains.get(self.spy_option.symbol)
if not chain:
return
expiry = min([x.expiry for x in chain])
puts = sorted([i for i in chain if i.expiry == expiry and i.right == OptionRight.PUT],
key=lambda x: x.strike)
if len(puts) < 2:
return
credit_per_spread = puts[-1].bid_price - puts[0].ask_price
if credit_per_spread <= 0:
return
budget = self.portfolio.total_portfolio_value * 0.02
self.num_spreads = int(budget / credit_per_spread)
bull_put_spread = OptionStrategies.bull_put_spread(self.spy_option.symbol, puts[-1].strike, puts[0].strike, expiry)
self.buy(bull_put_spread, self.num_spreads)
def trade_options(self):
if self.spy_price is None:
return
if self.spy_price > self.sma.current.value:
chain = self.current_slice.option_chains.get(self.spy_option.symbol)
if chain is None:
return
contracts = sorted(chain, key=lambda x: abs(x.greeks.delta - 0.35))
if len(contracts) == 0:
return
short_option = contracts[0]
long_options = [x for x in chain if x.strike < short_option.strike and x.expiry == short_option.expiry]
if not long_options:
return
long_option = sorted(long_options, key=lambda x: x.strike, reverse=True)[0]
if not self.has_position:
spread = OptionStrategies.bull_put_spread(self.spy_option.symbol, short_option.strike, long_option.strike, short_option.expiry)
ticket = self.buy(spread, self.num_spreads)
self.tickets.append(ticket)
self.open_symbols.append(self.spy_option.symbol)
self.has_position = True
def check_stop_loss(self):
current_float_loss = self.securities[self.spy].holdings.unrealized_profit - self.credit_received
if current_float_loss <= -1.25 * self.credit_received:
self.liquidate(self.current_option_strategy)
self.credit_received = 0.0
def check_take_profit(self):
current_float_profit = self.securities[self.spy].holdings.unrealized_profit
if current_float_profit >= .75 * self.credit_received:
self.liquidate(self.current_option_strategy)
self.credit_received = 0.0
def on_order_event(self, orderEvent):
if orderEvent.status == OrderStatus.FILLED:
self.has_position = False