Files
quant-os/docs/CROSS_ENGINE_CONSISTENCY.md
T

10 KiB
Raw Blame History

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
  • factorpre_closehigh_limitlow_limitpaused
  • 每个 member-date 的 PIT is_st
  • 每个交易日的历史指数成员。

快照必须保持 adjustment=nonefront-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 完成的日线。

验证入口:

PYTHONPATH=src:. python -c \
  "from quant60.data_snapshot import verify_data_snapshot; verify_data_snapshot('data/snapshots/csi500-2024/manifest.json')"

snapshot-backtestsnapshot-decision 都先通过该 verifier。它们能证明 同一个 snapshot 的本地可重放性,但在真实授权 JQData run 和平台导出前, 不能证明 provider entitlement 或 G9。

3. Required run manifest

每个 comparison 至少保存:

{
  "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 保存后执行:

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 使用:

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 必须包含:

(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_stST 不新买,已持有 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 momentumpyqlib==0.9.7 的 native fixture 已真实运行,产生 24 条 signal;结果保存 signal/report hash、表边界和从 report 重算的 portfolio 指标。它证明 runtime/path 可执行,不证明真实市场或 L3/L4。
  • Qlib Alpha158/LightGBMfixture 上已真实完成 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_onlyreal_platform_pass=falsegate_credit=[]

7. Difference reason codes

必须使用枚举 reason code,不能只写“平台差异”:

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

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

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