可解释性:为什么没信号、为什么没下单(Blocking Reasons 体系)
很多量化系统的“可解释性”停留在:图上叠几条指标线、给你看一下买卖点。
但真实团队最常遇到的问题不是“为什么在这里买”,而是更致命的两句:
- 为什么没信号?
- 为什么没下单/没成交?
如果每次都靠翻日志、靠作者经验猜,团队协作会迅速变慢,策略交付也会变成不可规模化的“手艺活”。
结论先行:EasyQuant 把“没发生”这件事做成产品能力——用结构化原因码(Blocking Reasons)把问题归类、可统计、可视化,并给出下一步排查入口。
一、为什么“没发生”比“发生了”更难解释?
当策略产生一次买卖点,系统至少有结果可以讨论。
但当“什么都没发生”,背后可能是任意一层出了问题:
- Universe 没解析出来(无标的可交易)
- K 线缺失、时间戳异常、被交易时段过滤(无有效 bars)
- 调度没跑、或者同一根 bar 被去重跳过(重复评估被跳过)
- 指标/DSL 引擎异常(计算失败或规则错误)
- 有信号但被风控拒绝(额度/仓位/数据质量)
- 下单被通道拒绝(参数校验/不可交易状态)
如果这些问题都混在一坨日志里,你就无法形成“团队共识的排障路径”。
因此,交付型平台必须回答:问题属于哪一类?下一步该查哪里?
二、Blocking Reasons 的设计目标:把排障变成流程
EasyQuant 的 Blocking Reasons 体系设计目标很直接:
- 结构化:每次阻塞给出可枚举的
eventCode(原因码),而不是一句自由文本 - 可聚合:能按 24h/7d 统计 Top 原因,发现“系统性问题”而非个案
- 可定位:每个原因码都能指向下一步检查(页面/API/数据表)
- 可复用:同一套原因码既服务回测,也服务 paper,也服务准生产演进
这意味着:排障不再依赖“这个策略作者在不在”,而是任何人都能按 checklist 快速收敛问题范围。
三、原因码分层:从“现象”到“归因”
下面是一个推荐的分层理解方式(你不必一次性记全):
1)标的层:NO_SYMBOLS
含义:无可交易标的(Universe 为空/未绑定/被过滤)。
典型现象:策略运行事件里没有任何 code,或系统诊断直接提示无标的。
下一步怎么查
- 策略是否绑定 Universe?Universe 是否有成分?
- 筛选条件(交易时段/市场/黑白名单)是否把标的过滤掉?
2)数据层:NO_BARS / DATA_QUALITY_BLOCKED
含义:缺少 K 线数据,或数据质量不足(不新鲜、异常时间戳、缺字段)。
典型现象:回测无成交;策略长期 HOLD;bars 接口在区间内返回为空。
下一步怎么查
- 是否能查询到最近 bars(例如
GET /api/market/bars?...&limit=10) - 是否需要 backfill 或 seed demo 数据
- 交易时段过滤后是否仍有数据(非交易时段 bars 会被过滤)
3)调度与去重:DUP_EVAL_SKIPPED
含义:同一根 bar 重复触发,被去重跳过(避免重复下单)。
典型现象:你看到策略“在跑”,但没有任何新评估/新订单。
下一步怎么查
- 是否真的产生了新 bars(ts 是否变化)
- 当前策略的执行状态是否卡在某个
lastEvaluatedBarTs
4)版本与配置:VERSION_NOT_ACTIVE
含义:策略版本未激活(你改了草稿,但执行侧仍在用旧版本/模板)。
典型现象:策略行为不符合你刚改的规则;回测结果像“没生效”。
下一步怎么查
- 是否发布并激活了版本
- 回测/运行快照(provenance)中记录的 versionId 是否符合预期
5)信号层:SIGNAL_NONE
含义:规则未触发(不是错误,只是当前行情不满足条件)。
典型现象:数据正常、调度正常、无风控/通道拒绝,但就是没成交。
下一步怎么查
- 用策略图表回看触发点(买卖点标记)
- 检查指标参数(周期过长导致信号稀少、阈值过严)
6)引擎层:ENGINE_ERROR
含义:信号引擎异常(DSL/指标/运行时错误)。
典型现象:策略运行事件出现错误码或异常栈;指标计算失败。
下一步怎么查
- 查看运行事件(错误上下文)
- 缩小到最小 DSL,逐步恢复组件定位问题
7)风控/通道:RISK_REJECTED / BROKER_REJECTED
含义:有信号但被风控拒绝,或被通道拒绝。
典型现象:有下单意图但订单 REJECTED / 未成交。
下一步怎么查
- 风控命中明细(额度、仓位、数据质量等)
- 通道校验失败原因(价格/状态/参数)
四、如何在 UI 上使用它:先看 Top 原因,再看明细
建议团队形成统一的“排障顺序”(省时间):
- 系统是否健康(健康检查/服务状态)
- 系统状态页:阻塞原因 Top(24h)
- 如果某个原因长期 Top1/Top2,说明是系统性问题(例如缺 bars、Universe 配置问题)
- 策略中心:运行事件列表
- 找到具体策略的 eventCode 与上下文
- 回测中心:回测详情页
- 看是否交易了多个标的、bars 是否正常、买卖点是否符合预期
这条路径的关键是:先归类,再下钻。不要一上来就翻全量日志。
五、为什么这件事能带来“交付价值”?
Blocking Reasons 体系本质上是在把“经验”变成“产品能力”:
- 让排障流程化:新人也能按 checklist 定位问题
- 让问题可统计:你能看到系统最常卡在哪里,从而指导平台优先级
- 让沟通有共识:讨论从“我感觉”变成“原因码 + 证据链”
- 为准生产演进铺路:风控拒绝/通道拒绝等,本来就需要可解释与可审计
当一套系统能回答“为什么没发生”,它才有资格承担团队的日常运行。
六、你可以立刻做的一个验证
找一个“没成交”的回测或 paper 运行,按下面顺序走一遍:
- 看系统状态页的阻塞原因 Top(24h),确认原因码与中文说明
- 打开该策略的运行事件,确认 eventCode 是否一致
- 用最小化步骤复现一次(相同时间窗、相同版本)
如果这三步能让你在 5–10 分钟内把问题收敛到“标的/数据/调度/风控/通道/引擎”之一,说明这套可解释体系是有效的。
结语:可解释性不是“讲得通”,是“查得快”
量化系统的可解释性,最终衡量标准不是“能不能讲一个漂亮故事”,
而是:当策略没信号、没下单时,你能否在最短时间内定位问题类别、找到证据、形成团队共识。
下一篇(04)我们会讲“可复现性”:为什么一次回测必须有 provenance(输入快照),以及它如何支撑评审、回归与审计。