# Tushare 本地数据盘点、Qlib 接入与回测手册 截至 2026-07-26,Quant OS 已能只读盘点另一个任务生成的 Tushare Parquet 镜像,校验已完成分区,并转换为不可变的 Qlib 0.9.7 provider。 这条路径已经完成两次 byte-identical 的本地动量回测。 当前证据的边界是: ```text completed_partitions_only_not_full_mirror production_ready = false investment_value_claim = false gate_credit = [] ``` 它证明“本地 Tushare 数据可以进入 Qlib 并可重放”,不证明镜像已经下载完整, 也不证明策略收益有效或 Quant OS 已达到 `BASELINE_60`。 ## 1. 2026-07-26 点时盘点 镜像中共有 93 个状态为 `completed` 的 Parquet,均通过 SQLite 记录的文件大小、 SHA-256 和 Parquet row count 校验;另有 1 个遗留 `running` job。 | 表 | 文件数 | 行数 | 当前范围/说明 | | --- | ---: | ---: | --- | | `daily` | 35 | 28,731 | 1990-12-19—1993-10-29,138 个代码、731 个交易日 | | `trade_cal` | 37 | 13,004 | SSE 1990—2026 日历,8,689 个开市日 | | `stock_basic` | 4 | 5,869 | 当前上市/退市/暂停上市等基础快照 | | `stock_company` | 3 | 6,294 | SSE/SZSE/BSE 公司资料 | | `index_basic` | 7 | 9,643 | CSI/SW/SSE/SZSE 等指数基础资料 | | `index_classify` | 6 | 870 | 申万 2014/2021 分类 | | `bse_mapping` | 1 | 248 | 北交所新旧代码映射 | | **合计** | **93** | **64,659** | **5,734,035 bytes Parquet** | `daily` 原计划覆盖 1990-12—2026-07,共 428 个月;当前完成 35 个月,约 8.2%。下载进程已停止,SQLite 仍遗留 `daily/month=1993-11` 的 `running` 状态。日志显示首先发生 DNS 解析失败, 错误处理阶段又发生 `sqlite3.OperationalError: unable to open database file`。因此不能把这个状态解释为仍在后台下载,也不要在 Quant OS 转换过程中修改或自动恢复原下载器。 尚未落盘的生产关键表包括: - `adj_factor`、`index_daily`; - `index_member_all`、`index_weight`; - `stk_limit`、`suspend_d`、`stock_st`; - `daily_basic`。 其中历史 `stock_st` 权限探测被拒绝。即使其他下载完成,历史 ST 仍需要新的 授权数据源或明确的降级门禁。 ## 2. 已确认的数据质量 - 已完成 Parquet 自然键无重复,核心日线字段无空值; - 无负成交量或负成交额,日线日期与同期 SSE 开市日完全对应; - 17 条早期 OHLC 包络异常;默认拒绝,只有显式 `--ohlc-policy expand-range` 才按原始 `open/high/low/close` 四价的 min/max 修复,并记录数量与异常键 hash; - 2 条 `pct_chg` 与保存精度下重算结果的偏差超过 0.02 个百分点; - 日线代码 `000022.SZ` 不在当前 `stock_basic` 快照; - `stock_basic` 存在遗留非标准代码 `T600018.SH`,转换器不会把它当成 A 股代码; - `index_basic.base_point` 存在分区类型漂移,后续 canonical 合并时必须 显式 cast。 Tushare 的 `daily` 是未复权行情,停牌期间不返回记录;`vol` 单位为手, `amount` 单位为千元。转换器固定执行: ```text 600000.SH -> SH600000 000001.SZ -> SZ000001 430047.BJ -> BJ430047 volume = vol * 100 money = amount * 1000 factor = 1 ``` 未上市、退市后和停牌缺口在 Qlib feature 中保留为 `NaN`。字段语义来源见 [Tushare 日线接口](https://tushare.pro/document/2?doc_id=27)与 [复权因子接口](https://tushare.pro/document/2?doc_id=28)。 ## 3. Quant OS 如何使用这些数据 当前已经实现的链路是研究/引擎验证路径: ```text Tushare mirror -> 只读取 SQLite completed jobs -> 文件大小 + SHA-256 + Parquet row count/footer 校验 -> 新目录原子发布 Qlib binary provider -> provider tree hash + data_version + manifest verifier -> Qlib momentum / Alpha158 research runner ``` 正式 Quant OS 还需要第二条生产数据路径: ```text 完整 Tushare/JQData PIT 数据 -> canonical immutable snapshot -> Quant OS 本地事件回测 / decision -> 聚宽、QMT、Qlib 的同输入分层比较 ``` Qlib 适合因子、模型和组合研究,不拥有原始数据,也不替代 Quant OS 的 Signal/Target/Order/Broker 合同。当前 Tushare adapter 只实现第一条链路; 在复权、真实 benchmark、历史成分、停牌、涨跌停和 ST 数据补齐前,不会把它 接入生产 decision。 ## 4. 可运行命令 从 Quant OS 根目录执行。镜像路径只放在当前 shell 环境变量中,不写入 Git: ```bash export QUANT_OS_ROOT=/path/to/quant-os export TUSHARE_MIRROR_ROOT=/path/to/tushare-mirror cd "$QUANT_OS_ROOT" python3.12 -m venv .venv-qlib312 source .venv-qlib312/bin/activate python -m pip install -r requirements/research-py312.txt export PYTHONPATH=src:. ``` 盘点并验证全部 completed 文件: ```bash python tools/tushare_qlib.py inventory \ --mirror-root "$TUSHARE_MIRROR_ROOT" \ --output-json artifacts/tushare-inventory.json ``` 当前未复权数据只能显式构建技术验证 provider;每次必须使用新目录,工具拒绝 覆盖已有 provider: ```bash python tools/tushare_qlib.py build \ --mirror-root "$TUSHARE_MIRROR_ROOT" \ --output-dir data/qlib/tushare-early-v1 \ --start 1990-12-19 \ --end 1993-10-29 \ --minimum-observations 60 \ --allow-unadjusted \ --ohlc-policy expand-range \ --output-json artifacts/tushare-qlib-build.json python tools/tushare_qlib.py verify \ data/qlib/tushare-early-v1 \ --output-json artifacts/tushare-qlib-verify.json ``` 运行 Qlib 0.9.7 本地回测: ```bash PYTHONHASHSEED=0 python -m platforms.qlib_runner \ --provider-uri data/qlib/tushare-early-v1 \ --market tushare_a \ --benchmark SH999999 \ --start 1992-01-02 \ --end 1993-10-28 \ --feature-start 1991-01-02 \ --lookback 20 \ --topk 10 \ --n-drop 2 \ --rebalance weekly \ --output-json artifacts/tushare-qlib-momentum.json ``` Qlib simulator 会消费结束日后的下一 provider session,所以 backtest `end` 必须早于 provider 最后一个交易日。Quant OS 对受管 provider 会在 Qlib 初始化前检查 market、benchmark、起始边界和这个终点条件。 `artifacts/` 与 `data/qlib/` 均被 Git 忽略。原始 Parquet、token、绝对镜像 路径和回测临时产物不得提交到仓库。 ## 5. 本次真实本地运行证据 最终 v4 provider: | 证据 | 值 | | --- | --- | | adapter source SHA-256 | `2228c23af176a0f2fcf311e88dca9bdc5d63fd36fa5a3c2d3e42808a405e7243` | | data version | `3378aa75a5601bde476ad07bea90418966a66a037ca59195dec93d77b41cc3f8` | | provider tree SHA-256 | `dc85b8daf692a66641afef64398700264c6054f1dac84b1211cb258a06b62948` | | manifest SHA-256 | `862e7435bb0be7c8a3c66180e49761c110056c1a3cc02c1618e70d9eb566d945` | | provider 文件/大小 | 975 / 1,085,886 bytes | | calendar | 1990-12-19—1993-10-29,731 sessions | | market | 107 个至少有 60 条记录的 A 股代码 | | selected rows | 27,998 | 回测参数为 1992-01-02—1993-10-28、20 日动量、周频、Top 10、每期 drop 2, 初始资金 1,000 万,Qlib 0.9.7、Python 3.12.13、`PYTHONHASHSEED=0`。 相同命令连续执行两次,结果 JSON 逐 byte 相同: | 证据/指标 | 值 | | --- | ---: | | result JSON SHA-256 | `92ff9b8cea746e9c89ddf62fcfe3feb21248ca9112d9e10d24e0639058a86020` | | runner source SHA-256 | `fa8118819252c55e99e67de356cc961d8a4a22f82256b4d62579a45426d96167` | | signal | 4,700 行;hash `cfad4087d68b7f71e33f0f46fc5bb97db985e02ac2515f01857e2ab6813a5909` | | portfolio report | 466 行;hash `5f8606fb64963d3e2618f66503e6ae94048c24b62c5d8e1806ff44ec57558b04` | | strategy cumulative return | -52.5251% | | max drawdown | -87.7604% | | synthetic benchmark cumulative return | 196,302.0822% | | total cost / turnover | 0.016013 / 29.567521 | 这些收益数字没有投资解释。原因包括未复权早期行情、没有真实指数 benchmark、 没有历史成分/ST/停牌/涨跌停、按全区间至少 60 条观测筛选带来的非 PIT 偏差,以及 1992—1993 特殊市场阶段。极端 synthetic benchmark 恰好说明 为什么“程序跑完”不能等价为“回测有效”。 ## 6. 何时可以升级为正式研究数据 至少完成以下步骤后,才能新建 production-eligible provider: 1. 修复下载器错误状态并完成目标日期的 `daily`; 2. 补齐 `adj_factor`,冻结复权基准日和公式; 3. 使用 `index_daily` 替换合成 benchmark; 4. 指数策略补齐 `index_member_all/index_weight`; 5. 补齐 `suspend_d/stk_limit`,为历史 `stock_st` 找到授权来源或保持硬阻断; 6. 冻结下载 job、请求 hash、Parquet hash、转换器 hash 和新 `data_version`; 7. 运行真实长样本 walk-forward/OOS,而不是复用本次早期 smoke; 8. 同一冻结输入进入 Quant OS 本地回测、聚宽和可用 QMT,生成 L1—L4 差异报告。 Qlib provider 的目录格式和缺失值/复权约定参见 [Qlib Data Layer 文档](https://qlib.readthedocs.io/en/latest/component/data.html)。