OCO Orders
How one-cancels-other pairs link two orders so the first fill cancels the sibling.
OCO means one-cancels-other. It links two orders through a shared pair id so the first filled leg cancels the remaining sibling.
Source
backtester/execution/fill_engine.pyLayerOrder execution / sibling cancellation
ModeOrder mode
Inputtwo orders with shared
oco_pair_idOutputone filled order and one cancelled sibling
Primary API
Order(..., order_type=OrderType.OCO, oco_pair_id=...)Main caveatUse unique OCO ids per pair to avoid accidental cross-cancellation.
Level 1: Manual TP/SL Pair
Use bracket orders for normal TP/SL entry plans. Use OCO directly when you need manual control over pair construction.
Manual exit OCO
python
oco_id = f"exit_{inst}_{date}"
self.fill_engine.submit(Order(
instrument=inst,
side=OrderSide.SELL,
quantity=pos,
order_type=OrderType.OCO,
limit_price=round(entry_price * 1.08, 2),
oco_pair_id=oco_id,
))
self.fill_engine.submit(Order(
instrument=inst,
side=OrderSide.SELL,
quantity=pos,
order_type=OrderType.OCO,
stop_price=round(entry_price * 0.95, 2),
oco_pair_id=oco_id,
))Level 2: Dip Or Breakout Entry
OCO can also express competing entry hypotheses: buy the dip or buy the breakout, but not both.
Competing entry OCO
python
oco_id = f"entry_{inst}_{date}"
self.fill_engine.submit(Order(
instrument=inst,
side=OrderSide.BUY,
quantity=shares,
order_type=OrderType.OCO,
limit_price=round(bar.close * 0.98, 2),
oco_pair_id=oco_id,
))
self.fill_engine.submit(Order(
instrument=inst,
side=OrderSide.BUY,
quantity=shares,
order_type=OrderType.OCO,
stop_price=round(bar.close * 1.02, 2),
oco_pair_id=oco_id,
))Level 3: Clear Stale OCO Orders
If neither branch remains valid, cancel the pair.
Cancel stale OCO pair
python
if pos == 0 and not entry_window_is_open:
self.fill_engine.cancel_all(instrument=inst)
self._oco_live[inst] = FalseImplementation Rule
- Orders with the same
oco_pair_idare registered as siblings. - When one sibling fills,
_cancel_oco_pair()cancels every other active sibling. OrderType.OCObehaves as limit-style whenlimit_priceis set and stop-style whenstop_priceis set.
Failure Modes
- Reusing the same OCO id across instruments or dates.
- Forgetting to cancel OCO orders when the entry window expires.
- Using OCO where bracket is simpler and less error-prone.
- Assuming OCO models exchange-native order queue semantics.