Bracket订单与OCO订单详解
了解Bracket订单是什么、获利目标与保护性止损如何通过OCO关联、部分成交时订单数量如何调整,以及这种关联实际存在于哪里。
Bracket订单是一条同时提交三笔订单的指令,三者之间设有固定关系:一笔入场单,加上位于入场价两侧、彼此关联的一对出场单。这对出场单就是OCO,即“一个成交,另一个取消”。获利目标限价单挂在入场价上方,保护性止损单挂在入场价下方;任一腿成交后,另一腿会自动取消。Bracket本质上是一个小型状态机,大多数意外都发生在状态切换之间。
什么是Bracket订单?
设想一名交易者希望在接近50美元处买入200股。如果交易顺利,股价接近53美元时平仓;如果走势不利,则在接近48.50美元时离场。若分别下单,这需要三笔订单,还需要手动处理:目标单成交后立即取消止损单,否则可能将200股卖出两次。Bracket将同一交易意图打包成一笔提交。入场单是普通的市价单或限价单。两笔出场单是它的子订单:一笔是在目标价平仓的限价单,另一笔是在保护价位平仓的止损单或止损限价单。
术语因平台而异。Bracket、附加订单、OCO bracket和OTOCO都描述这种结构。OTOCO,即“一个触发另一个,且一个取消另一个”,是对该流程最直观的称呼:入场单激活这对出场单,随后这对订单通过相互取消,最终只保留一笔。
Bracket订单中的OCO是什么意思?
OCO是两笔相互设有取消链接的待执行订单。两笔订单会同时在订单簿中生效。一笔成交后,另一笔被撤销。一笔部分成交时,另一笔不会直接撤销,而是按已成交数量相应减少。这样可以让持仓和保护性订单逐股匹配。
一笔200股多头Bracket的完整流程如下。
- 入场单单独生效。目标单和止损单存在于券商系统中,但尚未成为生效订单。因此,入场单尚未成交时,即使成交记录穿过目标价,也不会发生任何事情。
- 入场单成交200股。两笔子订单均生效,各自数量为200股。
- 市场触及止损价。止损单转化为生效卖单,并进入订单簿执行。
- 止损单在市场转向前成交120股。目标限价单的数量从200股减少至80股,与剩余持仓相匹配。
- 当日稍晚,剩余80股在目标价成交。止损单剩余的80股被取消,Bracket完成。
入场单部分成交时,各平台的处理差异最明显。有些券商会立即按已成交数量激活子订单,并随着入场单继续成交而增加子订单数量。另一些券商会等入场单全部成交后才激活子订单,这会使持仓在此期间没有保护。不同券商的规则差异并非表面问题,包括子订单是否会在入场单部分成交后激活,以及修改一笔子订单是否会破坏另一笔订单的取消链接。
两条腿之间应相距多远?
两条腿都应避开标的在普通交易日中的噪声,同时处于其实际可能达到的波动范围内。日内区间是最初步的衡量方法。下方面板统计了六只常见股票过去一年的数据:中位数最高价至最低价区间占开盘价的百分比,以及开盘价至收盘价绝对变动的中位数。
每个数字背后的完整 SQL
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的典型日内区间在六只股票中最宽,为2.72%;SPY最窄,为0.86%。注意每一行中,第二列都明显低于第一列。标的一般在交易日内的实际波动幅度,远大于其从开盘到收盘的净变动,而Bracket的两条腿都处于这一波动范围内。在普通交易日中,目标价和止损价都可能被触及。
Bracket的一条腿有多大概率被触及?
入场价与订单价格之间的距离,是交易者真正可以控制的参数。下一个面板将问题限定在SPY连续三个完整年度的交易日内,并考察一组相对于开盘成交价的固定距离:当天价格向下达到该距离的交易日占比,以及向上达到该距离的交易日占比。
每个数字背后的完整 SQL
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.dist当距离开盘价为百分之零点二十五时,62.3%的交易日曾向下达到该距离,64.7%的交易日曾向上达到该距离。将距离扩大至3%后,下行数据降至0.5%。两条曲线同步下降,这正是Bracket设置的核心矛盾。止损价过近,就容易在普通交易日被触发。目标价过远,则大多会在未成交的情况下到期。
止损单总能在止损价成交吗?
不能。止损单的作用,是在触发价出现成交记录后发送订单。普通止损单会发送市价单,成交价取决于当时订单簿中的实际价格。止损限价单会在设定价格发送限价单,这样可以控制价格,但也可能完全无法成交。这一取舍详见止损单与止损限价单。
隔夜跳空是最典型的情况。保护性止损单会在交易所闭市期间持续挂单,而开盘成交价可能远远超过触发价。以下是AAPL在三年半期间的十个例子:
每个数字背后的完整 SQL
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 10其中最大跳空出现在Aug 5, 2024,幅度为-9.45%;榜单上的第十个案例仍达到-2.96%。保护性止损单若位于这些跳空区间内的任何位置,都会在开盘成交价处触发,而不是在触发价成交。仅根据日内区间设置Bracket,会忽略这段风险距离。
OCO链接实际上位于哪里?
几乎从不在交易所。两笔子订单之间的取消链接由券商的订单管理系统维护,或者由运行在您自己设备上的交易平台在更外层维护。交易所看到的是两笔普通且互不关联的订单。
这一位置决定了系统故障时哪些部分仍会运行。券商端Bracket由券商服务器持有两条腿及取消逻辑,因此即使笔记本电脑关闭,订单仍可继续运行。平台端Bracket则不同。一些图表应用在本地执行此类Bracket,需要应用保持运行并连接网络。有些平台会将模拟止损单仅保存在本地内存中,直到触发价出现才发送。关闭笔记本电脑后,这笔止损单就永远不会被发送。
同样的问题也适用于您自己的代码。如果止损逻辑只存在于正在运行的进程中,那么进程停止后,订单簿中不会留下任何挂单。交易机器人熔断机制介绍了自动化系统的处理方式:假设进程会在最糟糕的时刻停止,然后检查券商端仍有哪些订单在运行。
有效期适用于每一条腿
每条腿都有自己的有效期设置。入场单设置为当日有效,而子订单设置为GTC,是一种常见但不理想的组合:入场单在收盘时到期,子订单从未激活,于是Bracket第二天早上会悄无声息地失效。反过来设置,则会使保护性订单在隔夜持仓时于美东时间下午4:00到期。
在常规交易时段之外,订单簿本身也会发生变化。下方面板按美东时间将SPY全天的分钟K线分组,并对每个半小时统计两项数据:一分钟变动的平均幅度,以基点表示(一个基点是百分之零点零一);以及一分钟内成交量的中位数。
每个数字背后的完整 SQL
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_time该面板涵盖32个半小时区间,时间范围从美东时间04:00至19:30。从左向右观察即可看出规律。两个序列在盘前时段都接近最低水平,在美东时间09:30开盘前后快速上升,16:00后再次回落。美东时间凌晨5点仍挂着的GTC止损单,处于这条曲线的低流动性区域;在如此稀薄的订单簿中,止损市价单的成交价可能远离触发价。
常见问题
Bracket订单与OCO订单有什么区别?
OCO本身就是那一对订单:两笔带有取消链接的待执行订单,其中一笔成交后,另一笔被撤销。Bracket则是附带OCO组合的入场订单,只有入场单成交后,这对出场单才会生效。每个Bracket都包含一个OCO,但许多OCO组合也会单独使用。
如果我的电脑关机,Bracket订单仍会运行吗?
这取决于链接位于哪里。券商端Bracket由券商服务器保存,即使交易平台关闭,订单仍会继续运行。平台端或模拟Bracket则需要应用保持运行并连接网络;没有应用,子订单可能根本无法进入市场。
如果获利目标单部分成交,止损单会怎样?
止损单会按已成交数量减少,而不是直接取消。如果200股目标单成交60股,止损单数量会降至140股,与仍在持有的仓位相匹配。只有当全部持仓都平仓后,取消操作才会执行。
可以在盘前或盘后交易时段使用Bracket订单吗?
不同券商的规则不同,许多券商只在常规交易时段路由Bracket子订单。特别是止损单,在美国股票市场美东时间09:30至16:00之外,通常会被拒绝或暂存。每条腿的有效期设置决定其是否有资格参与延长交易时段。
交易所知道我的两笔订单相互关联吗?
不知道。在美国股票市场,取消链接由券商或交易平台维护,交易所收到的是两笔相互独立的订单。当其中一笔订单报告成交后,保存该链接的系统会向交易所发送取消另一笔订单的消息。
本文每个面板下方都附有完整且准确的SQL代码。若要衡量您关注的标的的区间和跳空风险,请在Strasmore终端中用自然语言提出问题。