Public note

Quant OS 从回测曲线到可审计系统:当前架构、实跑证据与 60 分学习地图(2026-07-28)

·Markdown 原文

先记住这一句话

Quant OS 现在最有价值的成果,不是某条收益曲线,而是已经把“数据在什么时候可知、模型如何产生权重、权重如何送进平台、平台如何绑定真实账户、每一步如何留下证据”连接成了一条可验证的链。它已经是一个能继续填充真实证据的工程候选,但仍然是 NOT_BASELINE_60G1—G10 = 0/10 passed,不能投入真实资金。

这篇文章不继续堆技术名词。它只回答四个问题:

  1. 我们现在到底搭了一个什么系统?
  2. 已经跑过的本地、Qlib 和聚宽回测分别证明了什么?
  3. 为什么代码很多、测试很多、平台也跑过,仍然不能说“达到 60 分”?
  4. 你接下来应该怎样亲手验证,才能真正把这些知识吃进去?

项目边界保持不变:

两个状态面不要混淆

公开控制台当前固定在远端提交 692f6ef,代表已发布、可复查的稳定快照。2026-07-28 成稿时,本地工作候选又接通了五层 vertical slice、ModelBundle、TargetPackage 和一次真实聚宽 execution smoke,并完成 285 tests / OK / 6 optional skips。后者是正在固定的候选状态,不应倒推成远端稳定版已经具备的能力,更不改变 0/10 Gates

一、先换一把尺子:回测不是答案,而是一份证词

很多量化项目的叙事是:

找到因子 → 跑出收益 → 调参数 → 收益更好 → 准备实盘

Quant OS 刻意把这条路改成:

数据可知性
→ 样本外实验
→ 冻结模型与配置
→ 生成目标权重
→ 平台绑定真实账户与价格
→ 订单、成交、对账
→ 可重放证据
→ 才讨论是否有投资价值

这两条路最大的区别是:第一条路容易把“能运行”误认为“能赚钱”,把“历史上赚钱”误认为“未来可交易”;第二条路要求每个结论都回答三个问题:

  • 证据来自 synthetic、真实数据,还是真实平台?
  • 它证明的是接口、策略有效性,还是执行可靠性?
  • 换一台机器、换一个平台、换一天之后,能否用相同输入重放?

因此,一次负收益但身份清楚、时钟清楚、输入可复查的回测,往往比一条来源不明的高收益曲线更有价值。

二、我们搭的不是“一个模型”,而是一条责任链

Quant OS 当前可以用下面这张图理解:

合法数据源:Tushare / JQData / 平台数据
  ↓
不可变数据快照:PIT、交易日历、复权、成分、交易状态
  ↓
研究层:Universe → Feature → Alpha → OOS
  ↓
组合与风险:成本、容量、约束、post-risk gate
  ↓
ModelBundle + TargetPackage:冻结身份、权重、双时钟、lineage
  ├─→ 本地事件引擎 ─┐
  ├─→ 聚宽薄消费者 ─┼─→ 订单 / 成交 / 账本 / 对账
  └─→ QMT 薄消费者 ─┘
                         ↓
                只读影子、恢复、告警、合规证据

1. 数据层决定“当时能不能知道”

回测最危险的错误不是公式写错,而是偷看未来。

例如,某公司 4 月 30 日发布年报。它的财务数据可能描述的是上一年 12 月 31 日,但策略在 1 月 1 日不能使用它。于是 Quant OS 区分:

  • effective_time:数据描述哪个时期;
  • available_time:市场参与者什么时候真正能看到;
  • decision_time:策略什么时候做决定;
  • execution_time:订单什么时候可以执行。

只看一个 date 字段,很容易制造未来函数。

2. 研究层决定“信号是否在未见样本中成立”

当前研究链已经覆盖:

  • PIT Universe 状态;
  • 透明价量特征;
  • train-only 去极值、填充和标准化;
  • purged / embargo walk-forward;
  • Ridge 候选;
  • OOS IC、RankIC;
  • 成本、容量、风险和组合约束。

这里最重要的不是 Ridge 比 LightGBM “高级”或“低级”,而是训练阶段学到的所有东西都必须冻结。模型系数、特征顺序、预处理参数、训练截止时间、代码和配置,都要进入 ModelBundle。否则所谓“同一个模型”只是口头描述。

