# 2026-07-25 复评:为什么原文还不是“整体 60 分” 审计对象:`个人 A 股量化系统机构级 60 分 Baseline 技术选型设计:从聚宽研究到 QMT 实盘(2026-07-22)` 结论先行: | 刻度 | 分数 | 准确含义 | | --- | ---: | --- | | 设计覆盖度 | 约 70/100 | 原文已经讨论研究、数据、风险、成本、组合、执行、运维与合规的大部分责任边界 | | 可实施规格度 | 49/100 | 只有约一半内容足够明确,工程师无需继续发明字段、默认值、失败语义和验收口径 | | 原实现证据 | 6/100 | 截至 2026-07-22,主要证据是文章、架构图、外部资料与验收清单;没有可重放代码、数据、测试或平台运行记录 | | 硬门 | 0/10 | G1—G10 都缺少完整验收证据;不是“部分通过” | 这三条分数不能相加,也不能互相替代。设计覆盖 70 不代表系统得 70;代码文件存在也不代表 Gate 通过。依据原文自己的定义,达到 Baseline 60 必须同时满足: ```text 证据评分 >= 60 且 G1 ... G10 全部通过 ``` 当前 Quant OS 代码交付是一个可执行、可测试的工程起点;`quant60` 是其第一版 A 股 Baseline 内核。它的新增得分必须在授权数据、真实平台运行、QMT 影子盘、 连续对账和券商合规确认完成后,逐项写回 [`gate_scorecard.json`](../gate_scorecard.json)。本报告不预支这些分数。 截至 2026-07-26 的实现事实快照: > 这是复评当日的历史快照,不是滚动状态页。当前五层主链、测试数和平台证据 > 边界以 [`BASELINE_VERTICAL_SLICE.md`](BASELINE_VERTICAL_SLICE.md)、 > [`gate_scorecard.json`](../gate_scorecard.json) 和生成的公开状态为准。 - 本次复评当时的标准库全量测试为 `Ran 224 tests`、`OK (skipped=6)`; - JQData raw/factor/pre-close/limits/paused + 每日 PIT `is_st`/指数成员 已连接到 semantic snapshot verifier、`snapshot-backtest` 和 `snapshot-decision`,并拒绝把抓取当日未到 24:00 的日线标成完整收盘, 但尚未用用户授权账号跑真实快照; - CPython 3.12 + `pyqlib==0.9.7` native momentum fixture 已真实运行并产生 24 条 signal; - Qlib Alpha158 + LightGBM + Recorder fixture smoke 已真实成功;两条 Qlib workflow 均保存表级 hash、边界和从 portfolio report 重算的指标, runner 会为 local MLflow file store 显式设置 `MLFLOW_ALLOW_FILE_STORE=true`; - fixture 只有两只 synthetic 股票,任何性能数字都没有投资意义; - JoinQuant/QMT mock parity exporter 已实现,但 `real_platform_pass=false` 且不计 G9; - 2026-07-26 已完成一次 2024 全年真实 JoinQuant hosted momentum smoke,可见 日志无 ERROR;它证明 `portable_momentum_smoke` runtime/path,不是 Ridge/TargetPackage Baseline 证据,且尚无完整同输入导出和本地 strict peer; - 同日一个 `synthetic-research` TargetPackage 已在真实 JoinQuant hosted 环境完成 exact-clock/`day_open` 绑定、3 笔委托和 3 笔成交;该证据只支持 execution 层真实平台观察,不支持上游四层、G9 或投资表现; - XtTrader 已有严格只读、HMAC 账户绑定的 observation/snapshot/shadow plan 与 verifier,但真实 QMT、broker callback/shadow 均未运行, G1—G10 仍全部 `not_passed`。 ## 1. 审计方法 本次没有按“名词是否出现”评分,而是对原文每个责任域检查六类问题: 1. 是否明确输入、输出和时钟; 2. 是否给出机器可校验的数据契约; 3. 是否处理异常、恢复和幂等; 4. 是否给出确定默认值或明确标记待确认; 5. 是否有可运行实现和自动化测试; 6. 是否有来自目标平台、真实数据或券商的运行证据。 “设计覆盖度”主要看第 1 类及责任域是否齐全;“可实施规格度”要求前 4 类足够清楚;“实现证据”只认可第 5、6 类已保存的产物。外部文档说明某 API 有能力,不等于本系统已经正确调用它。 ## 2. 原文做对了什么 原文比常见的“因子 + 回测净值”方案完整得多,70 分设计覆盖主要来自: - 明确拆开 `Forecast → Target → Order → Fill`,避免预测、仓位和成交混为一谈; - 意识到 PIT、历史指数成分、退市样本、公告可得时间和公司行动; - 把风险、成本、换手和流动性放到事前组合决策,而不是只在绩效末尾扣滑点; - 讨论部分成交、撤改单、乱序回报、重启、三账对账和 kill switch; - 把本地、聚宽、Qlib、QMT 定位为不同角色,而不是追求单一平台全包; - 给出十道硬门,且明确“目标 66”只有在实现、模拟和券商确认后才成立; - 对深模型、混合整数优化、逐笔队列与多券商容灾做了合理的 V1 边界控制。 因此问题不是方向错误,而是大量段落仍处于“正确的架构意图”,没有下降为可执行合同和证据。 ## 3. 不足全景 | 责任域 | 原文已有 | 阻止整体 60 的主要缺口 | 最低补证 | | --- | --- | --- | --- | | 数据/PIT | 分层目录、`available_time`、数据版本思想 | 无真实字段字典、供应商字段到 canonical 的映射、公告时区/盘前盘后规则、历史修订样例、许可边界和 PIT 注入测试 | 固定数据快照、manifest、字段级时点规范、反未来函数测试 | | Security Master / Universe | PIT 成分、开/持/卖/冻结状态 | 无状态 schema、生效区间合并优先级、代码变更与退市/重组样例;指数成分来源和发布日期语义未冻结 | 历史 fixture 与逐原因码重放 | | 特征/标签/验证 | LightGBM + Ridge、purge/embargo、walk-forward | 无特征公式和缺失值策略的完整注册表;标签价格与可执行时钟未机器化;无 purge 算法、切分日历和未触碰测试集 | 训练配置、切分测试、冻结 OOS 报告 | | 风险 | 透明行业/风格风险模型与收缩思想 | 因子定义、估计窗、缺失暴露、协方差清洗、特异风险下限、行业映射版本和压力场景均未定 | 风险快照 schema、数值稳定性测试、压力报告 | | 成本/容量 | 日期化费用、价差与冲击公式 | 参数没有账户交割单或真实成交校准;最低佣金的非凸性如何进入候选/rounding 未实现;机会成本缺失 | 费率版本、逐笔 TCA、low/base/high 校准 | | 组合 | 连续优化 + rounding/repair 方向正确 | 目标函数量纲、风险厌恶系数、约束优先级、不可行诊断、冻结仓位与现金联立细节未形成求解器规格 | 可解释优化输出、不可行/rounding 回归测试 | | 本地回测 | 要求与执行器同源 | 没有事件时钟、公司行动、现金结算、价格基准、成交量切片和可重放输出合同 | 小型确定性 fixture、黄金输出、费用/T+1/涨跌停测试 | | 聚宽 | 定位为第二引擎 | 无可上传入口、参数表、调度回调、`avoid_future_data` 设置、结果导出和平台限制清单 | 上传包、平台回测记录、canonical 差异报告 | | QMT 内置 Python | 只笼统写 QMT/XtQuant | 没有处理内置 Python 3.6 与本地现代环境的边界;未说明 GUI 启动方式、回调入口和产物导出 | Python 3.6 薄核心、QMT 内置回测记录 | | qmttools | 未与其他 QMT 路径清楚分层 | 原文没有说明 `run_strategy_file` 是原生 Python 驱动 QMT 策略文件的独立运行形态,不能等同于 XtTrader OMS | 独立入口、版本/参数记录、回测结果导出 | | XtTrader | 异步 OMS 方向正确 | 无券商状态码映射、session/account 配置、连接恢复、查询与回调竞态、撤单确认、未知单处置 | 脱敏回调回放、重启/乱序/重复测试、20 日影子盘 | | Qlib | 工作流选型合理 | “接 Qlib”与“由 Qlib 完成本系统回测”边界模糊;无 provider URI、dataset handler、workflow YAML、canonical 转换和 Records 产物 | Python 3.12 锁定环境、固定数据、Qlib smoke/OOS 报告 | | 跨引擎 | 提出双引擎一致性 | 未定义到底比较输入、信号、目标、订单还是净值;没有容差、舍入、交易日历和差异原因码 | 见 [`CROSS_ENGINE_CONSISTENCY.md`](CROSS_ENGINE_CONSISTENCY.md) 的逐层合同 | | Schema/版本迁移 | 列出九类对象 | 原文只有字段清单,不是 JSON Schema;无 `schema_version`、兼容策略、正反例与验证命令 | 版本化 schema、fixture 和 CI 验证 | | 可复现 | Git/config/data/model/rules 版本思想 | 无 run manifest 格式、环境锁、随机源清单、原子发布、干净机复跑或 hash 容差 | 可保存 manifest、两次重放差异 | | 运维/安全 | 提到单机、告警、runbook | 无部署命令、目录权限、凭据注入、日志脱敏、磁盘满/时钟偏差/重复调度/损坏账本处置 | [`SECURITY.md`](SECURITY.md) 与故障演练记录 | | 合规 | 正确设为硬门 | 只链接通用法规;没有实际券商对账户、软件、频率、报告状态的确认 | 券商书面确认索引与“先报告、后交易”记录 | ## 4. 可实施规格为什么只有 49 原文的伪代码和目录树提供了良好边界,但工程实现仍需自行决定很多会改变结果的事实。例如: - `AlphaForecast` 写了“分数/预期超额”,却没有决定两者是否都必填、单位是什么、是否允许空值; - “按公告可得时间进入”没有定义 15:00 后公告应进入哪个交易日、时区和供应商延迟如何处理; - “Guarded TWAP/POV”没有冻结子单切片、限价、超时、撤单确认和窗口结束残单政策; - “差异在数值容差内”没有给各层容差,也没有区分浮点误差与平台成交机制差异; - “QMT adapter”没有区分 QMT 内置 Python、`qmttools.run_strategy_file` 与外部 `XtTrader` 三条生命周期不同的路径; - “Qlib workflow”没有给 provider、handler、dataset、model、record 和数据转换的可运行组合; - “三本账”没有定义事件唯一键、追加一致性、崩溃点、重复回调去重和 broker snapshot 的事实优先级。 当实现者必须自行补完这些选择时,文章仍是设计说明,不是完整实施规格。新仓库中的四个 JSON Schema 只是把一小部分边界机器化,不能倒推原文在 7 月 22 日已经拥有这些证据。 ## 5. 原实现证据为什么只有 6 6 分不是对文章质量的否定,而是严格区分“说明”和“运行事实”。原文当时可认可的证据主要是: - 一份结构完整、明确承认条件性的设计文章; - 一张架构图和可编辑源图; - 外部官方资料链接; - 评分公式、Gate 定义、阶段计划与手工验收清单。 缺失的是: - 可安装仓库与固定 Python 环境; - 可运行本地回测和确定性 fixture; - 聚宽/QMT/Qlib 平台入口; - 自动化测试、schema 验证、run manifest; - 数据质量、PIT、walk-forward、风险、成本和 TCA 报告; - 连续模拟、QMT 影子盘、故障演练和券商确认。 因此原实现证据只能落在“文档/原型前期”,不能用文章中的目标分 66 回填。 ## 6. Quant OS 当前实现的正确能力边界 当前已经不只是目录骨架,以下链路可运行、可测试、可扩展: - 本地 deterministic event backtest、ledger hash chain、manifest verifier; - A 股 canonical symbol、T+1 可卖量、百股单位、费用、停牌/涨跌停、 部分成交和未成交撤销; - PIT table、Universe 状态/原因码、透明特征、train-only 预处理、 purge/embargo walk-forward、deterministic Ridge、IC/RankIC; - 日期化费用、impact/capacity、因子风险、约束 target 与失败诊断; - JQData adapter 使用 `get_bars` 获取 raw OHLCV/money、factor、 `pre_close`、`high_limit`、`low_limit`、`paused`,使用 `get_extras` 获取 PIT `is_st`,并逐交易日获取历史指数成员; - canonical snapshot 采用 incomplete marker + exact artifact hash, verifier 会重建领域对象、重算质量汇总和 `data_version`; - verified snapshot 可直接进入历史 `snapshot-backtest` 或单日 `snapshot-decision`,后者可接完整 canonical broker snapshot 并 fail closed; - 聚宽/QMT 单文件 bundle、fake harness 与 mock parity exporter; - Qlib 0.9.7 native momentum CLI,以及 Alpha158/LightGBM/Recorder CLI; - QMT/XtTrader 严格只读 shadow CLI:账户 HMAC、broker observation、 T 日 Signal 与 T+1 broker fact 绑定、完整 artifact verifier; - Colab 默认无账号流程,以及显式可选的 JQData/Qlib cell。 最近一次 224-test suite、两条 Qlib fixture smoke 和 Tushare managed-provider 技术 smoke 证明上述代码路径能执行, 但仍明确不证明: - synthetic 数据或两股票 Qlib fixture 的收益具有投资价值; - 当前真实 JQData 账户的数据许可、PIT、质量与保存策略已验收; - 基本面公告、完整公司行动、Security Master 和退市链已生产化; - Ridge 或 LightGBM 已冻结为四引擎共同部署模型; - 聚宽与本地已在真实长样本上对齐; - QMT 客户端、`xtquant`、数据/账户权限或真实订单回调已经可用; - QMT 历史 ST 正例、官方 query API 的失败/空列表合同已在真实账号验证; - OMS 已达到断线恢复、未知单、持续对账和 20 日影子要求; - 程序化交易报告已经完成。 ## 7. 平台事实应分开写 截至本次复评所依据的官方文档和本地运行记录: - QMT 内置策略环境仍说明为 Python 3.6;它适合运行兼容的薄策略文件,不应直接加载要求 Python ≥3.10 的完整 `quant60` 包; - XtQuant 原生 Python 文档列出 3.6—3.12 的库,并要求运行前启动 MiniQMT;实际可用版本取决于券商分发; - qmttools 的 `run_strategy_file` 是从原生 Python 驱动策略回测/运行的路径,应与 XtTrader 的查询、报单、撤单和推送生命周期分开; - `pyqlib==0.9.7` 已有 CPython 3.12 的主流平台 wheel;本项目已经在该组合 实际跑通 native momentum fixture(24 signals)和 Alpha158/LightGBM/Recorder fixture; - Alpha158 runner 使用 `os.environ.setdefault` 自动确认 `MLFLOW_ALLOW_FILE_STORE=true`,以兼容本地 MLflow file store; 该确认只影响本地 tracking backend,不构成数据许可或模型有效性证明。 来源:[QMT 内置 Python 快速开始](https://dict.thinktrader.net/innerApi/start_now.html)、[XtQuant 原生 Python 快速开始](https://dict.thinktrader.net/nativeApi/start_now.html)、[原生 Python/qmttools 策略回测](https://dict.thinktrader.net/videos/touyan/ty_native_python.html)、[pyqlib 0.9.7 包与 wheel](https://pypi.org/project/pyqlib/)。 Qlib 的运行状态现在可以写成“固定运行时已通过 fixture smoke”,不能写成 “真实 A 股研究已验收”或“与 portable target/order 一致”。两股票 synthetic fixture 的 model/portfolio 指标没有投资意义;真实 provider、冻结 OOS 和 版本化 Recorder artifact 仍要单独补证。 对应的最小验证入口: ```bash python3.12 -m venv .venv-qlib312 source .venv-qlib312/bin/activate python -m pip install -r requirements/research-py312.txt python tools/build_qlib_tiny_fixture.py artifacts/qlib-fixture --days 80 PYTHONPATH=src:. python -m platforms.qlib_runner \ --provider-uri artifacts/qlib-fixture \ --market csi300 --benchmark SH000300 \ --start 2024-02-01 --end 2024-04-19 \ --lookback 20 --topk 1 --n-drop 1 --rebalance weekly \ --output-json artifacts/qlib-native/result.json ``` 真实 JQData 验证则必须由用户授权登录: ```bash PYTHONPATH=src:. python tools/jqdata_snapshot.py \ --index 000905.XSHG --start 2024-01-02 --end 2024-12-31 \ --output data/snapshots/csi500-2024 PYTHONPATH=src:. python -c \ "from quant60.data_snapshot import verify_data_snapshot; verify_data_snapshot('data/snapshots/csi500-2024/manifest.json')" PYTHONPATH=src:. python -m quant60 snapshot-backtest \ --snapshot data/snapshots/csi500-2024/manifest.json \ --config configs/baseline.json --output artifacts/csi500-2024-backtest ``` ## 8. 证据更新纪律 更新 [`gate_scorecard.json`](../gate_scorecard.json) 时必须遵守: 1. 先保存不可变证据,再改状态; 2. 每条 evidence 至少包含路径、生成命令、时间、代码版本、配置 hash 和数据版本; 3. `mock`、合成 fixture 和单元测试可证明代码语义,不能证明真实数据、券商或合规; 4. Gate 只有 `passed` 与 `not_passed` 两种对外结论;“完成 80%”仍是未通过; 5. G9 需要真实跨引擎产物,G6/G8 需要券商认证环境或脱敏真实回调,G10 只能由实际券商材料证明; 6. 任何代码变更使旧证据超出适用版本时,必须重新降为 `not_passed`; 7. 总分达到 60 但任一 Gate 未通过,系统仍必须标记 `NOT_BASELINE_60`。 ## 9. 下一条最短路径 按错误成本排序,而不是按模型新颖度排序: 1. 用户授权登录 JQData,生成不可变真实 snapshot,保存许可/lineage,并通过 semantic verifier、`snapshot-backtest` 和 `snapshot-decision`; 2. 把已完成的单包 JoinQuant execution smoke 扩展为授权真实数据的多期 TargetPackage,并保存完整 identity/plan/orders/fills; 3. 用本地与聚宽对相同输入逐层比较 L1—L4,而不是先比较净值;mock parity 只作为回归辅助; 4. 把基本面公告 available-time、完整公司行动/Security Master 加入真实 PIT data contract; 5. 在授权真实 provider 上运行 Qlib OOS,并把 Ridge/LightGBM 中选定的候选 冻结成 versioned model bundle;现有 synthetic Recorder 不能承担这一步; 6. 取得实际券商 QMT client、`xtquant`、数据与账户权限,分别验证 built-in、 qmttools 与 XtTrader; 7. 完成 60 个交易日模拟、20 个交易日 QMT shadow、故障演练、连续零未知账差; 8. 由实际券商确认程序化交易报告、接口权限、频率和软件要求,再讨论小资金 canary。 在第 7、8 步完成前,正确表述是“可执行、可继续填证据的 Quant OS 生产候选 框架”,不是“已达到机构级 60 分”。