From 997a5b3a596b6a82d78d90de7eea68da72769571 Mon Sep 17 00:00:00 2001 From: shaofl <2899218482@qq.com> Date: Fri, 19 Jun 2026 20:59:46 +0800 Subject: [PATCH] docs: record data-layer D4 ledger-scaling progress (PR #49 merged) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - data_layer_contracts.md: D4 recorded as implemented (CoverageLedger / IntradayCoverageLedger record_many batch writes + in-process lookup cache; parquet paths, column order, and coverage semantics unchanged); section-4 title gains D4; the unimplemented list moves to D5+ (concurrency / global rate limiter = D5, endpoint schema registry, PanelStore append/partition). D5-D6 stay explicitly unimplemented. - CLAUDE.md / AGENTS.md (kept byte-identical): PR #49 added to the merged-PR list; D4 progress bullet; quality gate 643 -> 656 passed (+ D4 coverage-ledger-scaling=13); roadmap next data-layer step is D5 concurrency / endpoint schema registry (D4 done). Docs only — no qt/ data/ tests/ config/ change. --- AGENTS.md | 12 +++++++++--- CLAUDE.md | 12 +++++++++--- docs/data/data_layer_contracts.md | 20 ++++++++++++++------ 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e67c916..9957e42 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -57,7 +57,7 @@ data → universe → factors(特征) → alpha(合成/预测) → portfolio(+ri ## 开发约定 - **交流中文**;代码/注释/commit message 用**英文**。 -- **Git**:feature 分支 + PR。**PR #1(P0+P1)、#2(P2-1)、#3(P2-2)、#4(进度文档)、#5(P2-3)、#6(进度文档)、#7(P2-4)、#8(进度文档)、#9(P3-1)、#10(进度文档)、#11(P3-2)、#12(P3-3)、#13(进度文档)、#14(P3-4)、#15(进度文档)、#16(P3-5)、#17(进度文档)、#18(P3-6)、#19(P3-7)、#20(进度文档)、#21(P3-8)、#22(进度文档)、#23(P4-1)、#24(进度文档)、#25(P4-2)、#28(tushare 权限/限频探测 + capability registry)、#29(I1–I4 分钟级 intraday pipeline,4 commit 一 PR)、#30(进度文档)、#31(P4-3 因子支撑端点缓存 + 21:00 data updater,2 commit 一 PR)、#33(P-I5a 事件驱动回测架构重构 + opt-in 分钟尾盘 event model,4 commit 一 PR)、#35(P-I5b 分钟尾盘执行期 raw stk_limit 涨跌停可行性,4 commit 一 PR)、#37(P-I5c MMP 分钟因子端到端 opt-in alpha)、#39(P-I5d MMP 五分位分组回测 standalone,含 I5c plumbing)、#41(数据层 D1 契约文档 + token 解析去重)、#43(数据层 D2 TushareCache specs/parsers 拆分)、#45(数据层 D3 report-only 数据质量层)、#47(数据层 D3b default-off `data-update` 质量报告钩子)均已 merge 到 `main`**。commit 用 conventional 格式,**无 attribution**(不加 Co-Authored-By)。 +- **Git**:feature 分支 + PR。**PR #1(P0+P1)、#2(P2-1)、#3(P2-2)、#4(进度文档)、#5(P2-3)、#6(进度文档)、#7(P2-4)、#8(进度文档)、#9(P3-1)、#10(进度文档)、#11(P3-2)、#12(P3-3)、#13(进度文档)、#14(P3-4)、#15(进度文档)、#16(P3-5)、#17(进度文档)、#18(P3-6)、#19(P3-7)、#20(进度文档)、#21(P3-8)、#22(进度文档)、#23(P4-1)、#24(进度文档)、#25(P4-2)、#28(tushare 权限/限频探测 + capability registry)、#29(I1–I4 分钟级 intraday pipeline,4 commit 一 PR)、#30(进度文档)、#31(P4-3 因子支撑端点缓存 + 21:00 data updater,2 commit 一 PR)、#33(P-I5a 事件驱动回测架构重构 + opt-in 分钟尾盘 event model,4 commit 一 PR)、#35(P-I5b 分钟尾盘执行期 raw stk_limit 涨跌停可行性,4 commit 一 PR)、#37(P-I5c MMP 分钟因子端到端 opt-in alpha)、#39(P-I5d MMP 五分位分组回测 standalone,含 I5c plumbing)、#41(数据层 D1 契约文档 + token 解析去重)、#43(数据层 D2 TushareCache specs/parsers 拆分)、#45(数据层 D3 report-only 数据质量层)、#47(数据层 D3b default-off `data-update` 质量报告钩子)、#49(数据层 D4 coverage ledger 批量写 + 进程内查找缓存)均已 merge 到 `main`**。commit 用 conventional 格式,**无 attribution**(不加 Co-Authored-By)。 - **不过度设计**:按路线图 MVP 先打通一条端到端链路,再加层(architecture.html §11,Phase 0→3)。 - **secrets** 一律走外部 `.config.json`;repo `.gitignore` 已排除数据产物(`*.parquet`等)、缓存、`tmp/`(仅留架构文档)。 - 文件小而专(<800 行),immutable 优先。 @@ -230,6 +230,12 @@ data → universe → factors(特征) → alpha(合成/预测) → portfolio(+ri - **接线**:`update_endpoints` 加可选 `capture` sink(默认 None → 暖路径字节级不变:feed 调用/参数/顺序/summary 全不变);`run_data_update` 仅 enabled 时跑钩子;`UpdateResult` +`quality_report_path`/`quality_findings_count`/`quality_hard_count`;CLI enabled 才打 `quality:` 行(disabled 输出不变)。 - **report-only 不变量**:不过滤/修复/改数据、不让 job 失败、不改 cache coverage / 每端点请求 summary、无新端点、无质量专用 live 调用、不写 `PanelStore`、不动 ledger schema;日频 close-to-close 不漂移;报告不含 secret 路径/token/无界 symbol dump(继承 D3 redaction)。 - **测试**(`tests/test_data_update_quality.py`,network-free fake feeds):默认禁用 / clean 报告 / bad 日频+分钟帧 → hard findings 且不抛异常不改 summary / 端点选择被尊重(未暖面绝不检查)/ `report_name` 路径校验 / 报告无 secret。真实 token 值扫描 **0 hits**;**未跑 live `data-update`**(network-free 验收)。 -- ✅ 质量门:`pytest` **643 passed**(P0=97 / P1=78 / P2-1=22 / P2-2=22 / P2-3=14 / P2-4=8 / P3-1=10 / P3-2=18 / P3-3=16 / P3-4=15 / P3-5=22 / P3-6=27 / P3-7=25+1 throttle / P3-8=8 / P4-1=28 / P4-2=17 / **intraday I1 schema=14 + feed=9 / I2 cache=10 / I3 aggregate=13 / I4 execution=10 / P4-3 cache=10 + updater=7 / P-I5a event-backtest=19 / P-I5b exec-feasibility=16 / P-I5c mmp-minute=18 / P-I5d mmp-quintile=19 / D1 token-dedup index-feed +2 / D2 cache-modularization +5 / D3 data-quality market=15 + intraday=12 + report=14 / D3b data-update-quality=18**);`ruff` clean;`validate-config`(全部 17 配置含 data_update + phase_i5a + phase_i5b + phase_i5c + phase_i5d)+ `run-phase0`(demo)均 OK(**ic 0.9600 / annual 0.8408 不变**)。 +- ✅ **数据层 D4 — coverage ledger 批量写 + 进程内查找缓存**(**PR #49 已 merge 到 `main`**,Codex 验收;行为保持的缓存内部扩展,降低重复全表读写开销):给日频 `CoverageLedger` 与分钟 `IntradayCoverageLedger` 加批量 API + 查找缓存。**公开方法/路径/列/coverage 语义全不变**。 + - **`record_many(rows)`**(两个 ledger):一次归一化 + 一次原子 parquet 写;空输入 no-op;每行与单行 `record` 逐字归一;写后 reindex 到公开列契约;无 secret 字段。**`record()` 委托给 `record_many([row])`**,单行路径与批量路径一致。 + - **进程内查找缓存**:每实例帧缓存 + 按 `(endpoint, key[, raw_freq])` 的 memo,使重复 `covered_intervals`/`snapshot_fetched_at`/`covered_day_intervals` 不再重读重过滤整张 parquet;按文件 `st_mtime_ns` 失效(**外部写绝不被当陈旧服务**),写入后原地刷新;三个 lookup **先 `_load()` 再查 memo**(外部变更总清陈旧 memo);`read()` 返回 copy 防外部污染内部缓存。 + - **缓存接线**:`TushareCache._record_gap_coverage` 的 not-ready 拆分用**一次** `record_many` 写其 1–2 行(经 `_record_rows`),`not_ready` 计数/状态不变;其余 call site 仍 `record()`(单行批量)——成功 gap 照常记录,后续失败 fetch 绝不反记成功。分钟缓存(每 gap 一行)未改;无明显安全批量。 + - **不变量守住**:公开构造/方法(`read`/`covered_intervals`/`snapshot_fetched_at`/`record`/intraday `covered_day_intervals`)、parquet 路径(`manifest/coverage.parquet`/`coverage_intraday.parquet`)、`LEDGER_COLUMNS`/`INTRADAY_LEDGER_COLUMNS` 名序、coverage 语义(仅 ok/empty 算覆盖;failed/not_ready 不算;snapshot 取最新成功 fetched_at;not_ready_days 不变)全不变;无 config 旋钮 / 无 cache-root 布局变更;phase0 `0.9600/0.8408` 不变。 + - **测试**(`tests/test_coverage_ledger_scaling.py`,network-free,13):`record_many` ≡ 重复 `record`(名序/值)/ `record_many([])` no-op / `covered_intervals` 仅 ok·empty / `snapshot_fetched_at` 取最新成功 / 分钟镜像 / **重复 lookup 不重读 parquet**(spy load 路径,非计时)/ **外部写失效缓存** / `read()` 返 copy / not-ready 拆分一次批量 / 平凡 gap 单行 / ledger 列无 secret 字段。 +- ✅ 质量门:`pytest` **656 passed**(P0=97 / P1=78 / P2-1=22 / P2-2=22 / P2-3=14 / P2-4=8 / P3-1=10 / P3-2=18 / P3-3=16 / P3-4=15 / P3-5=22 / P3-6=27 / P3-7=25+1 throttle / P3-8=8 / P4-1=28 / P4-2=17 / **intraday I1 schema=14 + feed=9 / I2 cache=10 / I3 aggregate=13 / I4 execution=10 / P4-3 cache=10 + updater=7 / P-I5a event-backtest=19 / P-I5b exec-feasibility=16 / P-I5c mmp-minute=18 / P-I5d mmp-quintile=19 / D1 token-dedup index-feed +2 / D2 cache-modularization +5 / D3 data-quality market=15 + intraday=12 + report=14 / D3b data-update-quality=18 / D4 coverage-ledger-scaling=13**);`ruff` clean;`validate-config`(全部 17 配置含 data_update + phase_i5a + phase_i5b + phase_i5c + phase_i5d)+ `run-phase0`(demo)均 OK(**ic 0.9600 / annual 0.8408 不变**)。 - ⚠️ 剩余(已显式披露):日线 only、demo 路径非真数据、旧三因子无信号(P3-3/P3-4 实证;但其组合在 2024-2026 holdout 上 SSE50/CSI300/CSI500 全正、CSI500 高达 +17.8%——小样本/regime 翻转的持续例证);value/低波信号获得**独立样本符号级确认**(P3-7 SSE50/CSI300 量级衰减;P3-8 CSI500 泛化成立且更强),组合级盈利能力仍未确立(排名跨 cell 翻转);subset 报告文件名已可配置(P3-8 起不再互覆盖)。 -- 路线图下一步:**I5d 独立泛化**(MMP 五分位单调性是项目首个正向 intraday 信号,但只一个重叠 5 年窗口/一个 universe → 在第二个 universe(CSI300/中证1000)和/或 disjoint 窗口上机器冻结复跑分组回测,使单调性可归因于因子而非该 regime,沿 P3-7/P3-8 独立确认先例);**I5b/执行 follow-up**(执行期 feasibility 可再扩 partial-fill / liquidity / volume cap,size-aware 读数前补);**P4-3 follow-up**(fina 按 ann_date 建披露日历 ledger 以去掉启发式 tail / updater 加 stk_mins 历史回填 / data-update summary 落 cache-stats artifact);**数据层 D4**(D1+D2+D3+D3b 已 merge:契约文档化 + token 解析收敛 + `TushareCache` specs/parsers 拆分 + report-only `data/quality/` 质量层 + default-off `data-update` 质量报告钩子;下一步 **D4**=`CoverageLedger` 存储扩展 / batch 写入;之后 **D5** 并发 / endpoint schema registry——均尚未实现);研究侧:更长 holdout 滚动复检 / 成本模型细化。 +- 路线图下一步:**I5d 独立泛化**(MMP 五分位单调性是项目首个正向 intraday 信号,但只一个重叠 5 年窗口/一个 universe → 在第二个 universe(CSI300/中证1000)和/或 disjoint 窗口上机器冻结复跑分组回测,使单调性可归因于因子而非该 regime,沿 P3-7/P3-8 独立确认先例);**I5b/执行 follow-up**(执行期 feasibility 可再扩 partial-fill / liquidity / volume cap,size-aware 读数前补);**P4-3 follow-up**(fina 按 ann_date 建披露日历 ledger 以去掉启发式 tail / updater 加 stk_mins 历史回填 / data-update summary 落 cache-stats artifact);**数据层 D5**(D1+D2+D3+D3b+D4 已 merge:契约文档化 + token 解析收敛 + `TushareCache` specs/parsers 拆分 + report-only `data/quality/` 质量层 + default-off `data-update` 质量报告钩子 + coverage ledger `record_many` 批量写 + 进程内查找缓存;下一步 **D5**=并发 / 线程池 / 全局限频器,以及 endpoint schema registry——均尚未实现);研究侧:更长 holdout 滚动复检 / 成本模型细化。 diff --git a/CLAUDE.md b/CLAUDE.md index e67c916..9957e42 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -57,7 +57,7 @@ data → universe → factors(特征) → alpha(合成/预测) → portfolio(+ri ## 开发约定 - **交流中文**;代码/注释/commit message 用**英文**。 -- **Git**:feature 分支 + PR。**PR #1(P0+P1)、#2(P2-1)、#3(P2-2)、#4(进度文档)、#5(P2-3)、#6(进度文档)、#7(P2-4)、#8(进度文档)、#9(P3-1)、#10(进度文档)、#11(P3-2)、#12(P3-3)、#13(进度文档)、#14(P3-4)、#15(进度文档)、#16(P3-5)、#17(进度文档)、#18(P3-6)、#19(P3-7)、#20(进度文档)、#21(P3-8)、#22(进度文档)、#23(P4-1)、#24(进度文档)、#25(P4-2)、#28(tushare 权限/限频探测 + capability registry)、#29(I1–I4 分钟级 intraday pipeline,4 commit 一 PR)、#30(进度文档)、#31(P4-3 因子支撑端点缓存 + 21:00 data updater,2 commit 一 PR)、#33(P-I5a 事件驱动回测架构重构 + opt-in 分钟尾盘 event model,4 commit 一 PR)、#35(P-I5b 分钟尾盘执行期 raw stk_limit 涨跌停可行性,4 commit 一 PR)、#37(P-I5c MMP 分钟因子端到端 opt-in alpha)、#39(P-I5d MMP 五分位分组回测 standalone,含 I5c plumbing)、#41(数据层 D1 契约文档 + token 解析去重)、#43(数据层 D2 TushareCache specs/parsers 拆分)、#45(数据层 D3 report-only 数据质量层)、#47(数据层 D3b default-off `data-update` 质量报告钩子)均已 merge 到 `main`**。commit 用 conventional 格式,**无 attribution**(不加 Co-Authored-By)。 +- **Git**:feature 分支 + PR。**PR #1(P0+P1)、#2(P2-1)、#3(P2-2)、#4(进度文档)、#5(P2-3)、#6(进度文档)、#7(P2-4)、#8(进度文档)、#9(P3-1)、#10(进度文档)、#11(P3-2)、#12(P3-3)、#13(进度文档)、#14(P3-4)、#15(进度文档)、#16(P3-5)、#17(进度文档)、#18(P3-6)、#19(P3-7)、#20(进度文档)、#21(P3-8)、#22(进度文档)、#23(P4-1)、#24(进度文档)、#25(P4-2)、#28(tushare 权限/限频探测 + capability registry)、#29(I1–I4 分钟级 intraday pipeline,4 commit 一 PR)、#30(进度文档)、#31(P4-3 因子支撑端点缓存 + 21:00 data updater,2 commit 一 PR)、#33(P-I5a 事件驱动回测架构重构 + opt-in 分钟尾盘 event model,4 commit 一 PR)、#35(P-I5b 分钟尾盘执行期 raw stk_limit 涨跌停可行性,4 commit 一 PR)、#37(P-I5c MMP 分钟因子端到端 opt-in alpha)、#39(P-I5d MMP 五分位分组回测 standalone,含 I5c plumbing)、#41(数据层 D1 契约文档 + token 解析去重)、#43(数据层 D2 TushareCache specs/parsers 拆分)、#45(数据层 D3 report-only 数据质量层)、#47(数据层 D3b default-off `data-update` 质量报告钩子)、#49(数据层 D4 coverage ledger 批量写 + 进程内查找缓存)均已 merge 到 `main`**。commit 用 conventional 格式,**无 attribution**(不加 Co-Authored-By)。 - **不过度设计**:按路线图 MVP 先打通一条端到端链路,再加层(architecture.html §11,Phase 0→3)。 - **secrets** 一律走外部 `.config.json`;repo `.gitignore` 已排除数据产物(`*.parquet`等)、缓存、`tmp/`(仅留架构文档)。 - 文件小而专(<800 行),immutable 优先。 @@ -230,6 +230,12 @@ data → universe → factors(特征) → alpha(合成/预测) → portfolio(+ri - **接线**:`update_endpoints` 加可选 `capture` sink(默认 None → 暖路径字节级不变:feed 调用/参数/顺序/summary 全不变);`run_data_update` 仅 enabled 时跑钩子;`UpdateResult` +`quality_report_path`/`quality_findings_count`/`quality_hard_count`;CLI enabled 才打 `quality:` 行(disabled 输出不变)。 - **report-only 不变量**:不过滤/修复/改数据、不让 job 失败、不改 cache coverage / 每端点请求 summary、无新端点、无质量专用 live 调用、不写 `PanelStore`、不动 ledger schema;日频 close-to-close 不漂移;报告不含 secret 路径/token/无界 symbol dump(继承 D3 redaction)。 - **测试**(`tests/test_data_update_quality.py`,network-free fake feeds):默认禁用 / clean 报告 / bad 日频+分钟帧 → hard findings 且不抛异常不改 summary / 端点选择被尊重(未暖面绝不检查)/ `report_name` 路径校验 / 报告无 secret。真实 token 值扫描 **0 hits**;**未跑 live `data-update`**(network-free 验收)。 -- ✅ 质量门:`pytest` **643 passed**(P0=97 / P1=78 / P2-1=22 / P2-2=22 / P2-3=14 / P2-4=8 / P3-1=10 / P3-2=18 / P3-3=16 / P3-4=15 / P3-5=22 / P3-6=27 / P3-7=25+1 throttle / P3-8=8 / P4-1=28 / P4-2=17 / **intraday I1 schema=14 + feed=9 / I2 cache=10 / I3 aggregate=13 / I4 execution=10 / P4-3 cache=10 + updater=7 / P-I5a event-backtest=19 / P-I5b exec-feasibility=16 / P-I5c mmp-minute=18 / P-I5d mmp-quintile=19 / D1 token-dedup index-feed +2 / D2 cache-modularization +5 / D3 data-quality market=15 + intraday=12 + report=14 / D3b data-update-quality=18**);`ruff` clean;`validate-config`(全部 17 配置含 data_update + phase_i5a + phase_i5b + phase_i5c + phase_i5d)+ `run-phase0`(demo)均 OK(**ic 0.9600 / annual 0.8408 不变**)。 +- ✅ **数据层 D4 — coverage ledger 批量写 + 进程内查找缓存**(**PR #49 已 merge 到 `main`**,Codex 验收;行为保持的缓存内部扩展,降低重复全表读写开销):给日频 `CoverageLedger` 与分钟 `IntradayCoverageLedger` 加批量 API + 查找缓存。**公开方法/路径/列/coverage 语义全不变**。 + - **`record_many(rows)`**(两个 ledger):一次归一化 + 一次原子 parquet 写;空输入 no-op;每行与单行 `record` 逐字归一;写后 reindex 到公开列契约;无 secret 字段。**`record()` 委托给 `record_many([row])`**,单行路径与批量路径一致。 + - **进程内查找缓存**:每实例帧缓存 + 按 `(endpoint, key[, raw_freq])` 的 memo,使重复 `covered_intervals`/`snapshot_fetched_at`/`covered_day_intervals` 不再重读重过滤整张 parquet;按文件 `st_mtime_ns` 失效(**外部写绝不被当陈旧服务**),写入后原地刷新;三个 lookup **先 `_load()` 再查 memo**(外部变更总清陈旧 memo);`read()` 返回 copy 防外部污染内部缓存。 + - **缓存接线**:`TushareCache._record_gap_coverage` 的 not-ready 拆分用**一次** `record_many` 写其 1–2 行(经 `_record_rows`),`not_ready` 计数/状态不变;其余 call site 仍 `record()`(单行批量)——成功 gap 照常记录,后续失败 fetch 绝不反记成功。分钟缓存(每 gap 一行)未改;无明显安全批量。 + - **不变量守住**:公开构造/方法(`read`/`covered_intervals`/`snapshot_fetched_at`/`record`/intraday `covered_day_intervals`)、parquet 路径(`manifest/coverage.parquet`/`coverage_intraday.parquet`)、`LEDGER_COLUMNS`/`INTRADAY_LEDGER_COLUMNS` 名序、coverage 语义(仅 ok/empty 算覆盖;failed/not_ready 不算;snapshot 取最新成功 fetched_at;not_ready_days 不变)全不变;无 config 旋钮 / 无 cache-root 布局变更;phase0 `0.9600/0.8408` 不变。 + - **测试**(`tests/test_coverage_ledger_scaling.py`,network-free,13):`record_many` ≡ 重复 `record`(名序/值)/ `record_many([])` no-op / `covered_intervals` 仅 ok·empty / `snapshot_fetched_at` 取最新成功 / 分钟镜像 / **重复 lookup 不重读 parquet**(spy load 路径,非计时)/ **外部写失效缓存** / `read()` 返 copy / not-ready 拆分一次批量 / 平凡 gap 单行 / ledger 列无 secret 字段。 +- ✅ 质量门:`pytest` **656 passed**(P0=97 / P1=78 / P2-1=22 / P2-2=22 / P2-3=14 / P2-4=8 / P3-1=10 / P3-2=18 / P3-3=16 / P3-4=15 / P3-5=22 / P3-6=27 / P3-7=25+1 throttle / P3-8=8 / P4-1=28 / P4-2=17 / **intraday I1 schema=14 + feed=9 / I2 cache=10 / I3 aggregate=13 / I4 execution=10 / P4-3 cache=10 + updater=7 / P-I5a event-backtest=19 / P-I5b exec-feasibility=16 / P-I5c mmp-minute=18 / P-I5d mmp-quintile=19 / D1 token-dedup index-feed +2 / D2 cache-modularization +5 / D3 data-quality market=15 + intraday=12 + report=14 / D3b data-update-quality=18 / D4 coverage-ledger-scaling=13**);`ruff` clean;`validate-config`(全部 17 配置含 data_update + phase_i5a + phase_i5b + phase_i5c + phase_i5d)+ `run-phase0`(demo)均 OK(**ic 0.9600 / annual 0.8408 不变**)。 - ⚠️ 剩余(已显式披露):日线 only、demo 路径非真数据、旧三因子无信号(P3-3/P3-4 实证;但其组合在 2024-2026 holdout 上 SSE50/CSI300/CSI500 全正、CSI500 高达 +17.8%——小样本/regime 翻转的持续例证);value/低波信号获得**独立样本符号级确认**(P3-7 SSE50/CSI300 量级衰减;P3-8 CSI500 泛化成立且更强),组合级盈利能力仍未确立(排名跨 cell 翻转);subset 报告文件名已可配置(P3-8 起不再互覆盖)。 -- 路线图下一步:**I5d 独立泛化**(MMP 五分位单调性是项目首个正向 intraday 信号,但只一个重叠 5 年窗口/一个 universe → 在第二个 universe(CSI300/中证1000)和/或 disjoint 窗口上机器冻结复跑分组回测,使单调性可归因于因子而非该 regime,沿 P3-7/P3-8 独立确认先例);**I5b/执行 follow-up**(执行期 feasibility 可再扩 partial-fill / liquidity / volume cap,size-aware 读数前补);**P4-3 follow-up**(fina 按 ann_date 建披露日历 ledger 以去掉启发式 tail / updater 加 stk_mins 历史回填 / data-update summary 落 cache-stats artifact);**数据层 D4**(D1+D2+D3+D3b 已 merge:契约文档化 + token 解析收敛 + `TushareCache` specs/parsers 拆分 + report-only `data/quality/` 质量层 + default-off `data-update` 质量报告钩子;下一步 **D4**=`CoverageLedger` 存储扩展 / batch 写入;之后 **D5** 并发 / endpoint schema registry——均尚未实现);研究侧:更长 holdout 滚动复检 / 成本模型细化。 +- 路线图下一步:**I5d 独立泛化**(MMP 五分位单调性是项目首个正向 intraday 信号,但只一个重叠 5 年窗口/一个 universe → 在第二个 universe(CSI300/中证1000)和/或 disjoint 窗口上机器冻结复跑分组回测,使单调性可归因于因子而非该 regime,沿 P3-7/P3-8 独立确认先例);**I5b/执行 follow-up**(执行期 feasibility 可再扩 partial-fill / liquidity / volume cap,size-aware 读数前补);**P4-3 follow-up**(fina 按 ann_date 建披露日历 ledger 以去掉启发式 tail / updater 加 stk_mins 历史回填 / data-update summary 落 cache-stats artifact);**数据层 D5**(D1+D2+D3+D3b+D4 已 merge:契约文档化 + token 解析收敛 + `TushareCache` specs/parsers 拆分 + report-only `data/quality/` 质量层 + default-off `data-update` 质量报告钩子 + coverage ledger `record_many` 批量写 + 进程内查找缓存;下一步 **D5**=并发 / 线程池 / 全局限频器,以及 endpoint schema registry——均尚未实现);研究侧:更长 holdout 滚动复检 / 成本模型细化。 diff --git a/docs/data/data_layer_contracts.md b/docs/data/data_layer_contracts.md index b0f1be2..3f25f74 100644 --- a/docs/data/data_layer_contracts.md +++ b/docs/data/data_layer_contracts.md @@ -3,7 +3,7 @@ > 目的:把 **`cache`(缓存)** 与 **`store`(面板存储)** 的边界写成可提交的契约, > 让后续改动有明确不变量可守。本文件只描述 **当前已实现** 的行为,不预告未实现的阶段。 -已实现:**D1**(边界文档化 + 低风险 token 解析去重)、**D2**(`TushareCache` endpoint specs/parsers 拆分,公开缓存行为不变)、**D3**(report-only `data/quality/` 数据质量层)、**D3b**(默认关闭的 `data-update` 质量报告钩子,report-only)。**D4–D6 尚未实现**,本文件不声称其存在。 +已实现:**D1**(边界文档化 + 低风险 token 解析去重)、**D2**(`TushareCache` endpoint specs/parsers 拆分,公开缓存行为不变)、**D3**(report-only `data/quality/` 数据质量层)、**D3b**(默认关闭的 `data-update` 质量报告钩子,report-only)、**D4**(coverage ledger `record_many` 批量写 + 进程内查找缓存,公开路径/列/语义不变)。**D5–D6 尚未实现**,本文件不声称其存在。 --- @@ -42,7 +42,7 @@ - 它 **不跑 factor / alpha / portfolio / backtest,不写 `PanelStore`**。 - 真实回测仍各自走 read-through,按需补自己的缺口;`data-update` 只是把常用 endpoint 提前填好。 -## 4. D1 / D2 / D3 / D3b 已做什么;D4+ 范围(未实现) +## 4. D1 / D2 / D3 / D3b / D4 已做什么;D5+ 范围(未实现) **D1**(行为零改动)做两件低风险事:**把上述边界写成本契约文档**,以及 **把 `TushareFeed` / `IndexConstituentsFeed` 里重复的 token 解析收敛到共享的 `data/feed/secret.py::read_token`** @@ -68,8 +68,16 @@ dump。**report-only**:不过滤/修复/改数据,不让 job 失败,不改 cache feed/factor/alpha/portfolio/runtime/backtest 语义(日频 close-to-close 不漂移)。不合成交易日历(仅结构检查; 缺日期/缺分钟的 D3 检查在 D3b 关闭)。 -以下明确 **仍未实现**(D4+,本文件 **不声称已实现**): +**D4**(行为保持的缓存内部扩展)给日频 `CoverageLedger` 与分钟 `IntradayCoverageLedger` 加 `record_many(...)` +批量追加(一次归一化 + 一次原子 parquet 写;空输入 no-op;每行与单行 `record` 逐字归一),`record(...)` 委托给 +`record_many([row])`;并加进程内帧缓存 + 按 `(endpoint, key[, raw_freq])` 的查找 memo,让重复 lookup 不再重读重 +过滤整张 parquet(按文件 mtime 失效,外部写绝不被当陈旧服务;`read()` 返回 copy 防污染)。`TushareCache` 的 +not-ready 拆分用**一次** `record_many` 写其 1–2 行覆盖。**公开方法/构造、parquet 路径(`manifest/coverage.parquet` +/ `coverage_intraday.parquet`)、`LEDGER_COLUMNS`/`INTRADAY_LEDGER_COLUMNS` 名序、coverage 语义(仅 ok/empty 算 +覆盖;failed/not_ready 不算;snapshot 取最新成功 fetched_at)全不变**。 -- 并发 / 线程池 / 异步抓取(concurrency); -- endpoint schema registry(改运行时 dispatch 语义)、`CoverageLedger` 存储格式变更 / batch 写入、 - `PanelStore` 的 append/partition 特性。 +以下明确 **仍未实现**(D5+,本文件 **不声称已实现**): + +- 并发 / 线程池 / 异步抓取 / 全局限频器(concurrency,**D5**); +- endpoint schema registry(改运行时 dispatch 语义); +- `PanelStore` 的 append/partition 特性。