Bracket Orders and OCO Orders Explained
What is a bracket order? How the profit target and the protective stop link as OCO, what happens on a partial fill, and where that linkage actually sits.
A bracket order is one instruction that ships three orders in a fixed relationship: an entry, plus a linked exit pair that sits on either side of it. The pair is the OCO, short for one cancels the other. A profit-target limit rests above the entry price and a protective stop rests below it, and a fill on either leg cancels the other automatically. A bracket is really a small state machine, and most of the surprises live in the moments between its states.
What is a bracket order?
Picture a trader who wants to buy 200 shares near $50, close the position near $53 if it works, and step out near $48.50 if it does not. Written as separate tickets that is three orders and a manual chore: cancel the stop the moment the target fills, or risk selling 200 shares twice. A bracket packages the same intent as one submission. The entry is an ordinary market order or limit order. The two exits are its children: a limit to close at the target, and a stop or stop limit order to close at the protective level.
The vocabulary varies. Bracket, attached order, OCO bracket, and OTOCO all describe this shape. OTOCO, one triggers a one-cancels-the-other, is the most literal name for the sequence: the entry activates the pair, then the pair cancels itself down to one.
What does OCO mean in a bracket order?
An OCO is two resting orders with a cancel link between them. Both sit live in the book at the same time. When one fills, the other is pulled. When one fills partially, the other is reduced by the filled quantity instead of being pulled outright, and that reduction is what keeps a position and its protection matched share for share.
The full sequence for a 200-share long bracket runs like this.
- The entry works alone. The target and the stop exist inside the broker's system but are not working orders, so a print through the target price while the entry is unfilled does nothing at all.
- The entry fills for 200 shares. Both children go live, each for 200 shares.
- Trading reaches the stop price. The stop converts into a live sell order and works into the book.
- The stop fills 120 shares before the market moves away. The target limit is reduced from 200 to 80, matching the position that remains.
- Those last 80 shares fill at the target later in the session. The stop's leftover 80 is cancelled and the bracket closes out.
Partial fills on the entry are where platforms diverge most. Some brokers activate the children for the filled quantity right away and grow them as the rest of the entry completes. Others wait for the entry to fill in full, which leaves the position unprotected in the interval. Semantics differ by broker in ways that are not cosmetic: whether children activate on a partial entry fill, and whether editing one child breaks the cancel link on the other.
How far apart do the two legs sit?
Both legs have to sit outside the noise a name makes on an ordinary day and inside the distance it can actually travel. Daily range is the first crude measure of that. The panel below reads six household names over the trailing year: the median high-to-low range as a percent of the open, next to the median absolute move from the open to the close.
The exact SQL behind every number
SELECT
ticker,
round(quantileDeterministic(0.5)(
(toFloat64(high) - toFloat64(low)) / toFloat64(open) * 100,
toUInt32(date)), 2) AS median_range_pct,
round(quantileDeterministic(0.5)(
abs(toFloat64(close) - toFloat64(open)) / toFloat64(open) * 100,
toUInt32(date)), 2) AS median_open_to_close_pct
FROM global_markets.stocks_daily_aggs
WHERE ticker IN ('SPY', 'AAPL', 'MSFT', 'NVDA', 'KO', 'JNJ')
AND date >= today() - 370
AND date < today() - 2
GROUP BY ticker
ORDER BY median_range_pct DESCNVDA carries the widest typical session of the six at 2.72%, and SPY the narrowest at 0.86%. Notice how far the second column sits below the first on every row. A typical name travels a good deal further during a session than it nets from open to close, and both bracket legs live inside that travel. A target and a stop can each be reachable on the same ordinary day.
How often does a bracket leg get touched?
Distance from the entry is the dial a trader actually controls. The next panel pins the question to three fixed years of SPY sessions and asks, for a set of distances from the opening print, what share of sessions reached that far down and what share reached that far up at some point in the day.
The exact SQL behind every number
SELECT
concat(toString(d.dist), '%') AS distance_from_open,
round(100 * countIf(
(toFloat64(a.open) - toFloat64(a.low)) / toFloat64(a.open) * 100 >= d.dist
) / count(), 1) AS reached_below_pct,
round(100 * countIf(
(toFloat64(a.high) - toFloat64(a.open)) / toFloat64(a.open) * 100 >= d.dist
) / count(), 1) AS reached_above_pct
FROM global_markets.stocks_daily_aggs AS a
CROSS JOIN
(
SELECT arrayJoin([0.25, 0.5, 1.0, 1.5, 2.0, 3.0]) AS dist
) AS d
WHERE a.ticker = 'SPY'
AND a.date >= '2023-08-01'
AND a.date < '2026-08-01'
GROUP BY d.dist
ORDER BY d.distAt a quarter of a percent from the open, 62.3% of sessions traded that far down at some point and 64.7% traded that far up. Widen the distance to 3% and the downside figure falls to 0.5%. The two curves decay together, which is the whole tension in bracket sizing. A tight stop is a stop that gets taken out on unremarkable days. A distant target is a target that mostly expires unfilled.
Does a stop loss always fill at the stop price?
No. A stop is an instruction to send an order once a trigger price prints. A plain stop sends a market order, and the fill lands wherever the book happens to be at that instant. A stop limit sends a limit order at a price you set, which defends the price and accepts the risk of no fill at all. That trade-off is the subject of stop order versus stop limit order.
The overnight gap is the clearest case. A protective stop rests through hours when the exchange is closed, and the opening print can land well past the trigger. Ten examples from AAPL over three and a half years:
The exact SQL behind every number
SELECT
formatDateTime(session_date, '%b %e, %Y') AS gap_label,
round((day_open / prev_close - 1) * 100, 2) AS overnight_gap_pct
FROM
(
SELECT
session_date,
day_open,
lagInFrame(day_close) OVER (
ORDER BY session_date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
) AS prev_close
FROM
(
SELECT
date AS session_date,
toFloat64(any(open)) AS day_open,
toFloat64(any(close)) AS day_close
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'AAPL'
AND date >= '2023-01-01'
AND date < '2026-07-01'
GROUP BY date
)
)
WHERE prev_close > 0
ORDER BY overnight_gap_pct ASC
LIMIT 10The largest of them measured -9.45% on Aug 5, 2024, and the tenth on the list still measured -2.96%. A protective stop resting anywhere inside those gaps converted at the opening print, not at its trigger price. Sizing a bracket from intraday range alone leaves that distance unmodelled.
Where does the OCO link actually live?
Almost never at the exchange. The cancel link between two children is held in the broker's order-management system, or one layer further out in a trading platform running on your own machine. The exchange sees two ordinary, unrelated orders.
That placement decides what survives an outage. A broker-side bracket keeps working when the laptop closes, since the broker's servers hold both legs and the cancel logic. A platform-side bracket, the kind some charting applications implement locally, needs the application running and connected. Some platforms hold a simulated stop that exists only in local memory until the trigger price prints. Close the laptop and that stop is never sent.
The same question applies to your own code. A stop that lives only inside a running process leaves nothing resting in the book once the process stops. Circuit breakers for trading bots covers the pattern for automated systems: assume the process dies at the worst possible moment, then ask what is still working at the broker.
Time in force applies to each leg
Every leg carries its own time in force setting. A day entry paired with GTC children is a common and awkward combination: the entry expires at the close while the children never activate, leaving a bracket that quietly does nothing the next morning. The reverse pairing leaves protection that expires at 4:00 p.m. ET on a position carried overnight.
Outside regular hours the book itself changes character. The panel below buckets SPY minute bars by ET clock time across the full day and reads two things per half hour: the average size of a one-minute move, in basis points (one basis point is a hundredth of a percent), and the median volume printed in a minute.
The exact SQL behind every number
SELECT
formatDateTime(
toStartOfInterval(toTimeZone(window_start, 'America/New_York'), INTERVAL 30 MINUTE),
'%H:%i') AS et_time,
round(avg(abs(toFloat64(close) - toFloat64(open)) / toFloat64(open) * 10000), 1) AS avg_move_bps,
round(quantileDeterministic(0.5)(toFloat64(volume), toUInt64(window_start)), 0) AS median_volume
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= today() - 120
AND window_start < today() - 2
GROUP BY et_time
ORDER BY et_timeThe panel returns 32 half-hour buckets, from 04:00 through 19:30 ET. Read it left to right and the shape does the teaching. Both series sit near their floor through the premarket hours, climb steeply into the 09:30 open, and fall away again after 16:00. A GTC stop resting at 5 a.m. is resting in the thin part of that curve, and a stop-market fill in a book that thin can land a long way from the trigger.
FAQ
What is the difference between a bracket order and an OCO order?
An OCO is the pair itself: two resting orders with a cancel link, where a fill on one removes the other. A bracket is an entry order with an OCO pair attached, and the pair only goes live once the entry fills. Every bracket contains an OCO. Plenty of OCO pairs are used on their own.
Does a bracket order still work if my computer is off?
It depends on where the linkage sits. A broker-side bracket rests on the broker's servers and keeps working with the platform closed. A platform-side or simulated bracket needs the application running and connected, and the child orders may never reach the market without it.
What happens to the stop if the profit target fills partially?
The stop is reduced by the filled quantity rather than cancelled. If a 200-share target fills 60 shares, the stop drops to 140 shares, matching the position still open. The cancel fires only when the last of the position is closed.
Can I use a bracket order in premarket or after-hours trading?
Behaviour varies by broker, and many route bracket children during regular hours only. Stop orders in particular are often rejected or held outside 9:30 a.m. to 4:00 p.m. ET on US equities. The time-in-force setting on each leg governs whether that leg is eligible for the extended session at all.
Do exchanges know that my two orders are linked?
No. In US equities the cancel link is held by the broker or the platform, and the exchange receives two independent orders. The cancel message for the surviving leg is sent by whichever system holds the link, after the other leg reports its fill.
Every panel here ships with the exact SQL underneath it. To measure the range and the gap risk on a name you follow, ask the question in plain English on the Strasmore terminal.