Skip to content

feature: add one-cancels-the-other (OCO) order group - #9635

Draft
Romazes wants to merge 3 commits into
QuantConnect:masterfrom
Romazes:feature-8253-oco-order
Draft

feature: add one-cancels-the-other (OCO) order group#9635
Romazes wants to merge 3 commits into
QuantConnect:masterfrom
Romazes:feature-8253-oco-order

Conversation

@Romazes

@Romazes Romazes commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Description

Adds a one-cancels-the-other (OCO) order group. QCAlgorithm.OneCancelsTheOtherOrder places 2 or 3 Limit/StopMarket orders together: when one leg fully fills, the other legs are canceled in the same order-event batch. A partial fill does not cancel the siblings.

C#:

MarketOrder(_spy, 100);
var price = Securities[_spy].Price;
var tickets = OneCancelsTheOtherOrder(new List<Order>
{
    new LimitOrder(_spy, -100, price * 1.01m, UtcTime),      // take profit
    new StopMarketOrder(_spy, -100, price * 0.95m, UtcTime)  // stop loss
});

Python:

self.market_order(self._spy, 100)
price = self.securities[self._spy].price
tickets = self.one_cancels_the_other_order([
    LimitOrder(self._spy, -100, price * 1.01, self.utc_time),
    StopMarketOrder(self._spy, -100, price * 0.95, self.utc_time)
])

Main changes:

  • New ComboType enum on GroupOrderManager (Combo, OneCancelsTheOther). Previously serialized groups keep loading as Combo.
  • New IBrokerageModel.SupportsGroupExecution(ComboType) with a default body that only accepts Combo, so existing brokerage models (including Python ones) keep today's behavior. AlpacaBrokerageModel opts into OCO. In live trading the transaction handler rejects a group the brokerage model does not support; backtesting and paper trading simulate the group in the engine.
  • BacktestingBrokerage evaluates the legs of a group in a fixed order (stop legs first, then limit legs, then by id) and cancels the open siblings as soon as one leg fully fills.
  • Buying power and projected holdings do not double count OCO siblings: a same-symbol group only needs to afford its most expensive leg; a mixed-symbol group checks every leg on its own.
  • Liquidate and CancelOpenOrders issue one cancel per group instead of one per leg, since canceling one leg cancels the whole group.
  • ADR documents: 0001-bracket-order-type.md and 0002-one-cancels-the-other-order-group.md.

Related PR(s)

N/A

Related Issue

#8253

Motivation and Context

First step of the bracket order plan: OCO now, conditional (OTO) next, bracket on top of both. Users can protect a position with a take-profit and stop-loss pair without managing the cancellation themselves.

Requires Documentation Change

Yes — the new OneCancelsTheOtherOrder API needs documentation.

How Has This Been Tested?

  • New regression algorithms (C# and Python): OneCancelsTheOtherOrderRegressionAlgorithm (winner leg fills and the sibling cancels in the same event batch), OneCancelsTheOtherOrderCancelRegressionAlgorithm (canceling one leg cancels the whole group), plus OneCancelsTheOtherOrderDemoAlgorithm.
  • Unit tests: BacktestingBrokerageTests (group fill, cancel and invalid paths), AlgorithmTradingTests (submit validation), BrokerageTransactionHandlerTests (live support gate, projected holdings), SecurityPortfolioManagerTests and CashBuyingPowerModelTests (buying power), OrderJsonConverterTests and OrderTests (serialization round trip), PythonWrapperTests, AlpacaBrokerageModelTests, DefaultBrokerageModelTests.

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)
  • 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>

@Romazes
Romazes marked this pull request as draft July 24, 2026 15:34
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