工程与管理交易系统架构安全决策

统一风控闸门: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 压力储备

这是最有趣的一个检查。逻辑:

  1. 找出当前持仓中浮亏最大的 TOP3 标的
  2. 假设它们再跌 6 个标准差(history low 6σ)
  3. 计算需要的 margin 缓冲
  4. 如果剩余保证金不够覆盖这个缓冲 → DENY

这跟广告系统的”预算预留”一模一样:OCPC 出价不只是看当前消耗,还要预留一部分预算给高转化时段的流量。你不会因为下午 CTR 高就把全天的预算在上午花光。


Shadow mode 首发

ARE 同样先跑 shadow mode。原因很简单:风控引擎本身也是一个 bug 来源。 如果 ARE 错误地 DENY 了正常交易,线上策略会莫名其妙地不开仓——比没有风控更难排查。

Shadow mode 的做法:

  • 正常交易走旧风控(各策略自己的逻辑)
  • ARE 在旁路计算 ALLOW/DENY/SHADOW 并记录日志
  • 对比新旧风控的决策差异
  • 确认无显著差异后切换

这和广告系统的”新旧策略 AB 对比”一样:新策略先不生效,只记录 would_have_bidwould_have_won,确认无异常再切。


统一后的收益

维度之前(各策略自建风控)之后(ARE 统一)
一致性3 个策略 3 套逻辑1 套逻辑
维护改一个规则改 3 处改 1 处
可见性风控日志分散统一 shadow log,一目了然
事故溯源”这个策略为什么开了这笔?“查 ARE 决策日志
新增策略需要自己实现风控直接接入 ARE

一句话总结收益:以前每个新策略上线要写 3 天业务代码 + 1 天风控代码,现在风控 0 天。


教训

  1. 分散的风控不是风控。 当每个策略各自实现风控时,一致性必然被破坏。总有一个人忘了检查某一条规则。
  2. 风控引擎本身需要灰度。 错误的 DENY 和错误的 ALLOW 一样致命。Shadow mode 让 ARE 先旁路验证,确认无误再接管。
  3. 压力测试要动态算。 HL-6 不是固定的 10% 或 20%,而是基于当前持仓动态计算——因为风险敞口每分钟都在变。固定的阈值要么太保守(浪费机会),要么太激进(不够安全)。

一句话:统一风控闸门 = 所有决策走同一个 gate,类比广告系统的 Budget Pacer——不管你是哪个策略,预算花完了就停了。