Skip to content

Fall back to per-leg margin when option strategy margin cannot be computed - #9682

Draft
jhonabreul wants to merge 2 commits into
QuantConnect:masterfrom
jhonabreul:bug-option-strategy-bp-fallback
Draft

Fall back to per-leg margin when option strategy margin cannot be computed#9682
jhonabreul wants to merge 2 commits into
QuantConnect:masterfrom
jhonabreul:bug-option-strategy-bp-fallback

Conversation

@jhonabreul

@jhonabreul jhonabreul commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Description

Algorithms legging into multi-leg option positions with sequential market orders could crash mid-run. The option strategy margin model threw when a position group's legs didn't fit the modeled strategy's shape:

Runtime Error: Sequence contains no matching element in OptionStrategyPositionGroupBuyingPowerModel.cs:line 516

Fix: OptionStrategyPositionGroupBuyingPowerModel falls back to margining each leg individually instead of throwing. Well-formed groups keep strategy margin.

  • GetMaintenanceMargin / GetInitialMarginRequirement catch InvalidOperationException and return per-leg margin sums, each leg margined through its own security's BuyingPowerModel.
  • The NotImplementedException tails for strategies without margin modeling (e.g. CallBackspread) use the same fallback.
  • The fallback is conservative (ignores leg offsets) and logs an error once per strategy/method.

Also unblocks the recommended atomic-entry path and hints at it:

  • OptionStrategy.OptionLegData gets a (quantity, right, strike, expiration, orderPrice = null) constructor, accepting Python date and datetime. Previously only a parameterless constructor existed, so building legs from Python failed.
  • OptionStrategy.Create and the OptionStrategy constructor no longer NRE on symbol-less legs.
  • QCAlgorithm.MarketOrder warns once per algorithm when an option market order is placed while holding other contracts of the same chain, suggesting ComboMarketOrder/OptionStrategies.

Related Issue

N/A

Motivation and Context

Legging into spreads with plain market orders is legitimate API usage. It should never dead-end an algorithm in an engine crash with no user-code workaround.

Requires Documentation Change

N/A

How Has This Been Tested?

  • New regression algorithm LeggedInOptionStrategiesMarginCallRegressionAlgorithm (C# + Python): legs into two spreads, forces a margin call, asserts full liquidation. Reproduces the crash before the fix, passes after, in both languages.
  • OptionStrategyPositionGroupBuyingPowerModelTests: new per-leg fallback tests for a degenerate group and an unmargined strategy — red before the fix, green after.
  • OptionStrategiesTests: new OptionLegData constructor tests, including construction from Python with date and datetime.
  • Full QuantConnect.Tests.Common.Securities suite: 5502 passed, 0 failed. AlgorithmTradingTests: 189 passed. Related option strategy regression algorithms all passed.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • Refactor (non-breaking change which improves implementation)
  • Performance (non-breaking change which improves performance. Please add associated performance test and results)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Non-functional change (xml comments/documentation/etc)

Checklist:

  • My code follows the code style of this project.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • My branch follows the naming convention bug-<issue#>-<description> or feature-<issue#>-<description>

…puted

Legging into multi-leg option positions with sequential market orders
hard-crashed algorithms with "Sequence contains no matching element"
when a margin call probed a degenerate trial position group, and matched
strategies without margin modeling (backspreads) threw
NotImplementedException. OptionStrategyPositionGroupBuyingPowerModel now
falls back to margining each leg individually instead of throwing,
logging the condition once.

Also adds an OptionLegData (quantity, right, strike, expiration)
constructor so strategy legs can be built from Python with either date
or datetime expiry, and a one-time hint suggesting combo orders when
market orders leg into option positions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant