Files
quant-os/docs/ARCHITECTURE.md
T

310 lines
16 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 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
snapshot-backtest / snapshot-decision
portable-momentum-v1 compatibility path (smoke only)
local Baseline authority:
Universe
-> frozen Ridge model bundle / Alpha
-> risk + cost-aware Portfolio
-> post-risk TargetPackageV1 (weights, no account quantities)
-> five-layer hash trace
|
+------------+-------------+
| |
JoinQuant consumer QMT consumer
T+1-open account bind completed-close bind + quickTrade=0
order_target passorder (backtest-only)
Current TargetPackage fixture is synthetic research evidence, not market proof.
Qlib 0.9.7:
Tushare completed/checksummed Parquet -> immutable managed provider
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
本地 Tushare 镜像是独立只读输入边界。adapter 只信任 SQLite 中 completed
job,并重新核对文件大小、SHA-256、Parquet 行数/footerQlib provider
发布到新目录,manifest 绑定 source job、build parameter、converter source、
完整 provider tree 和可重算 `data_version`。当前镜像未完成且缺复权、
真实 benchmark、历史成分/ST/停牌/涨跌停,因此只能进入 Qlib 技术 smoke
不能直接进入 canonical production decision。完整合同与实跑证据见
[`TUSHARE_LOCAL_DATA.md`](TUSHARE_LOCAL_DATA.md)。
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 vertical slice 当前实际接通:
- PIT table 和未来值拒绝;
- Universe 原因码;
- 透明价量特征与 T+1-open 标签时钟;
- train-only winsor/impute/standardize
- purge/embargo walk-forward
- deterministic Ridge、OOS IC/RankIC 与可重放 model bundle
- 60 日对角 realized variance
- dated explicit fee + spread + square-root impact/capacity
- deterministic constrained portfolio、独立 post-risk gate
- reference execution binding、完整五层 hash trace 与 TargetPackageV1。
`factor_risk.py`、CVXPY 路径和 guarded TWAP/POV 仍是有单测的独立组件,
不在上述 vertical slice 中。Ridge 已能冻结预处理、系数、标签、训练截止日
和 lineage,但目前只有 synthetic 候选;没有授权真实长样本 OOS、真实风险/
成本校准、多期逐层 parity 或 QMT peer,因此不是生产 champion。已有的单包
JoinQuant run 只观察 execution consumer。
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")` 显式确认。
- 本地 Tushare completed 分区已生成 managed provider;早期未复权动量
smoke 在 `PYTHONHASHSEED=0` 下连续两次得到逐 byte 相同的 evidence JSON。
该 fixture 只有两只股票和一个 benchmark,性能没有投资意义。Qlib 的单一
`limit_threshold` 也不能表达逐日板块/ST 规则,所以它只参与 L1/L2 和诊断
L6,不声称 L3 target 或 L4 order-intent parity。
## Portable strategy and platform boundary
hosted artifact 有两个互斥模式:
- `portable_momentum_smoke`:保留历史连通性回归,平台端计算动量;
- `target_package`:本地唯一权威已完成 Universe/Alpha/Portfolio/Risk
hosted wrapper 只验证包、精确匹配 `signal_as_of + next_session`、读取账户
事实并构造 execution plan,绝不回退到 momentum。
`portable-momentum-v1` 不是生产 Baseline。TargetPackage 只有权重,没有股数、
现金、订单或成交;这些属于下一交易日平台账户绑定后的 execution layer。
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` 用户属性。动量 smoke 路径固定中证 500 benchmark、PIT 历史
成分/ST 与费率;TargetPackage 路径消费本地冻结 Universe/权重,不重新计算
Alpha/Portfolio/Risk。built-in 的 10% 参与率由 QMT GUI 设置,qmttools
程序化传入。live mutation 只存在于外部 XtTrader adapter,并且默认关闭、
未认证、没有 live 启动命令;operator 可运行的 shadow CLI 只接受查询边界。
## Stable artifacts and release integrity
最低交换合同是:
- [`model_bundle.schema.json`](../schemas/model_bundle.schema.json)
- [`target_package.schema.json`](../schemas/target_package.schema.json)
- [`release_reachability.schema.json`](../schemas/release_reachability.schema.json)
- [`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 承担
各自边界的同类职责。
`release_reachability` 对每层分别记录 `implemented``unit_tested`
`local_entrypoint_reachable``jq_entrypoint_reachable`
`qmt_entrypoint_reachable``real_platform_observed`,并逐文件验证路径与
SHA。源文件总 hash 不能冒充真实运行。测试结果仍不能替代 schema 迁移演练、
真实平台导出或券商回调认证。当前只有
`execution.real_platform_observed=true`,由一个真实 JoinQuant
TargetPackage smoke 支持;其他四层及 all-layer summary 仍为 false。
## 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
- 授权真实数据训练的冻结模型包和真实 OOS 证据;
- 真实数据校准的风险、冲击、容量和 TCA;
- 授权真实数据的多期 JoinQuant 导出、逐层本地对账与真实 QMT peer;
- 券商状态映射、restart recovery daemon、连续对账,以及 Production 80
要求的同一冻结候选 60 日 shadowBaseline 60 的前置门槛为 20 日);
- 运维监控、kill-switch 演练和券商程序化交易报告/核查确认。
所以 Quant OS 已具备本地五层 vertical slice 与 TargetPackage 平台边界,
但仍只是可继续填证据的候选骨架,不是已经达到整体 60 分的实盘系统。证据政策见
[`AUDIT_2026-07-25.md`](AUDIT_2026-07-25.md)。