Generate code in 3 minutes
Enter your idea and AI generates runnable code.
To handle option exercise and assignment in QuantConnect, you primarily utilize the on_assignment_order_event and on_order_event event handlers.
When an option is exercised (either automatically at expiration or manually) or assigned (when you are short an option), the LEAN engine generates an order with the type OrderType.OPTION_EXERCISE.
The following algorithm demonstrates how to:
on_assignment_order_event.# region imports
from AlgorithmImports import *
# endregion
class OptionExerciseAssignmentAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2023, 1, 1)
self.set_end_date(2023, 6, 1)
self.set_cash(100000)
# Add the underlying equity
self.equity = self.add_equity("SPY", Resolution.MINUTE)
self.equity.set_data_normalization_mode(DataNormalizationMode.RAW)
self.symbol = self.equity.symbol
# Add Options
option = self.add_option("SPY", Resolution.MINUTE)
option.set_filter(-5, 0, 0, 30) # Look for OTM/ATM puts expiring within 30 days
self.option_symbol = option.symbol
def on_data(self, slice: Slice):
# Simple logic to open a Short Put position if we aren't invested
if not self.portfolio.invested and self.is_market_open(self.symbol):
chain = slice.option_chains.get(self.option_symbol)
if chain:
# Select an ATM Put
puts = [x for x in chain if x.right == OptionRight.PUT]
if not puts: return
# Sort by expiry and strike to find a near-the-money put
contract = sorted(puts, key=lambda x: abs(x.strike - x.underlying_last_price))[0]
# Sell 1 contract (Short Put)
self.market_order(contract.symbol, -1)
self.log(f"Sold Put: {contract.symbol} Strike: {contract.strike}")
def on_assignment_order_event(self, assignment_event: OrderEvent):
"""
This event handler is triggered specifically for Option Assignment events.
It allows you to handle the resulting equity position immediately.
"""
self.log(f"Assignment Detected: {assignment_event}")
# assignment_event.symbol is the Option Symbol.
# To get the underlying (Stock) symbol, we access the .underlying property.
option_symbol = assignment_event.symbol
underlying_symbol = option_symbol.underlying
# Check the resulting holdings of the Underlying Asset
underlying_holdings = self.portfolio[underlying_symbol]
if underlying_holdings.invested:
self.log(f"Assigned Stock Position: {underlying_holdings.quantity} shares of {underlying_symbol}")
# Example Logic: Liquidate the assigned stock immediately
# If we were Short Put, we are now Long Stock. We sell to close.
self.liquidate(underlying_symbol)
self.log(f"Liquidated assigned position for {underlying_symbol}")
def on_order_event(self, order_event: OrderEvent):
"""
Standard order event handler.
Useful for detecting automatic exercises of Long positions at expiration.
"""
if order_event.status == OrderStatus.FILLED:
# Check if this was an Option Exercise (applies to both Long Exercise and Short Assignment)
order = self.transactions.get_order_by_id(order_event.order_id)
if order.type == OrderType.OPTION_EXERCISE:
direction = "Assigned" if order_event.is_assignment else "Exercised"
self.log(f"{direction} on {order_event.symbol}. Fill Price: {order_event.fill_price}")
on_assignment_order_event(self, assignment_event)This is the preferred method for handling assignments. It isolates assignment logic from standard trading logic.
assignment_event contains details about the option contract.assignment_event.symbol.underlying) and liquidate the resulting stock position. This is common in strategies that want to capture the premium but do not wish to hold the stock.on_order_event(self, order_event)This handler catches all order updates. You can use it to detect exercises of Long positions (which on_assignment_order_event does not catch).
order.type == OrderType.OPTION_EXERCISE.order_event.is_assignment (boolean) to see if it was an assignment (Short) or an exercise (Long).self.exercise_option(option_symbol, quantity). This will also trigger on_order_event.When an option is assigned, you are purchasing (or selling) 100 shares of the underlying.
on_assignment_order_event or ensure your position sizing leaves enough margin room for potential assignment.Q: Does on_assignment_order_event trigger for Long options that expire ITM?
A: No. on_assignment_order_event is specifically for when you are Short and get assigned. For Long options that are exercised (automatically or manually), use on_order_event and check for OrderType.OPTION_EXERCISE.
Q: How do I stop LEAN from automatically exercising my Long options at expiration?
A: By default, LEAN exercises ITM options at expiration. To disable this, you can set the option assignment model in initialize:
option.set_option_exercise_model(DefaultExerciseModel()) is the default. You would need to implement a custom model or simply liquidate your options before market close on the expiration date to avoid exercise.
Q: What happens to my cash when I am assigned a Put?
A: When assigned a Short Put, you are forced to buy shares. Your cash balance will decrease by Strike Price * 100 * Contracts, and your portfolio will show a Long position in the underlying stock.
Q: Can I partially exercise an option?
A: Yes, if you hold multiple contracts. The self.exercise_option(symbol, quantity) method allows you to specify the quantity. However, assignment (when you are short) is random and determined by the brokerage/exchange simulation; you cannot control "partial" assignment, though you may be assigned on only a portion of your short contracts.