统一风控闸门:Account Risk Engine 的设计思路
某量化交易系统有多个策略:趋势追踪、网格反转、动量做空、事件驱动。每个策略入场前要做一堆检查:当前总敞口多少、保证金够不够、这个标的有没有风险敞口上限、HL-6 压力测试会不会击穿。
问题是——每个策略都自己写了一遍这些检查。
分散的风控 = 不一致的风控。有人检查了保证金没检查敞口,有人检查了敞口但用的是旧数据。一次 GRASS 事故(某个策略的风控绕过导致超额开仓)直接推动了统一风控引擎的立项。
这就是 ARE(Account Risk Engine)的由来。
设计目标
三类策略统一使用同一个 pre-trade 闸门:
| 策略类型 | 特点 | 风控需求 |
|---|---|---|
| Sniper(短线) | 高频、小仓位、快进快出 | 频率控制 + 单笔上限 |
| Swing(波段) | 中等频率、中等仓位 | 敞口叠加 + 保证金占用 |
| Equity(现货) | 低频、大仓位 | 集中度风险 + 流动性 |
统一后:所有策略在开仓前都走同一个 riskGate.check(),返回 ALLOW / DENY / SHADOW。
类比广告系统:所有广告在出价前都走同一个预算控制模块(Budget Pacer)。不管你是搜索广告还是信息流广告,预算花完了就停止出价——不会出现”搜索广告预算超了但信息流还在投”的情况。
核心架构
策略层 (Sniper / Swing / Equity)
│
│ 开仓请求 (symbol, size, side, strategy)
▼
ARE pre-trade gate
│
├─ 1. 账户总敞口检查 (total exposure vs equity)
├─ 2. 单标的敞口上限 (per-symbol exposure cap)
├─ 3. 保证金占用投影 (margin projection)
├─ 4. HL-6 压力储备 (TOP3 最大亏损标的的 margin 缓冲)
└─ 5. 策略级速率限制 (per-strategy rate limiter)
│
▼
ALLOW / DENY / SHADOW
HL-6 压力储备
这是最有趣的一个检查。逻辑:
- 找出当前持仓中浮亏最大的 TOP3 标的
- 假设它们再跌 6 个标准差(history low 6σ)
- 计算需要的 margin 缓冲
- 如果剩余保证金不够覆盖这个缓冲 → DENY
这跟广告系统的”预算预留”一模一样:OCPC 出价不只是看当前消耗,还要预留一部分预算给高转化时段的流量。你不会因为下午 CTR 高就把全天的预算在上午花光。
Shadow mode 首发
ARE 同样先跑 shadow mode。原因很简单:风控引擎本身也是一个 bug 来源。 如果 ARE 错误地 DENY 了正常交易,线上策略会莫名其妙地不开仓——比没有风控更难排查。
Shadow mode 的做法:
- 正常交易走旧风控(各策略自己的逻辑)
- ARE 在旁路计算 ALLOW/DENY/SHADOW 并记录日志
- 对比新旧风控的决策差异
- 确认无显著差异后切换
这和广告系统的”新旧策略 AB 对比”一样:新策略先不生效,只记录 would_have_bid 和 would_have_won,确认无异常再切。
统一后的收益
| 维度 | 之前(各策略自建风控) | 之后(ARE 统一) |
|---|---|---|
| 一致性 | 3 个策略 3 套逻辑 | 1 套逻辑 |
| 维护 | 改一个规则改 3 处 | 改 1 处 |
| 可见性 | 风控日志分散 | 统一 shadow log,一目了然 |
| 事故溯源 | ”这个策略为什么开了这笔?“ | 查 ARE 决策日志 |
| 新增策略 | 需要自己实现风控 | 直接接入 ARE |
一句话总结收益:以前每个新策略上线要写 3 天业务代码 + 1 天风控代码,现在风控 0 天。
教训
- 分散的风控不是风控。 当每个策略各自实现风控时,一致性必然被破坏。总有一个人忘了检查某一条规则。
- 风控引擎本身需要灰度。 错误的 DENY 和错误的 ALLOW 一样致命。Shadow mode 让 ARE 先旁路验证,确认无误再接管。
- 压力测试要动态算。 HL-6 不是固定的 10% 或 20%,而是基于当前持仓动态计算——因为风险敞口每分钟都在变。固定的阈值要么太保守(浪费机会),要么太激进(不够安全)。
一句话:统一风控闸门 = 所有决策走同一个 gate,类比广告系统的 Budget Pacer——不管你是哪个策略,预算花完了就停了。