diff --git a/CLAUDE.md b/CLAUDE.md index ca34c6e..a71acd2 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)均已 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)均已 merge 到 `main`**。commit 用 conventional 格式,**无 attribution**(不加 Co-Authored-By)。 - **不过度设计**:按路线图 MVP 先打通一条端到端链路,再加层(architecture.html §11,Phase 0→3)。 - **secrets** 一律走外部 `.config.json`;repo `.gitignore` 已排除数据产物(`*.parquet`等)、缓存、`tmp/`(仅留架构文档)。 - 文件小而专(<800 行),immutable 优先。 @@ -205,6 +205,14 @@ data → universe → factors(特征) → alpha(合成/预测) → portfolio(+ri - **接线**:`IntradayCfg.{price_limit_check(默认 false)/require_price_limit_coverage/limit_tolerance(≥0 校验)}` + `OutputCfg.intraday_report_name`(I5b 报告独立成文件,不覆盖已验收 I5a artifact,沿 baseline_report_name 先例);runner 经 `TushareFlagsFeed(cache=cache).limits()` 走既有 P4 read-through 缓存取 raw 限价(**不加新端点**),报告 H1/intro 按 check 自报 I5b(修同类 stale-title)。 - **不变量守住**:`BacktestEngine`/`BacktestDriver`/`DailyCloseEventModel`/`fills`/`execution` **零改动**(限价 map 仅 check 开时构建,默认 false → `feasibility()` 逐字退回 I5a bar-exists 规则);日频 close-to-close 不漂移。 - **真实 smoke(SSE50 2026-03-03→06-12,3 次跑 NAV 全 `0.976448` 确定性)**:`covered=58/58 / stk_mins_live_calls=0`;限价覆盖 **174/174**;**1 笔涨停挡买 / 0 笔跌停挡卖** → NAV 由 I5a 的 0.952207 变到 **0.976448**(2026-04-30 一只 14:51 封涨停的票被正确挡买,该期只持 9 只——I5a 只查 bar 存在会「买」进涨停板,**这正是 I5b 补的执行真实性,非业绩声明**);`stk_limit` gap-fetches=58(冷暖都 58:窗口尾端距今 3 天落在 `refresh_recent_days=14` 内,P4 按策略重抓 tail,据实报告,非 minute fetch);secret scan 报告+日志+58 缓存 parquet **0 处**。 -- ✅ 质量门:`pytest` **538 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**);`ruff` clean;`validate-config`(全部 15 配置含 data_update + phase_i5a + phase_i5b)+ `run-phase0`(demo)均 OK(**ic 0.9600 / annual 0.8408 不变**)。 +- ✅ **P-I5c MMP 分钟因子端到端 opt-in alpha**(**PR #37 已 merge 到 `main`**,**EXPLORATORY**,非业绩声明):把首个 EXPLORATORY 分钟因子作为真实 opt-in alpha 端到端接 I2→I3→I4→event engine,日频回归不破。 + - **MMP(Minute Microstructure Pressure)**(`data/clean/intraday_aggregate.py`,公式/PIT/前导 NaN/跨 symbol 隔离全测试锁定):逐 1min bar `mid=(high+low)/2`、`S=(close−mid)/mid`、`V=√(volume/median(vol[t-20:t]))`、`B=|close−open|/(high−low+eps)`、`R=(high−low)/(mean(hl[t-20:t])+eps)`、`MMP_t=S·V·B·R`(eps=1e-6);日频分数 = 在场 bar `[session_open, decision_time]` 等权均值,rolling baseline 用前 20 个在场 bar(首 20 NaN)。**先 `available_time≤cutoff` 过滤再聚合**(PIT-safe,绝不先归零)。 + - **可配置 `intraday.score_feature`**(默认沿用,`mmp_ew` opt-in)+ 可配置报告标题(修同类 stale-title);`config/phase_i5c_mmp_minute_factor.yaml`。decision feature→alpha→portfolio→event engine 全程复用既有机器,报告披露 cutoff/lag/execution_model/window。**日频 close-to-close 零漂移**(phase0 `0.9600/0.8408` 不变)。 +- ✅ **P-I5d MMP 五分位分组回测**(**PR #39 已 merge 到 `main`**,**standalone against `main`**,**EXPLORATORY,非业绩声明、非调参**):把 I5c MMP 日频分数 `intraday_mmp20_ew_0930_1450` 做 5 等额分位分组回测——每月调仓日按 PIT-safe 分数横截面排名切 `analytics.quantiles=5` 等数桶(Q1 最低 / Q5 最高),每组作独立 long-only 等权组合走**同一** `BacktestEngine`+`IntradayTailEventModel`+`SimExecution(fee_rate=0.001)`,I5b raw `stk_limit` 执行期涨跌停 ON。引擎/执行可行性/MMP 因子数学全不变,仅新增分组 + per-group 编排。本地验收:`tmp/context/session_handoff_20260615/stage_i5d_acceptance.md`。 + - **新增**(机器零改动复用 I5a/I5b/I5c):`qt/intraday_groups.py`(等额 rank 桶 / `GroupScores` / `EqualWeightAll`)、`qt/intraday_group_backtest.py`(cache-only anchor-date-sliced 分钟加载、一份共享 exec-price 矩阵跨 N 个 fresh per-group 模型、QN−Q1 合成 spread)、`qt/intraday_group_figures.py`/`intraday_group_report.py`(NAV/spread/metric 图 + 报告)、`config/phase_i5d_mmp_quintile_5y.yaml`;唯一 runtime 改动 `IntradayTailEventModel` 可选 `precomputed_prices`(默认 None → I5a/I5b 逐字节不变)。 + - **真实 run(CSI500 `000905.SH`,2021-06-01→2026-05-31,59 月调仓,~95min)**:`covered=892/995`(**103 只分钟未覆盖成分被 drop 并披露,5 年窗口不缩短**)/ `stk_mins_live_calls=0`(cache-only)/ `fee_rate=0.001`;final NAV Q1→Q5 **0.9822 / 1.0423 / 1.0495 / 1.1275 / 1.1577**(**单调 Spearman 1.0000**,等额 rank 桶对 MMP 肥尾稳健);合成 Q5−Q1 spread +0.29%/期、累计 **+17.15%**;限价覆盖 52,584/52,584(严格 `require_price_limit_coverage=true` 过)。 + - ⚠️ **caveat(保留,不移除)**:单因子/单重叠 5 年窗口/单 universe,无调参/无 robustness/无 learned 权重;`covered=892/995`(103 drop);`stk_mins_live_calls=0`;**Q5−Q1 是合成 long-only 腿差,非单独执行的 dollar-neutral 组合**;执行模型仍缺 partial-fill / liquidity / volume-cap;**Q5>Q1 不作业绩声明**。这是项目首个正向 intraday 信号,下一步需独立泛化(CSI300/中证1000 或 disjoint 窗口,机器冻结)。 + - **PR 处置**:#37(I5c)随 #39 落地后其 head 成 `main` 祖先,GitHub **自动 merged**(非本次手动 merge);#38(i5d stacked on i5c,base 非 main)已被 #39 **完全取代**(零 remaining commit/file diff vs main),保持 **OPEN 待清理**(未获显式授权关闭)。 +- ✅ 质量门:`pytest` **577 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**);`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 起不再互覆盖)。 -- 路线图下一步:**分钟级轨道 I5c**(执行真实性已就位:I5a 事件框架 + I5b raw `stk_limit` 执行期涨跌停 → 把 1~2 个 EXPLORATORY 分钟因子作为真实 opt-in alpha 端到端接 decision feature→alpha→portfolio→event engine,报告披露 cutoff/lag/execution_model/window,日频回归不破;首个分钟因子研究不会被后续可行性修复推翻);**I5b follow-up**(执行期 feasibility 可再扩 partial-fill / liquidity / volume cap);**P4-3 follow-up**(fina 按 ann_date 建披露日历 ledger 以去掉启发式 tail / updater 加 stk_mins 历史回填 / data-update summary 落 cache-stats artifact);研究侧:更长 holdout 滚动复检 / 中证1000 / 成本模型细化。 +- 路线图下一步:**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);**数据层 D1+**(cache/store 契约已文档化,token 解析已收敛,后续 D2+ 再做 cache 内部拆分/schema registry/data-quality/并发);研究侧:更长 holdout 滚动复检 / 成本模型细化。