| Overall Statistics |
|
Total Orders 3 Average Win 0% Average Loss -0.88% Compounding Annual Return -10.174% Drawdown 1.600% Expectancy -1 Start Equity 100000 End Equity 99156 Net Profit -0.844% Sharpe Ratio -3.5 Sortino Ratio -4.639 Probabilistic Sharpe Ratio 14.663% Loss Rate 100% Win Rate 0% Profit-Loss Ratio 0 Alpha -0.054 Beta 0.202 Annual Standard Deviation 0.036 Annual Variance 0.001 Information Ratio 1.775 Tracking Error 0.134 Treynor Ratio -0.631 Total Fees $2.00 Estimated Strategy Capacity $280000.00 Lowest Capacity Asset SPY Y4D62Z9A4X9I|SPY R735QTJ8XC9X Portfolio Turnover 0.06% |
# region imports
from AlgorithmImports import *
# endregion
class CryingRedOrangeKitten(QCAlgorithm):
def initialize(self):
self.set_start_date(2022, 11, 22)
self.set_end_date(2022, 12, 20)
self.underlying = self.add_equity("SPY", extended_market_hours=True)
self.option = self.add_option(self.underlying.symbol)
self.option.set_filter(lambda u: u.calls_only().strikes(0,1).expiration(0,31))
self.fixing_price = None
# added for fixing extended hours issue
self.set_security_initializer(MySecurityInitializer(self))
self.schedule.on(self.date_rules.every_day("SPY"), self.time_rules.at(16, 0,), self.calling_fixing_price)
# added for fixing extended hours issue
def calling_fixing_price(self) -> None:
self.fixing_price = self.underlying.close
self.Debug(f"fixing price at {self.Time} for {self.fixing_price}")
def on_data(self, data: Slice):
if not self.portfolio.invested:
chain = data.option_chains.get(self.option.symbol)
if chain:
self.market_order(list(chain)[0].symbol, 1)
class MySecurityInitializer(BrokerageModelSecurityInitializer):
def __init__(self, algorithm) -> None:
super().__init__(algorithm.brokerage_model, FuncSecuritySeeder(algorithm.get_last_known_prices))
self.algorithm = algorithm
def initialize(self, security: Security) -> None:
super().initialize(security)
if security.type == SecurityType.OPTION:
# security.set_option_exercise_model(MyOptionExerciseModel(self.algorithm))
option_exercise_model = MyOptionExerciseModel(self.algorithm)
option_exercise_model.update_fixing_price(self.algorithm.fixing_price)
security.set_option_exercise_model(option_exercise_model)
# This custom model implements the default model in LEAN (written in C#)
class MyOptionExerciseModel(DefaultExerciseModel):
def __init__(self, algorithm):
self.algorithm = algorithm
self.fixing_price = None # added for fixing extended hours issue
def update_fixing_price(self, price):
self.fixing_price_during_exercise = price # added for fixing extended hours issue
self.algorithm.Log(f"Updated fixing price to: {price}")
def option_exercise(self, option: Option, order: OptionExerciseOrder) -> List[OrderEvent]:
order_events = []
underlying = option.underlying
utc_time = Extensions.convert_to_utc(option.local_time, option.exchange.time_zone)
# added for fixing extended hours issue
in_the_money = option.is_auto_exercised(underlying.close)
#in_the_money = (self.fixing_price_during_exercise >= option.strike_price) if option.right == OptionRight.CALL else (self.fixing_price_during_exercise <= option.strike_price)
self.algorithm.Log(f"Exercising option: {option.symbol}, In-the-money: {in_the_money}, Fixing Price: {self.fixing_price}, Strike Price: {option.strike_price}, Origininal price {underlying.close}")
is_assignment = in_the_money and option.holdings.is_short
messages = Messages.DefaultExerciseModel
order_event = OrderEvent(
order.id,
option.symbol,
utc_time,
OrderStatus.FILLED,
Extensions.get_order_direction(order.quantity),
0,
order.quantity,
OrderFee.ZERO,
messages.contract_holdings_adjustment_fill_tag(in_the_money, is_assignment, option)
)
order_event.is_assignment = is_assignment
order_event.is_in_the_money = in_the_money
order_events.append(order_event)
if in_the_money and option.exercise_settlement == SettlementType.PHYSICAL_DELIVERY:
exercise_quantity = option.get_exercise_quantity(order.quantity);
order_event = OrderEvent(
order.id,
underlying.symbol,
utc_time,
OrderStatus.FILLED,
Extensions.get_order_direction(exercise_quantity),
option.strike_price,
exercise_quantity,
OrderFee.ZERO,
messages.option_assignment if is_assignment else messages.option_exercise
)
order_event.is_in_the_money = True
order_events.append(order_event)
return order_events