feat: add Quant OS A-share baseline

This commit is contained in:
2026-07-26 12:54:04 +08:00
commit 48c5f64bbd
98 changed files with 31874 additions and 0 deletions
+274
View File
@@ -0,0 +1,274 @@
# Quant OS architecture and trust boundaries
Quant OS 是项目;`quant60` 是第一版 A 股 Baseline 内核、CLI namespace
和 artifact 协议前缀。当前形态是模块化单体:共享可移植计算和稳定合同,但把
数据供应商、hosted 平台、QMT 专有运行时与券商事实放在不同信任边界内。
```text
JQData (authorized account)
get_bars(raw OHLCV/money, factor, pre_close, limits, paused)
+ daily PIT is_st + daily PIT index membership
|
v
canonical immutable snapshot
exact-set/hash + semantic reconstruction
|
+---------+----------+
| |
v v
snapshot-backtest snapshot-decision
local event engine Signal -> Target -> Order Delta
| |
+---------+----------+
|
portable-momentum-v1
|
+------------+-------------+
| | |
JoinQuant bundle QMT bundle local contract oracle
hosted backtest built-in/qmttools backtest-only
synthetic PIT/features -> purged walk-forward -> Ridge challenger
(not deployment-frozen)
Qlib 0.9.7:
native portable-momentum signal bridge
Alpha158 + LightGBM + Recorder research workflow
(no L3 target / L4 order-intent parity)
XtTrader:
read-only broker observation -> HMAC account-bound shadow plan
callback/mutation boundary remains uncertified and operator-inaccessible
```
箭头表示数据或合同流,不表示平台能力等价。hosted 引擎拥有自己的时钟、行情
和成交语义;broker snapshot/callback 才是现金、持仓、可卖量、订单和成交的
事实权威。本地 ledger 不能用预测持仓覆盖券商事实。
## Runtime split
| Layer | Runtime | Rule |
| --- | --- | --- |
| Quant OS / `quant60` | Python ≥3.10 | 本地回测、snapshot pipeline、research、ledger、CLI |
| JQData ingestion | 独立 Python 环境,`jqdatasdk==1.9.8` | 只从授权账户获取数据;凭据不进入快照 |
| Qlib research | CPython 3.12.x`pyqlib==0.9.7` | 与本地/QMT 环境隔离;provider 必须授权且版本化 |
| Portable strategy core | Python 3.6-compatible source | 无第三方依赖;bundler 内联到 hosted 策略 |
| JoinQuant hosted | 平台管理 | 上传生成的单文件;不能假设安装本地包 |
| QMT built-in | QMT Python 3.6 | 只上传 bundle;模块全局 `g` 持久状态,避免 `ContextInfo` 用户属性回滚 |
| qmttools / XtTrader | 券商分发的 native Python | `xtquant` 专有且 lazy import,不进入仓库 |
| Colab | notebook runtime | 默认只跑无账号流程;JQData/Qlib 是显式可选 cell |
不要用一个 Python 环境强行兼容所有路径。
## Data plane and point-in-time semantics
JQData adapter 的输入合同是逐交易日历史指数成员和 `get_bars` 日线字段:
- 未复权 `open/high/low/close``volume``money`
- 复权因子 `factor`
- `pre_close``high_limit``low_limit``paused`
- 每个 member-date 的严格布尔 PIT `is_st`
- `skip_paused=False`,保留停牌日语义。
快照保存 `bars.jsonl``memberships.jsonl``quality.json`
`manifest.json`。发布期间存在 incomplete marker;完成后 verifier 要求目录
是精确 artifact 集、每个文件 hash 正确,并从 JSONL 重建领域对象,重算质量
汇总、内容 hash 和 `data_version`。这比“下载成功”更强,但在授权真实账户运行
并保存许可/lineage 前,仍不构成 G1 证据。
JQData 日线在 24:00 完成,因此 adapter 拒绝把 Asia/Shanghai retrieval
当日作为 `T_CLOSE_COMPLETE`;请求 `end` 必须早于抓取日期。字段、ST 或成员
覆盖不完整也不会被当成默认 false/空集合。
`snapshot-decision` 只用 `as_of` 当日精确 PIT 成员和截至当日的数据。
执行/名义价格保持 raw;动量把每个历史 close 乘以当日可见 factor,再归一到
决策日因子,因此后续公司行动不会改写已经形成的历史决策。held but
untradable 标的不会从 Universe 消失,而会进入 frozen / hold-only /
sell-only 状态。
若目标用于下一交易日开盘前 shadow,Signal 时钟仍是 T 日 15:00。snapshot
冻结 JQData `get_trade_days``get_all_trade_days` 一致性校验后的完整
交易日序列,并显式保存 end 日后的唯一 `next_trading_session`。decision、
broker snapshot 和 shadow plan 必须绑定同一个相邻 session,以及
Asia/Shanghai `[09:00,09:30)``first_executable_window`elapsed-day
阈值和 weekday 近似都不是权威。周末、T 日 15:01、错过 09:30、错误 session 或
迟到多日全部 fail closed,国庆等长假只要下一 session 来自冻结日历即可。
账户绑定后还必须保持决策规模有效。shadow 对 `decision.equity` 和当前
`total_asset` 使用固定的
`max(1 元, 0.01% × abs(decision equity))` 包含边界容差;缺失、负数、
非有限值或超差都不能进入 ready,超差原因码为
`DECISION_EQUITY_DRIFT`。该合同进入 plan hashverifier 会从原始两个权益值
重新计算差额、阈值和 blocker。
QMT shadow verifier 使用 semantic replay,而不把 plan 当成事实来源。
`broker_observation.json` 保存 query 后 adapter state、live flag、callback
error/live-authorization history 计数、query 起止、原始记录数、校验结果及
脱敏资产/持仓/委托/成交事实。原始 decision manifest 是 verify 的必需输入。
纯 replay 从这两个输入独立重建 account binding、clock gate、资产和现金
恒等式、open/order-stability、trade/fill identity、完整 blocker 集、
snapshot-valid、完整 broker snapshot、逐 symbol target/weight/lot、
board-lot/sellable feasible delta、proposal、portfolio 和 status,再与 plan
exact compare。因而 plan 中同步改写多个派生字段或删除 blocker 不能形成新的
`SHADOW_READY`;READY 也强制存在可重建 snapshot。
普通 artifact hash 之外,planner 使用既有 account HMAC key 和独立 domain
签署 `QMT_SHADOW_EVIDENCE_V1` envelope。envelope 绑定完整 plan、
broker observation、broker snapshot 的 canonical 内容 hash 和三份实际发布
bytes 的 SHA-256、原始 decision manifest hash、planner/engine 及 operator
entrypoint `tools/qmt_shadow_plan.py` source hash,以及 semantic version、
10 秒/1 元 policy ceiling 和 equity drift policy。四个发布 JSON(包括
不参与自签名的 manifest)还必须逐 byte 符合唯一 deterministic writer
encoding。verifier 从当前真实输入与磁盘实际 bytes 重建
envelope 并 constant-time 比较 MAC;缺失、错误或轮换后的 key 全部失败。
这提供的是 Quant OS 本地 evidence publisher authenticity/完整性,不是
QMT/券商对 query result 的原生签名,也不把 adapter 升级成 broker-certified。
策略安全阈值是 canonical policyquery window 上限 10 秒,资产/持仓市值和
`cash + market_value = total_asset` 的绝对容差上限 1 元。CLI 只能使用等于
或更严格的值,builder 与 replay 都拒绝更宽值。目标权重总和还必须不超过
1,作为无报价条件下可独立证明的决策现金预算;实时 buying power(含成交价、
费用和卖出先后)仍不作证明。
持仓 drift 不会复用旧持仓:每次 target diff 都从当前券商 positions 和
sellable quantity 重算,且 open/变化中订单会阻断。因此数量 residual 不会
因旧持仓静默失真。由于 shadow 没有实时执行价,现金购买力仍不能被证明;
plan 明示该限制,ready 仅供人工审阅,不能升级为 live submission。
`trade.amount` 当前会被标准化、认证和重放,但在缺少真实
terminal/xtquant build 探针时不假设它与 `price × quantity` 的精确误差
合同;它不参与 target diff,正式券商验收必须记录 build 并冻结字段容差。
`snapshot-backtest` 在每个历史决策日重新调用同一 decision path,并使用:
- 第一实际交易日完整收盘形成计划;
- 紧接着下一实际交易日开盘尝试成交;
- 当日供应商停牌/涨跌停/前收字段;
- 上一交易日成交量参与率;
- T+1、百股交易单位、显式费用和未成交撤销。
这是本地 fill model,不是 JoinQuant 或 QMT 的成交事实。
## Research and model boundary
synthetic research pipeline 已实现:
- PIT table 和未来值拒绝;
- Universe 原因码;
- 透明价量特征与 T+1-open 标签时钟;
- train-only winsor/impute/standardize
- purge/embargo walk-forward
- deterministic Ridge、OOS IC/RankIC
- factor risk、dated cost/capacity 和 constrained target。
这些功能证明研究管线可执行。Ridge 尚未冻结成带版本、输入 schema 和推理
hash 的 deployment bundle,也没有授权真实长样本 OOS 与四引擎推理验证,因此
不是生产 champion。
Qlib 路径固定为 `0.9.7`。CPython 3.12 实际 fixture smoke 已得到:
- native momentum24 条 signal
- Alpha158 + LightGBM:完成 fit、SignalRecord、SigAnaRecord、
PortAnaRecord 和 model 保存;
- 两条 workflow 都保存表级 hash、行列/时间边界和从 portfolio report
重算的有限值指标,明确 `investment_value_claim=false`
- local MLflow file store 使用时,runner 以
`os.environ.setdefault("MLFLOW_ALLOW_FILE_STORE", "true")` 显式确认。
该 fixture 只有两只股票和一个 benchmark,性能没有投资意义。Qlib 的单一
`limit_threshold` 也不能表达逐日板块/ST 规则,所以它只参与 L1/L2 和诊断
L6,不声称 L3 target 或 L4 order-intent parity。
## Portable strategy and platform boundary
当前可跨 hosted wrapper 冻结的共同基线是 `portable-momentum-v1`。平台 API
不得进入 symbol normalization、momentum score、target weight、target
quantity 和 order delta 计算。
canonical 股票代码采用 JoinQuant 形式:
| Canonical | QMT/XtQuant | Qlib |
| --- | --- | --- |
| `600000.XSHG` | `600000.SH` | `SH600000` |
| `000001.XSHE` | `000001.SZ` | `SZ000001` |
| `830799.XBSE` | `830799.BJ` | `BJ830799` |
转换权威是 `quant60.portable_core.normalize_symbol`。当前 XtTrader mutation
边界只接受 `.SH` / `.SZ`,不能从转换覆盖推导北交所实盘覆盖。
QMT built-in bundle 和 qmttools runner 都硬限制为 backtest/history。built-in
状态存放在模块全局 `g`,不写入可能在下个 `handlebar` 回滚的
`ContextInfo` 用户属性。两条路径固定中证 500 benchmark、PIT 历史成分/ST
与 baseline 费率;built-in 的 10% 参与率由 QMT GUI 设置,qmttools
程序化传入。live mutation 只存在于外部 XtTrader adapter,并且默认关闭、
未认证、没有 live 启动命令;operator 可运行的 shadow CLI 只接受查询边界。
## Stable artifacts and release integrity
最低交换合同是:
- [`signal.schema.json`](../schemas/signal.schema.json)
- [`target.schema.json`](../schemas/target.schema.json)
- [`order_event.schema.json`](../schemas/order_event.schema.json)
- [`broker_snapshot.schema.json`](../schemas/broker_snapshot.schema.json)。
`verify-manifest` 不仅检查 ledger hash chain,还检查 incomplete marker、
精确 artifact 集、SHA-256、ledger head、report/manifest identity、
saved/current source aggregate、saved/current schema aggregate 和 payload
schema。`verify-snapshot-decision` 与 data snapshot semantic verifier 承担
各自边界的同类职责。
这些合同已有自动测试;最近一次标准库套件为 211 tests、OK、3 个可选路径
skip。测试结果不能替代 schema 迁移演练、真实平台导出或券商回调认证。
## Clocks and reconciliation
canonical weekly clock 是:
```text
ISO 周第一实际交易日:完整 close
-> 使用 as_of 之前实际可得信息形成 signal/target/order intent
紧接着下一实际交易日:open executable window
-> 刷新市场规则与 broker snapshot
-> pre-trade gate
-> backtest/shadow submit 或 fail closed
-> callback append + reconciliation
```
“紧接着下一日”是交易日关系,不是固定星期几。每个真实平台 run 必须记录
`signal_as_of``last_feature_bar``first_executable_time`
price adjustment 和 fill model。
完整 reconciliation 要同时比较 cash、positions、sellable quantities、
open orders 和带时区的新鲜 `as_of/source_time`。legacy/partial snapshot
即使数值碰巧平衡,也不能把 `safe_to_open` 设为 true。
## Facts and current claim
| Fact | Authority |
| --- | --- |
| canonical symbol、portable calculation | versioned source + config |
| snapshot 内容 | semantic verifier 通过的 immutable snapshot + manifest |
| historical provider entitlement | 实际数据账户许可与保存的 lineage 记录 |
| hosted 回测时钟/成交 | 平台真实导出 |
| cash、position、order、fill | broker snapshot/callback |
| 程序化交易权限与报告 | 实际券商书面确认 |
| Gate 状态 | [`gate_scorecard.json`](../gate_scorecard.json) |
synthetic/fake 数据是合同测试,不是市场证据;Qlib synthetic fixture 的真实
运行是运行时证据,不是收益证据;mock parity exporter 是 wrapper 合同证据,
不计 G9。
## Remaining production gaps
当前还缺:
- 授权 JQData 真实快照、基本面公告 PIT、完整公司行动/Security Master
- Ridge/LightGBM 冻结模型包和真实 OOS 证据;
- 真实数据校准的风险、冲击、容量和 TCA;
- 真实 JoinQuant/QMT 导出;
- 券商状态映射、restart recovery daemon、20 日 shadow 与连续对账;
- 运维监控、kill-switch 演练和程序化交易合规确认。
所以 Quant OS 是可执行、可继续填证据的生产候选框架,不是已经达到整体
60 分的实盘系统。证据政策见
[`AUDIT_2026-07-25.md`](AUDIT_2026-07-25.md)。
+250
View File
@@ -0,0 +1,250 @@
# 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 的实现事实快照:
- 截至 2026-07-26 的最新标准库全量测试为 `Ran 211 tests``OK (skipped=3)`
- 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 smoke,可见日志
无 ERROR;它证明 runtime/path,但尚无完整同输入导出和本地 strict peer
- 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。
最近一次 211-test suite 和两条 Qlib fixture 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 fixture24 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. 基于已完成的聚宽 hosted smoke,冻结一个小型 canonical 平台输入并导出
close arrays/hash、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 分”。
+252
View File
@@ -0,0 +1,252 @@
# Quant OS cross-engine consistency contract
“本地、聚宽、QMT、Qlib 都能跑”不等于四条净值曲线必须逐点相同。跨引擎
一致性按层比较:相同信息集应产生相同计算;平台特有的日历、价格语义和成交
差异必须被记录、归因和限制。
## 1. Comparison levels
| Level | Compared artifact | Same canonical input required | Pass rule |
| --- | --- | --- | --- |
| L0 | Source/config manifest | Git state、portable-core hash、strategy/model version、symbol map | Exact |
| L1 | Data/universe | `as_of`、sessions、symbols、PIT membership、raw/factor/declared adjusted prices、tradability | Exact values or explicit provider reason |
| L2 | Signal | symbol、horizon、lookback/skip、score、model bundle | Exact symbol setnumeric tolerance below |
| L3 | Target | target weight/quantity、frozen/sellable state | weight toleranceexact lot quantity |
| L4 | Order intent | ID、side、quantity、limit、type、TIF、timing、reason | Identical broker snapshot/rules 时 exact |
| L5 | Order/fill/portfolio | status、fills、fees、cash、positions | Semantic invariants;相同 fill fixture 才要求 exact |
| L6 | Performance | return、turnover、drawdown、cost | Diagnostic;不能代替 L1—L5 |
只比较 L6 不会通过 G9。Alpha158/LightGBM 与 portable momentum 是不同 model
spec,本来就不是 L2 peer;可做研究比较,不能冒充同策略 parity。
## 2. Canonical snapshot is the L1 handoff
JQData ingestion 通过官方 `get_bars` 保存:
- raw `open/high/low/close/volume/money`
- `factor``pre_close``high_limit``low_limit``paused`
- 每个 member-date 的 PIT `is_st`
- 每个交易日的历史指数成员。
快照必须保持 `adjustment=none`front-adjusted feature history 在每个
decision `as_of` 时由当时已保存的 raw close + factor 构造。这样执行价仍是
raw,且后来的 factor 不能改写旧决策。
L1 verifier 不只比文件 hash,还要:
1. 拒绝 incomplete marker
2. 要求目录是 manifest 声明的精确 artifact 集;
3. 重建每个 bar/membership 领域对象;
4. 重算质量统计、内容 hash 与 `data_version`
5. 拒绝重复键、非法 OHLC、停牌非零量、非法限价、缺失 factor 或非布尔/
缺失 `is_st`
6. 拒绝 retrieval 当日仍未在 Asia/Shanghai 24:00 完成的日线。
验证入口:
```bash
PYTHONPATH=src:. python -c \
"from quant60.data_snapshot import verify_data_snapshot; verify_data_snapshot('data/snapshots/csi500-2024/manifest.json')"
```
`snapshot-backtest``snapshot-decision` 都先通过该 verifier。它们能证明
同一个 snapshot 的本地可重放性,但在真实授权 JQData run 和平台导出前,
不能证明 provider entitlement 或 G9。
## 3. Required run manifest
每个 comparison 至少保存:
```json
{
"run_id": "unique-id",
"engine": "local|joinquant|qmt_builtin|qmttools|xttrader|qlib",
"mode": "fixture|provider_snapshot|backtest|simulation|shadow|live",
"git_commit": "commit-or-DIRTY",
"portable_core_sha256": "sha256",
"strategy_or_model_version": "immutable-id",
"python_version": "major.minor.patch",
"platform_version": "value-or-unknown",
"config_hash": "sha256",
"data_version": "immutable-id",
"rules_version": "immutable-id",
"timezone": "Asia/Shanghai",
"signal_as_of": "ISO-8601 timestamp",
"last_feature_bar": "ISO-8601 date-or-time",
"first_executable_time": "ISO-8601 timestamp",
"price_adjustment": "raw|pre|post|front_ratio|PIT_FRONT_FROM_RAW_AND_FACTOR",
"fill_model": "declared-name",
"evidence_class": "fake|synthetic|provider-snapshot|real-platform|broker"
}
```
unknown platform version 可用于 smoke,但阻止 release certification。
本地 execution/provider snapshot run 保存后执行:
```bash
PYTHONPATH=src:. python -m quant60 verify-manifest \
artifacts/<run-id>/manifest.json
```
它检查 incomplete marker、精确 artifact set/hash、ledger chain/head、
report/manifest identity、saved/current source/schema aggregate 和 payload
schema。snapshot decision 使用:
```bash
PYTHONPATH=src:. python -m quant60 verify-snapshot-decision \
artifacts/<decision-id>/manifest.json
```
## 4. Numeric and semantic tolerances
对传入 `portable_core.py` 的同一固定 close arrays
| Field | Tolerance |
| --- | --- |
| canonical symbol、rank、selected set | Exact |
| momentum score | absolute error ≤ `1e-12` |
| target weight | absolute error ≤ `1e-10` |
| target quantity | Exact integer |
| order delta | Exact signed integer |
真实 provider 数据先比较输入数组。不同复权约定、停牌填充、成分股日期或
feature cutoff 导致的 score 差异是 L1 failure,不是浮点噪声。
本地货币 ledger 按配置的 currency quantum 比较。hosted NAV 只有在 bars、
company actions、fees 和 fill events 都相同时才要求相同;否则必须分类:
- `input-price difference`
- `timing difference`
- `tradability/fill difference`
- `explicit-fee difference`
- `residual unexplained difference`
residual 必须为零或低于 release-specific bound,不能静默并入 slippage。
## 5. Clock alignment
canonical weekly clock 是 ISO 周第一实际交易日完整 close,紧接着下一实际
交易日 open。它不是固定星期几;单交易日长假周会自然跨到下一 ISO 周。
comparison key 必须包含:
```text
(signal_as_of, last_feature_bar, first_executable_time, adjustment_mode)
```
任一元素不同就不是 strict peer,只能做诊断 comparison。
本地 snapshot backtest 使用:
- exact daily PIT membership
- decision date raw close + factor 构造 point-in-time front-adjusted signal
- next session raw open 执行;
- provider daily pause/limit/pre-close
- provider daily PIT `is_st`ST 不新买,已持有 ST 只卖;
- prior-session volume capacity。
JoinQuant/QMT 必须导出相同输入或其 hash 才能进入 L2—L4 strict comparison。
## 6. Platform interpretation and current facts
- **Local**:固定 fixture 的 deterministic contract oracle,不自动等于市场
真相。
- **JoinQuant**:以前一交易日查询 PIT index/ST,以批量 `history` 读取完成
日线,并显式设置费用、滑点和 10% 参与率;必须导出实际 close
arrays/hash、plan、orders/fills 和平台配置。本地 fake harness 只证明
wiring。2026-07-26 已完成一次 2024 全年真实 hosted smoke,运行日志无
ERROR;但尚未导出上述相同输入与分层结果,所以它是 runtime evidence
不是 strict peer/G9 证据。
- **QMT built-in / qmttools**:共享 bundle 但生命周期不同,均硬
backtest-only;固定中证 500 benchmark,以历史 timetag 查询 PIT 成分/ST。
built-in 的 10% 最大成交量占比需要 QMT UI 设置并取证,qmttools
程序化传入。真实 QMT 环境尚未运行。qmttools 把 transfer fee 折入
commissionminimum commission/fill 行为是声明差异。
- **XtTrader**:比较 broker snapshot、order intent 与 normalized callback。
当前已有只读 HMAC 账户绑定、broker observation/snapshot 和 exact
shadow-plan verifier,但只有 fake broker contract,没有真实 shadow。
- **Qlib momentum**`pyqlib==0.9.7` 的 native fixture 已真实运行,产生
24 条 signal;结果保存 signal/report hash、表边界和从 report 重算的
portfolio 指标。它证明 runtime/path 可执行,不证明真实市场或 L3/L4。
- **Qlib Alpha158/LightGBM**fixture 上已真实完成 model + Recorder。
runner 自动以 `setdefault` 设置 `MLFLOW_ALLOW_FILE_STORE=true` 以兼容本地
MLflow file store,并读取 portfolio report 保存 hash、边界和重算指标。
两股票 synthetic 性能没有投资意义,且该模型不是 portable momentum 的
parity peer。
- **Mock parity exporter**:当前能逐层比较 JoinQuant/QMT fake wrapper 的
score、weight、quantity、delta,并校验 source hash。它明确是
`mock_contract_only``real_platform_pass=false``gate_credit=[]`
## 7. Difference reason codes
必须使用枚举 reason code,不能只写“平台差异”:
```text
CALENDAR
SYMBOL_MAP
UNIVERSE
MISSING_BAR
SUSPENSION_FILL
PRICE_ADJUSTMENT
AS_OF_CLOCK
ROUNDING
FEE_SCHEDULE
PRICE_LIMIT
T_PLUS_ONE
VOLUME_LIMIT
FILL_MODEL
BROKER_STATE
FLOAT_TOLERANCE
UNEXPLAINED
```
symbol set、signal、target、order intent、cash 或 position 出现任何
`UNEXPLAINED` 都阻止 release。
## 8. Runnable comparison support
mock-only exporter
```bash
PYTHONPATH=src:. python tools/export_mock_parity.py \
export --output artifacts/mock-parity/report.json
PYTHONPATH=src:. python tools/export_mock_parity.py \
verify artifacts/mock-parity/report.json
```
Qlib native momentum fixture
```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
```
两者都不是 G9 的真实平台证据。
## 9. What counts toward G9
| Evidence | Counts toward G9? |
| --- | --- |
| symbol/unit tests、fake JoinQuant/QMT harness | Supporting only |
| mock parity exporter | Nocontract regression only |
| local snapshot twice with same hash | Supporting G7/L1 only |
| Qlib 24-signal synthetic fixture smoke | Runtime evidence only |
| Qlib Alpha158 synthetic Recorder smoke | Research runtime evidence only |
| real JoinQuant export vs local canonical run | Yes,覆盖的 layers/dates |
| licensed qmttools run with saved version/result | Yes,覆盖的 layers |
| XtTrader shadow using real broker snapshot | Yespre-trade/order semantics |
| ≥20 trading days QMT shadow, zero unexplained differences | 文章 G9 必需 |
真实 JoinQuant smoke 已运行;QMT 和 broker shadow 尚未运行,而且
JoinQuant 仍缺同输入导出与 local peer,所以 G9 继续为 `not_passed`
状态权威是
[`gate_scorecard.json`](../gate_scorecard.json)。
@@ -0,0 +1,73 @@
# JoinQuant hosted backtest evidence — 2026-07-26
This is a real hosted-runtime smoke record, not a cross-engine acceptance
report and not an investment-performance claim.
## Run identity
- Strategy: `quant_os_portable_momentum_v1`
- Hosted record:
[JoinQuant backtest detail](https://www.joinquant.com/algorithm/backtest/detail?backtestId=62de09f1e0f9e81b260a18e0ee59e953)
- Period: 2024-01-02 through 2024-12-31
- Initial capital: CNY 1,000,000
- Frequency/runtime: daily, Python 3
- Benchmark: CSI 500 (`000905.XSHG`)
- Uploaded bundle:
`dist/joinquant_strategy.py`
- Uploaded bundle SHA-256:
`22ddb0546beb3bd4e4bbedecb271452111324c3903e45be1f4ac3d39f38cce4f`
- Portable core SHA-256:
`af29e4e5e10705cf6aff89874394c1e80d3780f093c19d90ed53ef9d0188a934`
## Hosted result
| Metric | Hosted value |
| --- | ---: |
| Strategy return | -19.98% |
| Annualized return | -20.56% |
| Excess return | -24.12% |
| Benchmark return | 5.46% |
| Alpha | -0.259 |
| Beta | 0.830 |
| Sharpe | -0.806 |
| Win rate | 0.474 |
| Profit/loss ratio | 0.816 |
| Maximum drawdown | 32.45% |
The visible completed-run log contained zero `ERROR`, `Traceback`, or
`订单委托失败` entries. These performance numbers are negative and are recorded
only to prove that the hosted execution path completed; they provide no
investment-value evidence.
## Defects found by the hosted runtime
The real platform run found three issues that fake wiring alone did not expose:
1. JoinQuant's hosted namespace shadowed Python's global `sum`. The portable
core now uses its own deterministic numeric reducer.
2. STAR Market market orders require worst-price protection. The wrapper now
submits a documented `LimitOrderStyle`: daily upper limit for buys and daily
lower limit for sells, and fails closed when that price is absent or invalid.
3. STAR Market auction orders require at least 200 shares, except a complete
sale of the remaining sub-200 balance. The rule now lives in the shared
portable core and local simulator, so JoinQuant and QMT receive the same
legal target/order delta.
The order API and limit-style contract are documented in the
[official JoinQuant API PDF](https://cdn.joinquant.com/help/img/JoinQuantAPI.pdf).
The 200-share minimum and remaining-balance exception are described by the
[Shanghai Stock Exchange](https://edu.sse.com.cn/tib/).
## Evidence boundary
This record proves that one real JoinQuant daily backtest completed with the
uploaded wrapper. It does **not** pass G9 because the following evidence is
still missing:
- a complete hosted export containing input close arrays or hashes, the
portable plan, orders and fills;
- a local canonical run over the exact same frozen inputs;
- layer-by-layer L1—L4 comparison with enumerated difference reasons;
- a real QMT peer run and at least 20 trading days of broker shadow evidence.
Accordingly, `gate_scorecard.json` remains `NOT_BASELINE_60`.
+116
View File
@@ -0,0 +1,116 @@
# Quant OS platform capability matrix
“有入口”与“已在目标平台验证”必须分开。Quant OS 共享的是冻结计算合同,
不是四个平台完全相同的时钟、行情和成交模型。
| Path | Intended use | Runtime / prerequisite | Current verified fact | Missing release evidence |
| --- | --- | --- | --- | --- |
| Local synthetic execution | 确定性事件回测、ledger/replay | Python ≥3.10,无账号 | 标准库套件最近记录为 211 tests、OK、3 skipsmoke + exact manifest verifier 可运行 | synthetic 不代表真实市场/收益 |
| Local synthetic research | PIT/features/walk-forward/Ridge/risk/cost/target | Python ≥3.10,无账号 | research smoke + manifest verifier 可运行 | Ridge 未冻结部署,未做授权长样本 OOS |
| JQData ingestion | 授权数据到 canonical immutable snapshot | `jqdatasdk==1.9.8` + 授权账号 | fake-provider 测试覆盖 raw/factor/pre-close/limits/paused/PIT `is_st`/membership、24:00 完整收盘约束和语义 verifier | 尚未登录真实账号保存快照、许可与 lineage |
| Snapshot local backtest | PIT membership 的 provider-data 本地回测 | semantic verifier 通过的 snapshot | `snapshot-backtest` 复用 production decision path,输出普通 run manifest | 尚无授权真实 snapshot;仍是本地 fill model |
| Snapshot decision | 某决策日 Signal/Target/Order Delta | snapshot + equity 或完整 broker snapshot | fail-closed broker state 与 exact decision manifest verifier 已实现 | 未接真实账户 snapshot,未冻结生产模型 |
| Colab | clone、测试、bundle、本地两条 synthetic 链;可选 JQData/Qlib | Colab runtime | notebook 已可本地逐 cell 执行 | 可选账号/依赖 cell 仍需运行时授权;不是平台证据 |
| JoinQuant local harness | wrapper API 合同 | Python ≥3.10,无账号 | fake lifecycle 与 mock parity 可运行 | 不证明 JoinQuant |
| JoinQuant hosted bundle | hosted backtest | JoinQuant 登录/数据权限 | 真实 2024 全年 run 已完成且可见日志 0 ERROR;单文件、PIT index/ST、批量 history、费率/滑点/10% 参与率、科创板保护价/200 股约束已运行 | 尚无完整输入/plan/orders/fills 导出和同输入本地比较 |
| QMT local harness | built-in wrapper 合同 | Python ≥3.10,无账号 | Python 3.6 source、`ContextInfo` 回滚模拟和 mock parity | 不证明 QMT |
| QMT built-in bundle | GUI backtest-only | 授权 QMT 客户端/板块与历史 ST 数据 | bundle 硬限制 backtest;毫秒 timetag PIT 成分/ST;固定中证 500、费率/滑点;模块全局 `g` | 尚无真实 QMT run/export10% GUI 配置与历史 ST 正例探针待取证 |
| qmttools runner | native-Python QMT backtest/history | 券商分发 `xtquant` + 已登录 terminal | 固定中证 500/10% 参与率、参数、只读 preflight 和 hard backtest/history 合同已测 | 尚无专有运行时实跑 |
| XtTrader read-only shadow | 账户绑定 target-diff 与 broker observation | MiniQMT/QMT、账户查询权限、既有本地 HMAC key | HMAC 账户绑定 + authenticated evidence envelope、decision/observation semantic replay、资产/持仓/委托/成交恒等式、fail-closed exact verifier 与 fake broker 合同 | HMAC 不是 broker attestation;仍缺官方 query 失败/空结果合同、callback/restart、20 日真实 shadownot live-ready |
| Qlib native momentum | signal/model research | CPython 3.12 + exactly `pyqlib==0.9.7` | 真实本地 fixture 成功,24 signal;保存 signal/report hash、表边界和重算 portfolio 指标 | synthetic 两股票;无真实数据/OOS,无 L3/L4 parity |
| Qlib Alpha158/LightGBM | model fit + Recorder workflow | 同上 + LightGBM/MLflow stack | 真实 fixture 完成 model/Recorder;读取 portfolio report,保存表 hash、边界、重算指标与 artifact path | synthetic 两股票性能无意义;真实 provider/OOS 和冻结模型缺失 |
| Mock parity exporter | JoinQuant/QMT wrapper 的 L2—L4 合同回归 | Python ≥3.10 | `mock_contract_only``real_platform_pass=false``gate_credit=[]` | 不计 G9;必须换成真实平台导出 |
G1—G10 当前都未通过。JoinQuant hosted smoke 与 Qlib fixture smoke 是真实
runtime 证据,但不是市场有效性或跨平台 Gate 通过证据。
## Stable strategy boundary
当前四引擎共同可冻结的是 `portable-momentum-v1`
- canonical symbol normalization
- momentum score/rank
- capped target weights
- lot-rounded target quantity
- T+1/sellable-aware order delta。
- 科创板 200 股最小申报、余额一次性卖清与 hosted 最坏价保护。
本地 Ridge 与 Qlib Alpha158/LightGBM 是研究候选。没有 versioned model
bundle、授权真实 OOS 和跨引擎推理结果前,不能称为已部署 champion。
Qlib 的单一 `limit_threshold` 是市场级近似,不能表达逐日板块/ST 限制;
因此它只参加 L1/L2 和诊断 L6。XtTrader mutation 边界目前只接受 `.SH`
`.SZ`,北交所 symbol conversion 覆盖不等于北交所实盘覆盖。
## Platform terms
- **QMT built-in**`init` / `handlebar` 在 QMT 管理的 Python 3.6 环境执行。
用户状态放在模块全局 `g`,避免 `ContextInfo` 用户属性在下个
`handlebar` 回滚。
- **qmttools**native Python 通过 `run_strategy_file` 驱动策略文件。
supplied runner 固定 backtest/history,不能等同于 XtTrader OMS。
- **XtTrader**:连接 MiniQMT 的查询、报单/撤单与异步推送 API。存在 guarded
mutation path 不代表券商认证或 live-ready;本项目对 operator 暴露的
shadow CLI 严格只读,没有报单/撤单命令。
- **fake harness**:函数名和生命周期匹配的本地对象,只用于合同回归。
- **Qlib Recorder**:研究 artifact 记录机制。两股票 synthetic Recorder
成功不等于模型有投资价值。
## Minimum verification commands
`quant-os` 项目根目录运行:
```bash
# 核心和 Colab 默认流程
make local
# JQData 快照与 semantic verifier(会交互式无回显读取密码)
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
PYTHONPATH=src:. python -m quant60 snapshot-decision \
--snapshot data/snapshots/csi500-2024/manifest.json \
--config configs/baseline.json --as-of 2024-12-31 \
--equity 1000000 --output artifacts/csi500-2024-decision
# hosted bundle 和 mock-only parity
python tools/bundle_platforms.py
PYTHONPATH=src:. python tools/export_mock_parity.py \
export --output artifacts/mock-parity/report.json
PYTHONPATH=src:. python tools/export_mock_parity.py \
verify artifacts/mock-parity/report.json
# Colab notebook 本地合同/执行
python tools/run_colab_notebook.py notebooks/quant_os_colab.ipynb
python tools/run_colab_notebook.py notebooks/quant_os_colab.ipynb --execute
# QMT 环境就绪后:先运行未绑定账户的只读 bootstrap(预期 exit 2),再用
# 输出的非 null broker_snapshot.json 重建同一 Signal 日 decision
# broker observation 本身仍来自唯一下一交易日盘前窗口。完整步骤见 runbook
PYTHONPATH=src:. python tools/qmt_shadow_plan.py plan \
--decision artifacts/latest-decision/manifest.json \
--output artifacts/qmt-shadow-bootstrap
```
后续 `verify` 必须同时提供原始 decision,并读取 plan 时使用的既有
`QMT_ACCOUNT_HASH_KEY_FILE`verify 不会补建丢失 key。manifest HMAC
envelope 绑定 plan/observation/snapshot 的内容与发布 byte hash、
decision/source(含 operator CLI/policy;四个 JSON 必须保持唯一 writer
encoding。但信任主体是本地 Quant OS key holder,不是 QMT/券商。
Qlib 和真实平台的完整命令见
[`runbooks/PLATFORM_DEPLOYMENT.md`](../runbooks/PLATFORM_DEPLOYMENT.md)。
## Version and evidence policy
每个真实 run 都要记录 JoinQuant environment、QMT client/build、
`xtquant`、broker plugin、Qlib/Python、bundle hash、data version、
config/rules hash 和实际日历。文档说明 API 存在不证明当前账号有权限;
mock/fake/synthetic 成功不证明真实平台;Qlib synthetic 成功不证明模型收益。
+201
View File
@@ -0,0 +1,201 @@
# Quant OS data, credential and live-trading safety
Quant OS 仓库需要能够被 review、clone 和推送,但不能携带可复用凭据、账户
身份、受许可限制的数据或券商专有运行时。Obsidian 只保存项目说明,也不能
成为密码、cookie 或行情文件的旁路存储。
## Never commit or copy into documentation
- JoinQuant/JQData username、password、cookie、token、session export
- QMT/MiniQMT account ID、terminal profile、userdata directory、session
file、device fingerprint
- 从持牌 QMT 安装复制出的 `xtquant` binary
- broker statement、raw callback 或含账户/个人信息的截图;
- private key、API key、`.env`、subscription URL、带凭据的 clone URL
- provider licence 不允许再分发的 raw/derived market data
- Colab notebook output 中的 secret、完整账户值或授权数据;
- MLflow/Recorder artifact 中意外缓存的环境变量、machine path 或身份信息。
`.gitignore` 不是安全边界。每次提交前必须检查 staged diff 和所有 generated
artifacts。
## Credential injection
提交到 Git 的配置只能含 placeholder。推荐本地变量:
```text
JQDATA_USERNAME
JQDATA_PASSWORD
QMT_ACCOUNT_ID
QMT_USERDATA_PATH
QMT_SESSION_ID
QMT_ACCOUNT_HASH_KEY_FILE
```
JQData adapter 优先读取本地环境变量,也支持交互式读取;密码提示无回显。
不得把密码作为 CLI 参数,因为 shell history/process list 会泄漏。
Colab 可选 JQData cell 必须在 runtime 内通过无回显 prompt/Colab secret
注入。禁止:
- 把 secret 写在 notebook source 或共享链接里;
- `print(os.environ)`、输出 auth object 或异常中的 credential
- 把带 secret 的 notebook output 下载、同步或提交;
- 运行结束后继续复用包含授权数据和 secret 的共享 runtime。
用完后清除 runtime。Colab secret 只是注入渠道,不授予数据再分发权。
QMT 账号不应作为 CLI 参数。`.env.example` 只列变量名和安全默认值;
真实 `.env` 必须保留在 operator-controlled local secret store。
不得在 `--help`、exception、run manifest、test snapshot 或 OB 文档打印上述
值。低熵账户号的普通 SHA-256 可枚举恢复;对外证据应使用 keyed one-way
identifier,并把 key 保存在独立 secret store。
`QMT_ACCOUNT_HASH_KEY_FILE` 只指向本地 HMAC key,不是 key 本身。
`qmt_shadow_plan.py plan` 在文件不存在时生成至少 32 byte 的安全随机 keyUnix
要求文件 mode 0600,并且不会为了创建 key 而放宽或改写一个已经存在的父目录
权限。`verify` 只读取既有 key,绝不会在 key 丢失时静默生成替代品。该 key
必须稳定备份和最小权限访问:轮换后账户 hash 会变化,历史 broker snapshot
与 decision 会按设计失配,历史 authenticated evidence 也无法再验签。key
内容不得进入 Git、OB、notebook、artifact、stdout、异常或聊天。
shadow manifest 保存的是 `QMT_SHADOW_EVIDENCE_V1` HMAC,不是 secret。
它用与账户标识不同的 domain 签署 canonical evidence envelope,覆盖完整
plan、broker observation、broker snapshot 的内容 hash 和三份实际发布文件
原始 byte SHA-256、原始 decision manifest hash、planner/engine 以及
`tools/qmt_shadow_plan.py` operator entrypoint source hash,并绑定固定
semantic/policy ID 和阈值。四个发布 JSON(含不自签的 manifest)必须符合
唯一 deterministic writer bytesminify、key 重排和空白变化不是等价发布物。
verifier 必须同时拿到原始 decision 与既有 key,并读取磁盘实际 bytes 重建
envelope 后用
constant-time compare 验证。普通 SHA-256 重新封装、替换 decision、改写
observation 或同步修改 plan 派生字段都不能在不知道 key 时伪造该 MAC。
这个 HMAC 的信任主体是“持有本地 key 的 Quant OS evidence publisher”。
它证明发布后没有被无 key 的第三方改写;它**不是** QMT/券商对 API 返回值的
签名,不证明终端、账号或 callback 未在采集前被攻陷。key 泄漏后攻击者可以
伪造本地 envelope,应立即按 credential incident 轮换、隔离旧证据并重新做
可信采集。
## JQData and provider-data licence
`jqdatasdk==1.9.8` adapter 可获取 raw OHLCV/money、factor、pre-close、
daily limits/paused、PIT `is_st` 和历史指数成员。可获取不等于可再分发。
首次真实 snapshot 前记录:
- provider、账户 entitlement 和允许用途;
- local/Colab 是否允许持久保存、保存期限;
- raw 与 derived data 是否可共享;
- API/field semantic version
- query、retrieval time、event/effective/available time
- partition/data hash、retention 和 deletion policy。
snapshot manifest 不含密码,但 snapshot 本身仍可能是受许可数据。默认放在
被 Git 忽略的 local storage,不上传代码仓库、OB、公开 object storage 或
公开 Colab drive。
synthetic fixture 可共享但不是市场证据。真实 JQData snapshot 只有在许可、
lineage 和语义 verifier 都完成后,才可能成为 G1 的候选证据。
## QMT proprietary and licensed boundary
`xtquant` 由持牌 QMT/MiniQMT 与券商分发。Quant OS
- 不 vendoring、不上传、不从非官方 PyPI 模仿包安装;
- 仅在 QMT-specific path 内 lazy import
- 没有专有运行时也能跑核心/fake tests
- 只使用实际券商支持的 Python 和 client/plugin 组合。
QMT 并非只提供用户名密码即可运行。还需要已授权 QMT/MiniQMT client、
匹配的 `xtquant`、userdata path、行情/历史数据 entitlement 和登录会话。
复制其他用户安装不能建立许可或兼容性。
平台导出必须先脱敏:raw account、broker order ID、userdata path、device
信息和专有异常字符串不进入 Git。
只读 shadow 的 `broker_observation.json` 只保存 keyed account hash、query
安全 envelope 和通过标准化的资产、持仓、委托、成交事实;不保存原始
account ID。manifest 通过 authenticated evidence HMAC 将 observation、
broker snapshot、plan、decision、source 和 canonical policy 绑定。即便如此,
它仍可能包含敏感持仓/交易信息,只能放在被 Git 忽略且访问受控的证据目录。
## Qlib, MLflow and Colab artifacts
Qlib 固定为 CPython 3.12 + `pyqlib==0.9.7`。Alpha158 runner 为本地
MLflow file store 使用:
```text
MLFLOW_ALLOW_FILE_STORE=true
```
这是对 local backend 的显式兼容确认,不是安全授权,也不会替代访问控制。
Recorder 目录可能包含 model、label、prediction、code cache/status 和
provider-derived output;提交前必须按 provider licence 与 secret scan
检查。真实模型 artifact 应存放在访问受控、可审计的 artifact store。
不要在公开 Colab runtime 上加载券商文件。JQData/Qlib 可选流程只处理研究
数据;QMT/XtTrader 应留在受控且持牌的本地/Windows 环境。
## Default live posture
所有 broker-facing 路径默认只能是:
```text
BACKTEST
SIMULATION
SHADOW
```
QMT built-in 和 qmttools supplied runner 硬限制 backtest/history。XtTrader
`allow_live_orders` 默认 false,仓库不提供 live launch command。
未来任何 live mutation 至少还要求:
1. broker read-only preflight 成功;
2. market data 与完整 broker snapshot 新鲜且带时区;
3. account allow-list 匹配;
4. 无 unknown open order 或 reconciliation difference
5. notional/order/rate limit 已配置;
6. operator approval 与 kill switch 已演练;
7. 程序化交易报告和软件/频率要求由实际券商确认;
8. shadow、重启恢复和连续日终对账达到 release 条件。
环境变量本身不构成批准。mock guard、fake broker 和单元测试也不构成券商认证。
## Safe evidence and redaction
可安全导出的候选内容:
- source/config/data/rules/model hash
- canonical symbols 和非受限聚合;
- order state/reason code
- keyed account hash
- 在不需要精确值时脱敏/取整的 operational metric。
需要删除或保护:
- raw account 和可关联 broker order ID
- 用户 machine path、用户名、device/profile 信息;
- proprietary client exception
- notebook cell output 中的 token/credential
- provider licence 不允许公开的数据行。
审计所需原始版本应留在加密、访问受控的本地/企业存储,而不是为了方便直接
提交 Git。
## Incident response
如果 credential、账户标识或授权数据进入 Git/OB/Colab output
1. 停止新订单和相关自动任务;
2. 通过 provider/broker 撤销或轮换 credential
3. 在仓库外保存 incident timeline
4. 从当前树移除,并在明确批准后清理历史和 mirror;
5. 检查 CI、artifact、OB sync、Colab/Drive 和 downstream clone
6. 评估数据许可/个人信息泄漏范围并完成必要通知;
7. 记录恢复和复发预防。
删除可见文件不等于 credential rotation。交易与数据故障流程见
[`runbooks/INCIDENTS.md`](../runbooks/INCIDENTS.md)。