3. TargetPackage 是系统的关键分界面

本地权威链最终不直接输出“买 2,300 股”,而是输出一个无账户股数的 TargetPackageV1

  • 哪个决策日形成的信号;
  • 哪个实际交易日执行;
  • 每只股票的 post-risk 目标权重;
  • 数据、模型、特征、风险、成本、优化器和源码身份;
  • 包本身及整条 tape 的 hash。

为什么不提前写死股数?因为股数取决于执行时账户净值、已有持仓、可卖数量和开盘价。这些事实应该由聚宽或 QMT 在执行边界读取,而不应该伪造在研究回测里。

目标架构因此是:

本地唯一决策权威:数据 → 模型 → 风险 → 权重
平台薄消费者:验包 → 对时钟 → 读账户和价格 → 算股数 → 下单

这样可以避免在本地、聚宽和 QMT 各维护一套“看起来相同、实际逐渐漂移”的策略。

4. 执行层决定“想买”和“买得到”之间的差距

A 股不是连续、无限流动、想买多少就买多少的数学世界。当前本地执行内核已经模拟:

  • T+1 可卖量;
  • 停牌与涨跌停;
  • 主板百股规则和科创板最小申报;
  • 卖单优先;
  • 参与率限制、滑点、费用;
  • 部分成交、撤单、现金与持仓;
  • 事件 hash-chain、幂等重放和 manifest 校验。

但本地撮合仍然只是模型。只有真实平台导出的订单和成交,才能证明平台行为。

三、已经跑过的回测,分别属于哪一级证据

把当前结果放在同一张表里看,信息会清楚很多:

运行 使用的数据/环境 已观察结果 真正证明的事 不能证明的事
本地 synthetic execution 人工构造的 90 个交易日 收益约 -2.21%,最大回撤约 -3.07%,26 个订单、25 次成交 事件引擎、规则、账本、重放和确定性路径能运行 真实市场有效性、未来收益
本地 synthetic research 人工构造研究样本 五层链、Ridge ModelBundle、TargetPackage、逐层 hash trace 已生成 Universe→Alpha→Portfolio→Risk→Execution 能形成因果闭环 真实数据 OOS、真实风险参数
Qlib native fixture 两只 synthetic 股票,pyqlib 0.9.7 动量 fixture 产生 24 个 signals;Alpha158 + LightGBM + Recorder 流程完成 真实 Qlib runtime、数据接口和实验记录器可运行 Alpha158/LightGBM 在 A 股真实样本有 Alpha
Tushare → Qlib 1990—1993 的不完整早期日线 策略累计 -52.53%;合成 benchmark 约 +196,302% 93 个文件可校验、provider 可构建、两次 evidence JSON 逐 byte 相同 收益可信、真实 benchmark、PIT 股票池、复权后策略表现
聚宽动量 smoke 聚宽真实 hosted,2024 全年,100 万初始资金 策略 -19.98%,基准 +5.46%,最大回撤 32.45%,可见完成日志无报错 单文件在真实聚宽环境能完整跑完 与本地同输入一致、策略有投资价值
聚宽 TargetPackage execution smoke 一个 synthetic-research 包,2024-03-11—03-13 3 月 12 日精确命中;3 笔委托、3 笔成交;前后交易日均 no-op 验包、双时钟、真实账户/开盘价绑定和 execution consumer 可工作 上游四层在真实数据上有效、QMT parity、G9 通过
QMT / XtTrader 本地 bundle、fake contract、只读 shadow harness Python 合约和不可变证据路径已测试 适配层和安全边界已经准备 真实 QMT 运行、券商回调、20 日影子和实盘资格

下面逐个拆开。

1. 本地 synthetic:测的是“机械结构”

本地 90 日结果约为 -2.21%,这个数字没有投资意义。它的价值在于 synthetic 场景可以故意制造:

  • 一只股票跌停卖不掉;
  • 一笔订单只能部分成交;
  • T+1 可卖量小于持仓;
  • 账户现金不足;
  • 相同输入重复运行。

