← 返回文档中心 · 来源:Languangxun/stock-analyzer · 同步于 2026-09-27

范围:stock_cache.db 日K(7624 只代码 / 约 1240 万根)与 data_clean.py 清洗链。 本报告为只读诊断 + 已实施修复的记录;第三节是仍需决策的数据层问题。


一、已修复:浅迁移截断(数据丢失 28.2 万根)

现象:data_clean.py 旧版 _fetch_tx_kline 固定翻 2 页(腾讯 800/根/页 → 上限 1600 根)。热修⑩给 --fix 加 force=True 后,被扫描判定(含大量误报)的 664 只 代码整只重拉,其中约 370 只长历史股被截断:

  • 全库日K:12,685,971 → 12,403,617(-282,354 根);
  • 664 只中有 369 只现为 1600/1601 根且首根早于 2020-02-26(截断签名), 例:创业板指 sz399006 1600 根(起点 2020-02-26),同批指数/老股原为 2400 根 (起点 2016-11-11)。

已修:

  • 迁移深度改为 max(库内根数, --depth=2400),按需翻页(最多 6 页/4800 根);
  • 新增防缩水守卫:新序列首根变晚且不更长(keep_head)或末根变旧(keep_tail) 时保留库内原数据,--allow-shrink 才可覆盖;
  • 新增 --repair(GUI 数据工具「截断修复」):重拉「根数<2400 且首根早于 2021-01-01」的 1972 只代码补齐 2016–2020 深历史。实测单只 sz399006 1600→2400 根、起点回到 2016-11-11。 (注:截断修复跑到 600/1972 时,第三节口径问题确认,改为全库 --all-adj --force 重迁——该重迁同时补齐深度,修复模式保留供后续使用。)

二、已修复:扫描误报与噪声(同一规则还被 GUI 清洗沿用)

扫描判定原先未复用 stock_gui._bars_anomalous 的误报豁免,导致大量健康数据 被反复”整只重拉”(即第一节截断的触发源)。现 data_clean 与 GUI 共用同一 规则(新股前 10 根 / 相邻>30 天停牌复牌 / 现名回溯 ST 放宽到 10% / ETF 折算 孤立跳变放行 / 指数与退市整理豁免)。修复前后全库扫描对比:

项 修复前 修复后 说明
涨跌幅越界 779 只 59 只 北交所源停更 84 只单独忽略

残留 59 只多数正是第三节仿射失真的表现(收益被放大 s>1 后,真实 10% 涨停在 hfq 里显示 >13%);对它们重拉腾讯 hfq 无济于事(_validate 会拒绝同源失真数据),须等第三节省口径决策后统一处理。 | 末价<0.5「失真」 | 40 只 | 0 | ETF/退市真实低价不再误报 | | 长停牌缺口 | 1316 只 | 41 只 | 只报近一年(陈年停牌属正常) | | 落后市场最新日>10天 | 370 只 | 33 只 | 北交所停更 336 只单独统计 | | 孤立代码(有K线无代码表) | 未检 | 新增统计 | 如错误前缀 sz688012 | | 扫描耗时(全库) | 238s | 40s | 日期解析改 date.fromisoformat |

stock_gui.clean_daily_db 同步安全化:判定走 _bars_anomalous,整只重拉 target=max(库内根数, 2400) 并加丢头/丢尾守卫(不满足则保留原数据)。

三、待决策:腾讯 hfq 是仿射变换,日收益率被逐股缩放(严重)

结论:库内主口径(热修⑩起统一为腾讯「后复权 hfq」)不是乘法后复权。 实测腾讯 hfqday 在不含除权的区间内严格满足

hfq(t) ≈ a × 不复权价(t) + b     (段内 a、b 恒定)

于是整段日收益率被缩放为 s = a·P / (a·P + b) ≈ 中位(hfq日收益 / 不复权日收益); 该缩放随每次除权除息跳变,且每一根 bar 都受影响(不是只在除权日)。

证据(近 120 根拟合,配对同一交易日):

