先记住这一句话
Quant OS 现在最有价值的成果,不是某条收益曲线,而是已经把“数据在什么时候可知、模型如何产生权重、权重如何送进平台、平台如何绑定真实账户、每一步如何留下证据”连接成了一条可验证的链。它已经是一个能继续填充真实证据的工程候选,但仍然是
NOT_BASELINE_60、G1—G10 = 0/10 passed,不能投入真实资金。
这篇文章不继续堆技术名词。它只回答四个问题:
- 我们现在到底搭了一个什么系统?
- 已经跑过的本地、Qlib 和聚宽回测分别证明了什么?
- 为什么代码很多、测试很多、平台也跑过,仍然不能说“达到 60 分”?
- 你接下来应该怎样亲手验证,才能真正把这些知识吃进去?
项目边界保持不变:
- Quant OS 代码在
~/boat-workspace/Code/quants-strategies/quant-os; - 远端代码在 git.gomars.fun/boat/quants-strategies/quant-os;
- OB 只保存文章和验证说明,不保存源码、数据、账号、密码、Token、Cookie、QMT userdata 或券商文件;
- 公开状态入口是 Quant OS 验收控制台。
两个状态面不要混淆
公开控制台当前固定在远端提交
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=false、investment_value_claim=false、gate_credit=[]。
一套成熟系统不只会生成收益,更要能主动告诉你:“这条收益现在不可以解释。”
4. 聚宽全年负收益:证明真实平台能跑,不证明策略好
2026-07-26 完成的聚宽 hosted 回测覆盖 2024-01-02 至 2024-12-31,初始资金 100 万,结果是:
- 策略收益 -19.98%;
- 中证 500 benchmark +5.46%;
- 最大回撤 32.45%;
- 可见完成日志中没有
ERROR、Traceback或订单拒绝。
这次结果至少淘汰了一个幻想:一个简单动量 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 这轮最值得保留的工程认知,是把下面五件事分开:
- implemented:代码文件存在;
- unit tested:局部行为通过自动测试;
- local entrypoint reachable:真实本地命令能走到;
- platform entrypoint reachable:聚宽/QMT wrapper 能走到;
- 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 分钟:只看证据边界
- 打开 公开验收控制台;
- 只看三列:
已实现、已有证据、仍缺什么; - 找出页面中所有
synthetic、fake、not_passed; - 用一句话解释:为什么“真实聚宽跑完”仍不等于 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_of与next_session;- TargetPackage 里为什么只有权重,没有账户股数。
120 分钟:做一次“故意破坏”
复制一份本地产物到临时目录,任选一个数值改掉,再运行 verifier。你要观察的不是报错本身,而是:
- 系统是否 fail closed;
- 它能否指出身份或 hash 不一致;
- 是否存在“校验失败后仍继续下单”的隐式降级;
- 修改普通 artifact hash 后,语义重放能否继续识别伪造。
真正理解可审计系统的最好方法,是亲手看它拒绝一份被改写的证据。
八、接下来最合理的证据顺序
后续不要同时追十个方向。按下面顺序填证据:
- 补齐合法的复权、PIT 成分、ST、停牌、涨跌停和真实 benchmark;
- 冻结一套授权真实数据的长样本,封住测试集;
- 训练 Ridge / LightGBM challenger,保存真正的 OOS 与容量报告;
- 用真实数据校准风险、成本和冲击,明确选定 Baseline 主链;
- 生成多期真实 TargetPackage tape;
- 在本地和聚宽使用同一 tape,逐层比较;
- 有 QMT 权限后跑同一 tape,补齐 QMT peer;
- 在已登录的 QMT/MiniQMT 做至少 20 个交易日只读 shadow;
- 完成订单回调、重启恢复、日终对账和 kill-switch 演练;
- 最后确认数据许可、券商程序化交易和软件使用合规,再讨论有限资金上线。
用户真正需要提供环境的地方只有三类:
- JQData 或其他合法数据源的本机授权登录;
- 聚宽登录后的 hosted 回测与导出;
- Windows QMT/MiniQMT 已登录客户端、历史数据与只读账户查询权限。
凭据只应在对应平台或本机无回显入口输入,不能进入聊天、OB、Git 或公开网页。
九、读完这篇文章后,你应该能回答
- 为什么收益高不等于回测可信?
effective_time和available_time有什么不同?- 为什么 TargetPackage 保存权重而不保存最终股数?
- 为什么本地、聚宽、QMT不应该各自重新计算完整策略?
- synthetic、真实数据、真实平台三种证据分别能证明什么?
- 为什么 Tushare 回测里 196,302% 的 benchmark 是警报?
- 为什么聚宽 -19.98% 仍然是一份有价值的工程证据?
- 为什么一次真实聚宽成交只让
execution.real_platform_observed=true? - 为什么 285 个测试不能换算成 Baseline 分数?
- 在什么证据出现之前,系统绝对不能投入资金?
如果这十个问题能够不看文章复述出来,你已经不再只是“会跑回测”,而是开始用机构级方式判断一套量化系统。
结语:60 分不是模型分,是可信链条的及格线
Quant OS 当前最真实的评价是:
本地工程链:已接通
Qlib 研究运行时:已接通
聚宽真实执行边界:局部观察到
QMT 真实运行:未取证
真实数据 OOS:未完成
跨引擎同输入:未完成
20 日影子与对账:未完成
Baseline:NOT_BASELINE_60
Gates:0/10 passed
它已经比一份策略脚本强很多,因为它知道自己的证据边界,也能告诉我们下一块证据应该放在哪里。但它还没有到“可以上线”的阶段。
真正的 60 分,不是回测图更漂亮,也不是模型名字更复杂,而是从一条原始数据到一笔真实订单之间,每一步都能解释、冻结、重放、对账,并在证据不足时坚决停下来。
OB 内部延伸阅读:
- 60 分 Baseline 技术选型设计
- Quant OS 实现状态与验证手册
- Tushare 数据资产与 Qlib 回测记录