系统必须对这些情况产生稳定、可解释的事件记录。若输入相同,输出 artifact、ledger head 和关键 hash 应一致;任意文件被改写,verifier 应拒绝。

这类测试相当于飞机在地面做舵面和传感器检查。它不能证明飞机能完成跨洋飞行,但不做它就不应该起飞。

2. Qlib fixture:测的是“研究工具链能否落地”

Qlib 在 Quant OS 中是研究引擎,不是券商 OMS,也不是原始数据仓库。

两只 synthetic 股票的 fixture 跑通了:

  • Qlib provider 初始化;
  • 表达式与信号生成;
  • 策略回测;
  • Alpha158 特征;
  • LightGBM;
  • Recorder 记录模型、信号和分析结果。

这证明环境、API 和 artifact 流程可运行,却没有证明模型在真实 A 股有预测力。样本只有两只 synthetic 股票时,即使 Sharpe 很高也不能用于投资判断。

3. Tushare 早期回测:最值得学习的是“异常高收益为什么是警报”

已经下载的 Tushare 镜像中,93 个 completed Parquet 合计 64,659 行,文件大小、SHA-256 和行数都已校验。可是 daily 只完成 35/428 个月,约 8.2%,行情只到 1993-10-29,并且缺少:

  • adj_factor
  • 真实指数日线;
  • PIT 指数成员;
  • 历史 ST、停牌和涨跌停;
  • 生产需要的完整公司行动与证券主数据。

在这批数据上,动量策略累计约 -52.53%,合成等权 benchmark 却出现约 +196,302%。

这个极端数字不是发现了“30 年前的暴利策略”,而是数据诊断信号:未复权早期市场、非 PIT 股票筛选、合成 benchmark 和缺失交易状态把结果扭曲了。

真正的成果是:

  • 原始镜像保持只读;
  • 只消费状态为 completed 且校验通过的文件;
  • 转换成不可变 Qlib provider;
  • 相同命令连续运行两次,证据 JSON 逐 byte 相同;
  • manifest 明确写出 production_ready=falseinvestment_value_claim=falsegate_credit=[]

一套成熟系统不只会生成收益,更要能主动告诉你:“这条收益现在不可以解释。”

4. 聚宽全年负收益:证明真实平台能跑,不证明策略好

2026-07-26 完成的聚宽 hosted 回测覆盖 2024-01-02 至 2024-12-31,初始资金 100 万,结果是:

  • 策略收益 -19.98%;
  • 中证 500 benchmark +5.46%;
  • 最大回撤 32.45%;
  • 可见完成日志中没有 ERRORTraceback 或订单拒绝。

这次结果至少淘汰了一个幻想:一个简单动量 smoke 并没有因为进入聚宽就自动成为好策略。

它证明的是平台运行路径,包括数据读取、PIT 成分/ST、调度、费率、滑点、参与率和订单 API。它没有导出和本地完全相同的输入、score、weight、target、order、fill,因此不能证明跨引擎一致性。

5. TargetPackage 真实 execution smoke:证明了“薄平台”架构

第二次真实聚宽证据更重要,但范围更窄。

一个证据等级为 synthetic-research 的 TargetPackage 被嵌入单文件,在真实聚宽环境运行 2024-03-11 至 2024-03-13:

  • 3 月 11 日:时钟不匹配,no-op;
  • 3 月 12 日:精确命中包,使用真实 day_open 和账户净值;
  • 3 月 13 日:没有新包,no-op;
  • 目标包含 4 只股票,最终产生 3 笔委托并全部成交;
  • 贵州茅台因一手市值高于 10% 目标名义金额,合法取整为 0 股,而不是订单失败。

这证明平台可以只消费本地冻结的 post-risk 权重,并在真实账户边界计算股数。它支持且只支持:

execution.real_platform_observed = true

Universe、Alpha、Portfolio、Risk 仍是本地 synthetic 产生,不能标记为真实平台已观察。运行详情可在登录聚宽后查看:TargetPackage hosted smoke

四、怎样判断一条回测能不能信

以后看到任何回测,不妨按下面十个问题逐项问。

