交易机器人熔断机制与单日亏损上限
了解交易机器人如何通过熔断器限制亏损、动态调整仓位,并查看单日亏损限额触发频率,找到更可靠的风险控制方法。
交易机器人熔断机制是指:当达到预设限值时,阻止自动化策略继续发出订单的规则。它位于策略与经纪商之间的风险控制层,并对每笔订单执行,无论策略是否同意。策略决定交易什么。风险控制层决定是否允许交易。
这种分离是整个设计的核心。由策略自行监管,意味着当策略自身的假设失效时,没有独立的检查机制。而这正是检查最有价值的时刻。
交易机器人中的熔断器功能
风险控制层包含四个部分。每个部分都用于防止一种具体但常见的故障。
- 对持仓规模、单个证券代码的名义敞口和下单频率设置硬性上限。这样可以限制程序错误造成的损失,避免损失无限扩大。
- 设置回撤熔断器。当账户在本交易时段内亏损达到规定金额,或从权益峰值回撤达到规定金额时,停止提交新订单。
- 使用动态调整的下单规模。根据近期波动率,或凯利下注比例的一部分设定下单规模,而不是固定股数。这样即使市场波动区间发生变化,也能大致维持每笔交易的风险水平。
- 建立记录每项决策的追加式审计日志,包括被风险控制层拒绝的订单。只有这份记录能区分“策略判断错误”和“检查根本没有执行”。
下面的内容都属于上述四个部分之一,并将进一步说明其具体实现。
交易机器人的合理单日亏损上限是多少?
单日亏损上限会在当日交易时段的亏损超过阈值后,暂停提交新订单。阈值的设定取决于校准,而不是个人偏好:如果将其设在正常市场噪声范围内,机器人多数星期都会处于暂停状态;如果设得远高于正常波动,它又几乎不会触发。设定的起点,是观察市场本身出现特定幅度下跌日的频率。
每个数字背后的完整 SQL
WITH daily AS (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
argMax(toFloat64(close), window_start) AS close_px
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2017-12-01')
AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY d
),
with_prev AS (
SELECT d,
close_px,
any(close_px) OVER (ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_close
FROM daily
)
SELECT toYear(d) AS year,
countIf(close_px / prev_close - 1 <= -0.01) AS down_1pct_days,
countIf(close_px / prev_close - 1 <= -0.02) AS down_2pct_days,
countIf(close_px / prev_close - 1 <= -0.03) AS down_3pct_days
FROM with_prev
WHERE prev_close > 0
AND d >= toDate('2018-01-01')
GROUP BY year
ORDER BY year全年大约有 250 个交易日,其中下跌 1% 或以上的交易时段,在 15 和 2019 中分别有 45 和 2020 个。下跌 3% 或以上的情况则完全不同:0 中有 2019 个,而 16 中有 2020 个。9 的最后一行仅涵盖截至 2026 年 7 月 31 日的交易时段。
这条分布曲线并不平滑,而是呈现出明显的聚集性。这种聚集性正是设计时需要考虑的重点。剧烈下跌往往会连续出现。如果机器人在一轮连续剧烈波动的第一天暂停、第二天恢复交易,那么它实际上并没有真正暂停。
两个阈值承担不同职能。单日亏损上限通常设为账户净值的 2%,用于结束当日交易。以净值历史高点为基准计算的移动回撤上限通常约为 10%,触发后暂停策略,等待人工审查。前者用于处理日常风险,后者应当很少触发。如果机器人只有单日亏损上限,账户可能每次下跌 2%,逐步损耗,却始终不会触发更高层级的风控机制。
波动率缩放如何改变头寸规模?
波动率目标策略根据近期实现波动率反向调整头寸规模:当日内波动区间扩大一倍时,头寸规模大致减半,从而将每笔交易的美元风险维持在相对稳定的水平。这里的实现波动率是日收益率标准差的年化值,其变化幅度往往超出多数人的预期。
每个数字背后的完整 SQL
WITH daily AS (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
argMax(toFloat64(close), window_start) AS close_px
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2023-12-01')
AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY d
),
rets AS (
SELECT d,
close_px / any(close_px) OVER (ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) - 1 AS ret
FROM daily
)
SELECT formatDateTime(toStartOfMonth(d), '%Y-%m') AS month,
round(stddevSamp(ret) * sqrt(252) * 100, 1) AS realized_vol_pct,
round(least(100.0, 1200.0 / (stddevSamp(ret) * sqrt(252) * 100)), 1) AS vol_target_size_pct
FROM rets
WHERE d >= toDate('2024-01-01')
AND isFinite(ret)
GROUP BY toStartOfMonth(d)
HAVING count() >= 15
ORDER BY toStartOfMonth(d)实现波动率按年化口径计算为 11.1%,分别对应 2024-01 和 12%,覆盖 2026-07 的 31 个月。第二列将每个读数转换为在12%波动率目标下的头寸规模,并以满仓为上限:100% 对应 2024-01,99.7% 对应 2026-07。策略相同,判断相同,但持有的股份数量可能大不相同。
凯利准则从另一个角度处理同一问题。它根据估计的优势和方差确定头寸规模,而不只是依据波动率。鉴于这两个输入值都来自有限样本估计,大多数系统化交易者只使用凯利仓位的一部分,例如二分之一凯利或四分之一凯利。凯利准则头寸规模详细说明了相关计算。
为什么交易机器人在止损后不断重新入场?
止损被触发,仓位平仓。九十秒后,入场条件再次成立,机器人重新入场,再次承受同样的亏损,如此反复。没有任何单个组件发生故障。策略按预设逻辑运行,止损也按预设逻辑执行,但账户仍在一轮轮往返交易中持续亏损。
交易频率直接取决于价格路径。本面板按交易时段统计:SPY从高于开盘价0.1%以上的位置跌至低于开盘价0.1%以上,或反向移动,分别发生了多少次。
每个数字背后的完整 SQL
WITH mins AS (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
window_start AS ts,
toFloat64(close) AS px
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2025-08-01')
AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
),
opens AS (
SELECT d, argMin(px, ts) AS open_px
FROM mins
GROUP BY d
),
zoned AS (
SELECT m.d AS d,
m.ts AS ts,
multiIf(m.px >= o.open_px * 1.001, 1,
m.px <= o.open_px * 0.999, -1,
0) AS zone
FROM mins AS m
INNER JOIN opens AS o ON m.d = o.d
),
flips AS (
SELECT d,
zone,
any(zone) OVER (PARTITION BY d ORDER BY ts ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_zone
FROM zoned
WHERE zone != 0
),
per_day AS (
SELECT d, countIf(prev_zone != 0 AND zone != prev_zone) AS crossings
FROM flips
GROUP BY d
)
SELECT formatDateTime(toStartOfMonth(d), '%Y-%m') AS month,
round(avg(crossings), 1) AS avg_crossings_per_session,
max(crossings) AS max_crossings_in_a_session
FROM per_day
GROUP BY toStartOfMonth(d)
ORDER BY toStartOfMonth(d)在2025-08年,SPY每个交易时段平均穿越该区间0.7次;在2026-07年,平均穿越1.5次。其中一个交易时段在2026-07记录了5次穿越。任何在价格位于某一水平线一侧时开仓、在另一侧触发止损的规则,都可能在单日内有这么多次触发机会。
四项机制可以限制这种情况。
- 每次止损后设置冷却期,以分钟或K线数量计。在此期间,该交易品种的新订单不得通过风险控制层。
- 设置单个交易品种的每日交易次数上限,将无限循环限制在可控范围内。
- 设置可锁定的暂停标志。每日亏损限额一旦触发,该标志便保持启用状态,直到由人工清除。
- 将该标志持久化保存于进程内存之外。监督程序重启崩溃的机器人时,会为其提供一个全新的状态;而防止这种“全新状态”正是设置该标志的目的。
最后一项最容易被忽视,即使其他措施都已正确实施也是如此。网格交易机器人本身就会按设计分层挂出订单,因此交易次数上限是承载风险控制的关键机制,而不是装饰性设置。
当机器人依据过时的价格源交易时,会发生什么?
停止更新的报价看起来仍然是一个数字。机器人读取该报价,并据此为订单定价,然后将订单发送到一个已经发生变化的市场。故障不会显现出来:系统不会抛出异常,也不会记录错误日志,只有事后才能发现成交结果异常。
最容易准确衡量的情况是隔夜跳空:已知价格数小时保持不变,但可交易价格已经发生变化。
每个数字背后的完整 SQL
WITH daily AS (
SELECT ticker,
toDate(toTimeZone(window_start, 'America/New_York')) AS d,
argMin(toFloat64(open), window_start) AS open_px,
argMax(toFloat64(close), window_start) AS close_px
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'KO', 'MSFT', 'AAPL', 'NVDA', 'TSLA')
AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2024-01-01')
AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY ticker, d
),
gaps AS (
SELECT ticker,
d,
open_px,
any(close_px) OVER (PARTITION BY ticker ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_close
FROM daily
)
SELECT ticker,
round(quantileDeterministic(0.5)(abs(open_px / prev_close - 1) * 100, cityHash64(ticker, d)), 2) AS median_gap_pct,
round(quantileDeterministic(0.95)(abs(open_px / prev_close - 1) * 100, cityHash64(ticker, d)), 2) AS p95_gap_pct,
round(max(abs(open_px / prev_close - 1) * 100), 2) AS max_gap_pct
FROM gaps
WHERE prev_close > 0
GROUP BY ticker
ORDER BY p95_gap_pct DESC按第95百分位跳空幅度计算,幅度最大的标的是 TSLA,为 4.41%;相比之下,KO 为 1%。大多数夜间的波动要小得多:两者的跳空中位数分别为 1.01% 和 0.24%。风险控制层正是为了应对尾部风险而设计的。在统计窗口内,TSLA 出现的单次最大跳空为 14.57%。这就是机器人依据一段时间前读取的价格采取行动时可能面对的价格距离。为什么股票会在隔夜跳空介绍了其中的运作机制。
防护措施成本很低。为风险控制层依据每个报价定价设置最大报价时效。对于日内策略,通常可设为几秒。除数据本身外,还应单独监测数据源的心跳信号,以区分连接静默和市场平静。将缺失数据视为停牌,而不是继续持有上一报价,因为机器人在没有价格的情况下也无法评估退出条件。
风险层应设置哪些硬性上限?
- 单个标的的最大名义金额,占账户净值的比例。将上限设为10%,可避免单个标的出现问题时拖累整个账户。
- 所有未平仓头寸的最大总名义金额。将其设为账户净值的100%,意味着不使用杠杆。这个决定应明确作出,而不是沿用券商的默认设置。
- 每分钟和每天的最大下单次数。对大多数零售策略而言,每分钟10笔订单已经足够宽松,同时也能在一分钟内限制失控循环。
- 单笔订单的最大规模,占该标的平均日成交量的比例。将上限设为1%,可避免机器人推动其试图交易的价格;平均日成交量是计算分母。
上述每一项都应属于风险层,而不是策略层。每一项都应在回测、模拟盘和实盘中走相同的代码路径。只有实盘存在的限制,等于没有经过测试的限制。
交易机器人审计日志需要包含哪些内容?
只追加日志会为每个决策写入一条记录,且永不修改或删除。每条记录都应包含时间戳、所使用的报价及其时效、运行过的每项限额检查及其判定结果、已发送的订单,以及经纪商的回复。被拒绝的订单与已成交订单一样,均应完整记录。
关键在于能够重建决策过程。一次糟糕的交易时段过去六周后,问题通常不是盈亏是多少,而是哪项检查通过了,以及当时使用了什么输入。如果没有记录输入,您最终只能根据市场状态重新推导机器人的状态。这与回测中的前视偏差犯的是同一个错误:使用系统在决策当时并未掌握的信息。
riskguard项目是这种分离设计的一种开源实现。它将限额检查放在策略调用的独立组件中,而不是把相关逻辑分散在策略本身。它只是多种设计方案之一,值得阅读,但不应未经评估就直接采用。无论您依赖哪种实现,都应固定使用带标签的版本,而不是默认分支。同一回测运行两次期间,分支内容可能发生变化;而一个悄然改变的风险层,甚至不如没有风险层。
为什么首次部署要在模拟交易经纪商上运行
经纪商适配器默认使用模拟交易,实盘交易则必须明确设置相应标志。这一设计有意防范一种常见错误:复制配置文件,或忘记覆盖环境变量,导致系统用真实资金提交真实订单。
模拟运行还会生成一项重要记录:风险层基于实时价格作出的决策日志。该日志显示哪些限额被触发,哪些没有触发。这是评估风险层的证据,与策略能否盈利是两个不同问题。投入真实资金前进行模拟交易介绍了模拟交易记录能够证明什么、不能证明什么;多智能体AI交易系统则说明,当多个智能体都能下单时,为何暂停交易的权限必须置于所有智能体之外。
交易机器人熔断机制常见问题
交易机器人中的熔断机制是什么?
这是风险层中的一项规则。当达到设定上限时,停止机器人发送新订单。触发条件通常是单日亏损阈值,或账户权益从峰值回撤达到一定幅度。该机制独立于交易策略,对每笔订单执行检查,并会持续处于触发状态,直到被明确解除。
市场出现单日下跌 2% 的频率有多高?
SPY 在 2019 年有 5 个交易日下跌 2% 或更多,在 2020 年有 25 个交易日下跌 2% 或更多。两年每年约有 250 个交易日。平静年份与压力年份之间的差异,说明亏损限额应根据历史数据校准,而不是凭直觉设定。
如何防止机器人在止损后重新入场?
每次触发止损后设置冷却窗口,并设定单个标的的每日交易次数上限,可将无限循环限制在可控范围内。暂停标志还必须锁存,并持久化到进程内存之外。否则,监督程序重启崩溃的机器人时,机器人会获得一个全新且未暂停的状态。
机器人如何判断价格数据源是否已失效?
机器人应在根据报价进行订单定价前,检查每个报价的更新时间;同时,还应独立监测数据源的心跳信号。隔夜跳空可以说明陈旧价格可能掩盖多大的风险:2024 年 1 月至 2026 年 7 月期间,隔夜价格变动的第 95 百分位在 TSLA 达到 4.41%。
小型交易机器人真的需要审计日志吗?
成交日志记录实际发生的情况。决策日志记录机器人认为自己获准执行的操作。只有这样,才能区分错误的交易策略和根本未运行的风险检查。最低限度的实用版本应采用只追加方式,并记录被拒绝的订单。
以上每个数据均来自基于分钟线的存储查询,每个图表面板都可以打开其背后的 SQL。您可以在 Strasmore terminal 中对自己的标的列表运行相同的查询。