option-strategies
Skill268 starsChanged 48 days agoApache-2.0View on GitHub
Use when placing or managing MULTI-LEG option positions and the option lifecycle in QuantConnect/LEAN — the `OptionStrategies` factory + `buy/sell` route, combo orders (`combo_market_order`, `combo_limit_order`, `combo_leg_limit_order`), position-group margin, early assignment, exercise, and expiry cleanup. Triggers — iron condor / straddle / strangle / spread / butterfly / calendar / collar / covered-call code; questions like "how do I place all four legs at once", "why was my short option assigned", "what happens to my position at expiry", "why did my algorithm stop trading after expiry". Skip when — chain subscriptions and greeks freshness (see equity-options), single-leg orders (see orders), historical option data (see historical-data-equity-options).
In this repository39 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- docs-styleSkill
- calendarSkill
- code-qualitySkill
- cryptoSkill
- data-exportSkill
- data-issuesSkill
- debug-algorithmSkill
- debug-performanceSkill
- equity-fundamental-dataSkill
- equity-optionsSkill
- futuresSkill
- historical-data-equity-optionsSkill
- historySkill
- indicatorsSkill
- loggingSkill
- option-strategiesSkill
- ordersSkill
- pricingSkill
- scheduled-eventsSkill
- universesSkill
- calendarSkill
- code-qualitySkill
- cryptoSkill
- data-exportSkill
- data-issuesSkill
- debug-algorithmSkill
- debug-performanceSkill
- equity-fundamental-dataSkill
- equity-optionsSkill
- futuresSkill
- historical-data-equity-optionsSkill
- historySkill
- indicatorsSkill
- loggingSkill
- ordersSkill
- pricingSkill
- scheduled-eventsSkill
- universesSkill
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 1 is distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 58
No expiry-slip state cleanup: position-tracking fields never cleared when contracts expire, permanently halting re-entry.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Option strategies and the option lifecycle — QuantConnect / LEAN
Placing multi-leg positions: two documented routes, no third
Route A — OptionStrategies factory + buy. One call builds the whole structure from the canonical option symbol (saved from option = self.add_option(...); self._symbol = option.symbol) plus strikes/expiries — no contract symbols needed, all legs placed atomically:
strategy = OptionStrategies.iron_condor(self._symbol, far_put, near_put, near_call, far_call, expiry)
self.buy(strategy, 2) # 2 condors; sell(strategy, q) inverts every legBoth directions of every structure have their own factory (straddle / short_straddle, iron_condor / short_iron_condor) and a "short_" factory is still placed with buy. The catalogue (snake_case members of OptionStrategies): bear/bull call/put spreads; long/short call/put butterflies (strike order higher, ATM, lower); long/short call/put calendar spreads ((strike, near_expiry, far_expiry)); covered/naked/protective calls and puts; protective collar; conversion/reverse conversion; long/short straddles and strangles; long/short iron butterflies and iron condors (strikes ascending); long/short box spreads; long/short jelly rolls; bear/bull call/put ladders; long/short call/put backspreads. Covered/protective/conversion structures embed the underlying — buying one unit of covered_call is long 100 shares + short 1 call.
Route B — combo orders. Build Leg.create(symbol, ratio) lists from actual contract symbols when you need custom ratios, a leg set no factory matches, or limit pricing:
legs = [Leg.create(short_call.symbol, -1), Leg.create(long_call.symbol, 1)]
tickets = self.combo_market_order(legs, quantity) # one ticket per leg- Leg quantities set the ratio; the order's
quantityargument is a global multiplier and sets the combo's direction. At least one positive and one negative leg; each leg a unique contract. combo_limit_order(legs, quantity, limit_price)— one net price for the package, legs fill together when the combined price crosses it; the only combo type documented to also accept an underlying-equity leg.combo_leg_limit_order— per-leg limits via the third argument ofLeg.create; each leg fills on its own limit. Both are updatable through the leg tickets until filled.- Combo orders are synchronous by default with a 5-second wait (extend via
self.transactions.market_order_fill_timeout); passasynchronous=Trueto fire-and-continue. Marketable combos on illiquid OTM contracts "may take a few minutes to fill".
There is no route C. Legging into a multi-leg structure with sequential single market orders is not a documented pattern: it carries leg risk (partial structures during fills) and the interim one-sided position can fail margin that the complete structure would pass. Single-leg strategies (naked call/put) are the one case where a plain market_order is the documented approach.
Margin: recognized structures are cheaper
LEAN groups positions that compose a recognized strategy and margins the group, not the legs — the docs' example: an ITM long call ($29,150) plus an OTM short call ($101,499) margin at $130,649 separately but $0 as a bull call spread. Defined-risk structures (spreads, condors, butterflies) are therefore dramatically cheaper than their leg-sums; don't pre-reject a trade by summing per-leg requirements. For a pre-trade check, wrap the strategy in OptionStrategyPositionGroupBuyingPowerModel(strategy) and query get_initial_margin_requirement(...) against self.portfolio.margin_remaining (the result is per one unit — multiply by your quantity).
Early assignment: an hourly simulation you must expect
Short American options in a backtest can be assigned before expiry. The default DefaultOptionAssignmentModel scans hourly and assigns a short option that is within 4 days of expiry, at least 5% in the money, and profitable to exercise after fees (European style: expiry day only). Any strategy holding short legs into that window (covered calls, short condors near expiry, diagonals) must handle assignment — or, when the strategy's rules exit before the window (e.g. manage-at-21-DTE), assignment simply never triggers. To disable the simulation deliberately: security.set_option_assignment_model(NullOptionAssignmentModel()) in a security initializer.
Handle assignment in on_assignment_order_event — not by sniffing is_assignment in the generic order-event handler. The docs' working examples read the just-delivered share position inside the dedicated handler (holdings are current there) and clean up immediately:
def on_assignment_order_event(self, assignment_event: OrderEvent) -> None:
shares = assignment_event.quantity * self._option.symbol_properties.contract_multiplier
self.market_order(assignment_event.symbol.underlying, -shares, tag="Assignment cleanup")Reacting from the generic on_order_event instead has been observed to fire before the delivered shares are booked, so a holdings-based cleanup silently does nothing until a later event. Note the delivered shares appear at the strike price via a fill event, simultaneous with a zero-price fill that removes the option contract; assignment after the close cannot be flattened until the next session's open regardless of handler.
Expiry: LEAN acts on the contracts, not on your state
At expiration LEAN auto-exercises long ITM positions ("Automatic Exercise": zero-price fill removing the contract + a strike-price fill delivering the underlying for physical settlement) and removes OTM contracts worthless. None of your exit logic runs. Any strategy that tracks its own open position (a self._position object, leg symbol fields) must clear that state when contracts expire — otherwise the algorithm believes a position is still open, its management checks keep early-returning on missing data, and it silently never trades again. If the strategy's rules are supposed to exit before expiry, treat reaching expiry as a bug signal, but still write the state-cleanup path. Manual exercise: self.exercise_option(contract_symbol, quantity) — long positions only, American any time, European only at expiry, rejected on insufficient capital.
Common mistakes
- Selling a
short_*factory (double inversion) — short factories are bought;sellon the long factory is the other spelling of the same trade. - Butterfly strike order: all four butterfly factories take (higher, ATM, lower) — the doc examples' variable names disagree with their own math; follow the order, not the names.
- Passing the underlying Equity symbol or a contract symbol as a factory's first argument — it must be the canonical option symbol.
- Summing per-leg margin to pre-check a defined-risk structure (position grouping makes the real requirement far lower).
- Assignment cleanup in the generic order-event handler reading holdings that aren't updated yet — use
on_assignment_order_event. - No expiry-slip state cleanup: position-tracking fields never cleared when contracts expire, permanently halting re-entry.
- Pairing route A with per-leg limit prices — factories place market executions; limit pricing needs route B.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