问题 不回答会发生什么
数据什么时候发布、什么时候可用? 偷看未来
股票池是否按当日 PIT 重建? 幸存者偏差
价格是否复权,复权是否因果? 假收益与跳变
标签和成交价格之间是否留出可执行时间? 用收盘价看完收盘后又按收盘价成交
训练、验证、测试是否真正隔离? 参数和模型过拟合
手续费、滑点、涨跌停、停牌、T+1 是否存在? 纸面收益无法交易
权重、股数、订单、成交是否分层? 研究假设和账户事实混在一起
输入、代码、模型、配置能否冻结和重放? 无法解释结果变化
本地与平台是否使用同一个输入做逐层比较? “同策略”实际不同
失败后能否对账、停机和恢复? 小错误进入真实账户后持续放大

这十问基本对应 Quant OS 的十个 Gate:

Gate 核心问题 当前状态
G1 数据时点 是否真正 PIT 未通过
G2 样本外验证 是否有冻结真实 OOS 未通过
G3 A 股现实 是否覆盖真实交易规则与状态 未通过
G4 稳定合约 数据、信号、目标、订单合同是否可迁移 未通过
G5 事前风险 风险、成本、容量是否真实校准 未通过
G6 订单状态 订单生命周期是否由真实平台证明 未通过
G7 可复现 输入和结果是否可重放 未通过
G8 对账与停机 差异能否阻断、恢复能否演练 未通过
G9 跨引擎一致性 本地、聚宽、QMT 是否同输入一致 未通过
G10 合规 数据、软件、券商和程序化交易要求是否确认 未通过

所以当前分数不是“59 分差一点”,而是 score = null / not_scored。硬门没有通过之前,不能用单测数量给自己折算分数。

五、五种容易混淆的“完成”

Quant OS 这轮最值得保留的工程认知,是把下面五件事分开:

  1. implemented:代码文件存在;
  2. unit tested:局部行为通过自动测试;
  3. local entrypoint reachable:真实本地命令能走到;
  4. platform entrypoint reachable:聚宽/QMT wrapper 能走到;
  5. real platform observed:真实平台日志、订单和成交已经观察到。

一个因子风险模块可以“已实现并有单测”,但没有进入当前 Baseline 主链;CVXPY 优化器和 guarded TWAP/POV 也可以作为组件存在,却没有成为现行候选的真实执行路径。

同理,285 个测试说明回归保护比以前更厚,不代表 285 份真实市场证据。

六、当前模型和平台各自扮演什么角色

模型

  • portable-momentum-v1:跨平台连通性 smoke,用来证明最小路径,不是 Baseline champion;
  • Ridge:当前五层本地候选,可冻结为 ModelBundle,但上游仍是 synthetic;
  • Qlib Alpha158 + LightGBM:研究候选和工作流验证,不是已部署模型;
  • 风险模型:当前主 slice 使用 60 日对角实现方差;完整 factor risk 尚未进入主链;
  • 优化器:当前主 slice 使用确定性约束优化;CVXPY 是可选组件,未自动算入完成;
  • 执行:当前 slice 使用 reference one-shot planner;guarded TWAP/POV 尚未成为实跑主链。

平台

  • 本地 / Colab:唯一研究与冻结决策权威,适合实验、回放和生成 TargetPackage;
  • Qlib:研究实验与模型记录器;
  • 聚宽:已完成真实 hosted 动量 smoke 和一次 TargetPackage execution smoke;
  • QMT built-in / qmttools:已有 backtest-only 单文件和适配合同,等待 Windows 授权客户端实跑;
  • XtTrader:只读 shadow 路径,当前只允许查询、对账和生成计划,不允许真实下单。

平台不是彼此竞争的四套系统。正确关系是:本地形成唯一决策,Qlib帮助研究,聚宽和 QMT验证平台执行,XtTrader在资金接入前验证真实账户状态。

七、你可以怎样亲手消化

30 分钟:只看证据边界

  1. 打开 公开验收控制台
  2. 只看三列:已实现已有证据仍缺什么
  3. 找出页面中所有 syntheticfakenot_passed
  4. 用一句话解释:为什么“真实聚宽跑完”仍不等于 G9 通过。

如果你能回答“因为缺少同一冻结输入在本地、聚宽、QMT的逐层导出和差异归因”,第一关就过了。

