Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` 质量报告钩子)、#49(数据层 D4 coverage ledger 批量写 + 进程内查找缓存)均已 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 批量写 + 进程内查找缓存)、#51(数据层 D5 opt-in 有界并发 + 全局限频器)均已 merge 到 `main`**。commit 用 conventional 格式,**无 attribution**(不加 Co-Authored-By)。
- **不过度设计**:按路线图 MVP 先打通一条端到端链路,再加层(architecture.html §11,Phase 0→3)。
- **secrets** 一律走外部 `.config.json`;repo `.gitignore` 已排除数据产物(`*.parquet`等)、缓存、`tmp/`(仅留架构文档)。
- 文件小而专(<800 行),immutable 优先。
Expand Down Expand Up @@ -236,6 +236,11 @@ data → universe → factors(特征) → alpha(合成/预测) → portfolio(+ri
- **缓存接线**:`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 不变**)。
- ✅ **数据层 D5 — opt-in 有界并发 + 单一全局限频器**(**PR #51 已 merge 到 `main`**,Codex 验收;给 `data-update`/缓存暖跑取数阶段加可选并发,默认全串行):`data_update.concurrency.max_workers` 默认 **1**(串行,所有现存配置照常 validate、行为字节级不变;`<1` 可读报错)。**公开缓存方法/返回帧/ledger 路径列/coverage 语义/重试语义全不变,phase0 `0.9600/0.8408` 不变**。
- **全局限频器**(`data/feed/scheduler.py::GlobalRateLimiter`):线程安全 ticket 限频器,锁内预定下一时隙、锁外 sleep,N 个 worker 汇入**一个**每分钟预算(配额绝不按线程倍增);`monotonic`/`sleep` 可注入(fake-clock 测试),只见整数预算,无 token/kwargs/异常 payload。`request_with_retry(..., scheduler=)` 每次 attempt(含重试)前 acquire 全局时隙,且不再做 per-call rate sleep;未给则历史 per-call 节流不变。
- **缓存并发**(`TushareCache(max_workers=)`):`==1` 串行字节级不变;`>1` 且多 symbol → **只有日频密集 per-symbol 取数**走有界 `ThreadPoolExecutor`,**store upsert + ledger 写仍在主线程按计划序**(成功 gap 先 durable 再抛首个失败,失败 gap 不记覆盖、可重试;store/ledger 内容与取数完成序无关)。snapshot / `index_weight` 90 天分页 / intraday 在 D5 仍串行(并发开启时仍共享同一限频器)。
- **updater 接线**:`run_data_update` 仅 `max_workers>1` 才建**一个** `GlobalRateLimiter`(用 `rate_limit_per_min`),经 `_build_feeds` 共享给全部 feed(6 个 feed 加 `scheduler=None` 默认不变参);`UpdateResult`+`format_summary` 暴露 `max_workers`/全局 `rate_limit_per_min`(非密)。
- **测试**(`tests/test_scheduler.py` + `tests/test_data_update_concurrency.py`,network-free,21):全局时隙在争用下逐次升 sleep(fake clock)/ **8 线程实测全局非按线程**(`next_allowed==N*interval`)/ 重试逐次 acquire / scheduler 模式不做 per-call sleep / 失败 secret-safe(仅异常类型)/ feed 转发其 scheduler / config 校验(`<1` 拒;默认 1)/ **serial==concurrent** 帧·ledger·请求计数 / 失败留 gap 未覆盖可重试而成功 durable / empty·not_ready 不变 / 单 symbol 仍串行。真实 token 扫描 **0 hits**;**未跑 live `data-update`**(network-free 验收)。
- ✅ 质量门:`pytest` **677 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 / D5 scheduler=9 + concurrency=12**);`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);**数据层 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 滚动复检 / 成本模型细化。
- 路线图下一步:**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);**数据层 D6**(D1+D2+D3+D3b+D4+D5 已 merge:契约文档化 + token 解析收敛 + `TushareCache` specs/parsers 拆分 + report-only `data/quality/` 质量层 + default-off `data-update` 质量报告钩子 + coverage ledger `record_many` 批量写 + 进程内查找缓存 + opt-in 有界并发 + 全局限频器;剩余数据层 follow-up:**endpoint schema registry** 仍延后;**D6**=`PanelStore` append/partition / 可选物化派生面板存储,**仅当因子研究需要可复用派生面板时才启动**——均尚未实现);研究侧:更长 holdout 滚动复检 / 成本模型细化。
Loading