代码 名称 拟合 R² 收益缩放 s 备注
sh600000 浦发银行 0.96 0.63 日收益被缩小 37%
sh601318 中国平安 0.98 0.72  
sh600519 贵州茅台 0.98 0.82  
sz000725 京东方A 0.9998 0.87  
sz300750 宁德时代 0.99 0.95  
sz000005 ST星源 1.0000 1.75 日收益被放大 75%
sh600653 申华控股 1.0000 1.75  

单日对照(sh600653 2018-08-01,涨跌停 ±10% 的主板股): 不复权 1.98→2.18 = +10.10%(涨停);腾讯 qfq +10.1%(正确); 腾讯 hfq +16.35%(失真)。sh600595 2014-07-22/23 两天连续涨停, 不复权 +10.10%/+10.07%,hfq 报 +15.24%/+14.52%。

影响面(抽样 8 只,5 只 |s-1|>2%):失真既非个别股票也非小量级; v6.1.5 起(热修⑩/全库迁移后的)回测、因子、形态匹配所用收益率均带逐股 缩放,且缩放系数随时间(除权)变化。热修⑩的”重叠日偏差 0.0000%”验证是 循环验证(库内与源同为腾讯 hfq),未检出该问题。

可复现体检(新增,只读):

python3 data_clean.py --check-adj --sample 300      # 报告 reports/复权体检_*.md
# GUI:工具 → 数据工具 → 模式选「复权失真体检」

处置(2026-09-27 已确认并实施,全链切换):

用新浪复权因子 finance.sina.com.cn/realstock/company/<code>/hfq.js × 腾讯不复权日K 重建真乘法后复权,已落到全部数据路径:

路径 改动
data_clean.py 迁移 _hfq_mul 为第一候选源(sina > tx hfq > em),K=1/f_last 顺带算出
stock_gui.py 在线拉取 新增 _fetch_tencent_mul,_fetch_remote_rows 四个腾讯源全部改走它
stock_gui.py 深历史 _bf_tx_pages(不复权可翻页)+ _to_hfq_mul,_bf_fetch_one 重写
backfill_full.py _fetch_one 统一委托 sg._bf_fetch_one,不再直存腾讯 hfq
sync_adjust.py 基期漂移比对改 fetch_hfq_correct(同口径),不再与仿射 hfq 比

验证:sh600000 / sh600653 / sh600595 重建后收益比中位 1.0000、 涨跌停越界 0 处(同股腾讯 hfq 越界 70~167 处);抽样 30 只 ETF/LOF 用腾讯 qfq,越界 0;深度 2400 根。全库 --all-adj --force 重迁已完成 (7103/7105 成功,2 只防缩水保留原数据,约 2 小时;日志 /tmp/opencode/migrate_basis4.log)。

四、完工复核(2026-09-27 14:35)

  • --check-adj --sample 300:有效 297、低波动不判 3、失真 0(s 中位 P10/P90 全为 1.000);
  • 全库清洗扫描(38s):结构异常 0(修复前 107/10)、负价 0、 涨跌幅越界 10 只(修复前 779,余者为 PT水仙/PT金田A/吉林化工等 退市老股的真实历史事件)、末价失真 0、价格粘性 0;
  • 全库 12,714,846 根(受损后 12,403,617、受损前 12,685,971), 截断丢失的深度全部补齐且更深:sz399006 1600→2400(2016-11 起)、 sh600000/sh600519/sz002241/sh510050 均 2400 根;≥2400 根代码 3127 只;
  • 旧策略缓存 meta 表 strategy:* 7178 条已清空(按需重算)。

待办:重跑 v6.1.5 回测 / factor_lab 面板(旧口径结果作废)。

备选/后续:

  1. 等东财恢复后验证 fqt=2 收益率保真度,作为新浪因子的交叉校验/容灾;
  2. 若两源都不可用:改存不复权价 + 除权事件表,读取层自行复权;
  3. 过渡方案:研究/回测前用体检的 s 还原(不推荐,s 随除权变化)。

生成:v6.1.5 热修⑪(2026-09-27)。不构成投资建议。