60 分钟:在本地重放工程证据

cd ~/boat-workspace/Code/quants-strategies/quant-os
make test
make smoke
make verify
make research
make research-verify

当前候选的 make test 应看到:

Ran 285 tests
OK (skipped=6)

然后对照:

artifacts/local-smoke/report.json
artifacts/local-smoke/manifest.json
artifacts/research-smoke/model_bundle.json
artifacts/research-smoke/target_package.json
artifacts/research-smoke/pipeline.json

不要先看收益。先找:

  • evidence_class
  • investment_value_claim
  • data/model/config/source hash;
  • signal_as_ofnext_session
  • TargetPackage 里为什么只有权重,没有账户股数。

120 分钟:做一次“故意破坏”

复制一份本地产物到临时目录,任选一个数值改掉,再运行 verifier。你要观察的不是报错本身,而是:

  • 系统是否 fail closed;
  • 它能否指出身份或 hash 不一致;
  • 是否存在“校验失败后仍继续下单”的隐式降级;
  • 修改普通 artifact hash 后,语义重放能否继续识别伪造。

真正理解可审计系统的最好方法,是亲手看它拒绝一份被改写的证据。

八、接下来最合理的证据顺序

后续不要同时追十个方向。按下面顺序填证据:

  1. 补齐合法的复权、PIT 成分、ST、停牌、涨跌停和真实 benchmark;
  2. 冻结一套授权真实数据的长样本,封住测试集;
  3. 训练 Ridge / LightGBM challenger,保存真正的 OOS 与容量报告;
  4. 用真实数据校准风险、成本和冲击,明确选定 Baseline 主链;
  5. 生成多期真实 TargetPackage tape;
  6. 在本地和聚宽使用同一 tape,逐层比较;
  7. 有 QMT 权限后跑同一 tape,补齐 QMT peer;
  8. 在已登录的 QMT/MiniQMT 做至少 20 个交易日只读 shadow;
  9. 完成订单回调、重启恢复、日终对账和 kill-switch 演练;
  10. 最后确认数据许可、券商程序化交易和软件使用合规,再讨论有限资金上线。

用户真正需要提供环境的地方只有三类:

  • JQData 或其他合法数据源的本机授权登录;
  • 聚宽登录后的 hosted 回测与导出;
  • Windows QMT/MiniQMT 已登录客户端、历史数据与只读账户查询权限。

凭据只应在对应平台或本机无回显入口输入,不能进入聊天、OB、Git 或公开网页。

九、读完这篇文章后,你应该能回答

  1. 为什么收益高不等于回测可信?
  2. effective_timeavailable_time 有什么不同?
  3. 为什么 TargetPackage 保存权重而不保存最终股数?
  4. 为什么本地、聚宽、QMT不应该各自重新计算完整策略?
  5. synthetic、真实数据、真实平台三种证据分别能证明什么?
  6. 为什么 Tushare 回测里 196,302% 的 benchmark 是警报?
  7. 为什么聚宽 -19.98% 仍然是一份有价值的工程证据?
  8. 为什么一次真实聚宽成交只让 execution.real_platform_observed=true
  9. 为什么 285 个测试不能换算成 Baseline 分数?
  10. 在什么证据出现之前,系统绝对不能投入资金?

如果这十个问题能够不看文章复述出来,你已经不再只是“会跑回测”,而是开始用机构级方式判断一套量化系统。

结语:60 分不是模型分,是可信链条的及格线

Quant OS 当前最真实的评价是:

本地工程链:已接通
Qlib 研究运行时:已接通
聚宽真实执行边界:局部观察到
QMT 真实运行:未取证
真实数据 OOS:未完成
跨引擎同输入:未完成
20 日影子与对账:未完成
Baseline:NOT_BASELINE_60
Gates:0/10 passed

它已经比一份策略脚本强很多,因为它知道自己的证据边界,也能告诉我们下一块证据应该放在哪里。但它还没有到“可以上线”的阶段。

真正的 60 分,不是回测图更漂亮,也不是模型名字更复杂,而是从一条原始数据到一笔真实订单之间,每一步都能解释、冻结、重放、对账,并在证据不足时坚决停下来。


OB 内部延伸阅读: