Files
quant-os/docs/CROSS_ENGINE_CONSISTENCY.md
T

253 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)。