修复:量价单位 / 未来函数守卫 / 实时画像闸门;行情回补到 2005;手册补全流程

本轮会话的三项正确性改造(均为「不报错、只让结果静默错」的类型):

1) 修复 stock_daily 量价单位前后不一致
   - 现象:2015-2019 存 Tushare 原始单位(手/千元),2020 起存(股/元),2019 同日混合;
     而流动性阈值按「元」配置 → 早年门槛实际是「日均成交额 ≥ 200 亿元」,
     把 2015-2019 的股票池整体清空(实测 2016/2017/2018 各选出 0 只)。
   - 修复:写入端 sync/price.py 统一换算;读取端 units.normalize_ohlcv_units
     按行判定并幂等换算(price_history / avg_amount 都走它);
     审计新增 UNIT-OHLCV 防回归。
   - 效果:2016/2017/2018 的股票池变为 7/11/13 只。

2) 未来函数守卫(单次回测)
   - 股票池自带 asof:若晚于回测起点即**拒绝执行**(原先静默冻结套用),
     与 walk-forward 已有的拒绝理由一致;确需复现加 --allow-lookahead-universe,
     偏差写入 unimplemented_json。

3) 新增实时(PIT)个股画像闸门
   - profile/pit.py:每个决策日按当时可见数据重算过去 5 年画像,
     惰性(仅买入条件已触发的标的)、面板按 asof 缓存、
     规则不含财务指标时不查财报表;被剔除时产出 REJECT + 逐规则留痕。
   - 指标定义复用 ProfileBuilder._profile_one(与批量画像逐值等价的回归测试)。
   - profile/coverage.py:窗口覆盖率(按交易日历的真实开市天数),
     策略新增 entry.profile_gate.min_window_coverage(默认 0,不改变既有行为)。
   - core/metrics.py:闸门可用指标的唯一定义(配置期即校验,避免写错指标名静默失效)。

4) 行情回补到 2005(使 5/8/10 年窗口真正完整)
   - stock_daily / adjust_factor / daily_basic 补到 2005-01-04;
     hd_suspend / hd_limit 补到 2010-01-04。
   - 5 年窗口覆盖率:2018-05-18 由 67.0% → 99.1%,2016-12-30 由 39.8% → 99.0%;
     残差经逐日与 hd_suspend 交叉核实为真实停牌(16/16 命中)。
   - 审计 G2/G3 与断点续传原先用固定阈值(2000 / 1500 只),
     会把 2005-2009 的正常数据误判为异常 —— 改为按「当年应有上市股票数」成比例判定。
   - 节流修正:daily/adj_factor/daily_basic 限频 480 → 170(实测该 token 约 196/min 即被拒)。

5) 自我声明如实化
   - 原先「约束未生效」由「过滤后集合为空」判定,会把「这批股票恰好没停牌」
     误报成「hd_suspend 无数据」;改为按表级判定。
   - 补齐此前静默的「配置承诺但未实现」项:suspended_rule/limit_up_down_rule 的 defer、
     cash_mode=reinvest/reinvest_rule、handle_rights_issue、signal_to_execution、
     max_volume_pct、liquidity_limit_pct_adv —— 全部写入 unimplemented_json。

6) 手册:新增 §0「全流程操作(选股 → 画像 → 回测)」置于最前
   - 逐步说明「命令做了什么、数据从哪来、落了哪些库、有哪些坑」;
     含实时画像闸门 9 问 9 答、未来函数守卫表、成交与成本口径、验证 SQL。
   - 修正旧 §2.4 漏传 --universe-run(选了池子却没用于回测);
     修正两处声称「停牌顺延」「分红再投资」已实现的相反表述。

测试:403 项全部通过(含新增 test_units.py、test_profile_pit.py、
未实现声明诚实性测试、行序无关性回归测试)。

注意:本提交中 docs/*、README.md、src/hdiv/web/service.py 除本轮修改外,
也含此前遗留的未提交改动(无法按文件切分)。
This commit is contained in:
2026-10-04 12:47:17 +08:00
parent fb6608193b
commit 14ec0c6c86
25 changed files with 4543 additions and 209 deletions
+29 -3
View File
@@ -74,12 +74,38 @@ docs/ 文档
**本系统的实测结论是:策略没有稳定的样本外超额收益。**
全期回测(2015–2026)显示 +114.80% / CAGR 6.73%,
但 7 窗口 Walk-forward 的样本外收益均值仅 **−0.95%**(基准 +2.29%,超额 **−3.24pp**)。
全期回测(2015–2026)显示 +92.73% / CAGR 5.75%,
但 7 窗口 Walk-forward 的样本外收益均值仅 **+1.16%**(基准 +2.29%,超额 **−1.12pp**)。
它真正的价值在于**回撤控制**(样本外最差 −24.62%,基准同期 −46%~−52%)——
它真正的价值在于**回撤控制**(样本外最差 −22.97%,基准同期 −46%~−52%)——
更像降低波动的配置工具,而非超额收益来源。
> **四条必须说的结论**(详见[实施状态 §4.6c/§4.6d/§9](docs/implementation-status.md)):
>
> 1. **修数据让结果变差、但变真实了。** 行情原先只到 2015-01-05,
> 使「过去 5 年」窗口在 2019 年前被静默截短(覆盖率仅 20%~67%)。
> 2026-10-04 已把行情回补到 **2005-01-04**、涨跌停/停牌到 **2010**,
> 5 年窗口覆盖率提升到 **98.7%~100%**。代价是全期收益从 +117.36%
> 降到 **+92.73%** —— 因为 **2015 年(牛市顶 + 股灾)从「被数据缺口
> 挡住」变成被真实交易(−3.18%)**。靠数据缺口躲过股灾不是策略能力。
> 2. **实时画像闸门在两个口径下结论相反**:
> 单条路径 **−8.47pp**(有害),样本外 **+1.16pp**(有益)。
>
> | 口径 | 闸门开 | 闸门关 |
> |---|---:|---:|
> | 全期单路径总收益 | +92.73% | **+101.20%** |
> | Walk-forward 样本外均值 | **+1.16%** | −0.00% |
> | 样本外最差回撤 | **−22.97%** | −24.22% |
>
> **按本项目一贯立场以样本外为准**:闸门是改善。是否启用由你决定
> (`entry.profile_gate.enabled`);全期剔除 1027 次买入信号。
> 3. **同一项数据修正,在两个口径下的「效果」相差 32.9pp**
> (回补对样本外贡献 **0** —— 7 个窗口逐窗口未变;对单路径贡献 −32.9pp)。
> 这是「不要采信单条路径」最有力的例证。
> 4. **`stock_daily` 的量价单位曾前后不一致**(2015-2019 存「手/千元」,
> 2020 起存「股/元」),使流动性门槛在早年低估 1000 倍、**把 2015-2019
> 的股票池整体清空**。已修复(读取层幂等归一化 + 审计 `UNIT-OHLCV` 防回归)。
**请始终以 Walk-forward 的样本外结果为主要依据,不要采信单条路径的全期数字。**
详见[实施状态 §4.6](docs/implementation-status.md)。