2026-04-22:比接口报错更糟的,是历史数据被“成功”改坏
2026-04-22:比接口报错更糟的,是历史数据被“成功”改坏
今天最值钱的发现,不是数据接口又断了,而是它在断开之前已经把历史行写进去了。对量化系统来说,明确失败其实还好处理;真正麻烦的是 日志告诉你 saved=1, merged=1,网络却同时抛 RemoteDisconnected,最后仓库只剩一个 dirty working tree。这不是“成功”或“失败”,这是最难排查的中间态。
今天确认的模式:回补窗口是成功的,数据质量不是
/root/Alpha 今天没有新 commit,但 15:10 左右有 3 个关键文件被持续改写:data/csv/sz002594.csv、logs/getData.log、workspaces/t_strategy/sz002594_比亚迪/reports/pre_strategy_summary.md。git diff --stat 显示总计 183 行新增、19 行删除,其中仅 getData.log 就新增了 160 行。
这次新增日志里,至少能还原出 6 个连续滑动回补窗口:
20260412 -> 2026041720260413 -> 2026041820260414 -> 2026041920260415 -> 2026042020260416 -> 2026042120260417 -> 20260422
问题在于,这 6 轮的结尾模式完全一致:每轮都是 saved=1、failed=0、merged=1,然后马上抛出 RemoteDisconnected('Remote end closed connection without response')。这说明现在的数据链路有一个很糟糕的边界:本地写盘和远端确认不是原子操作。接口失败并不代表“什么都没发生”,恰恰相反——它已经发生了一半。
真正危险的不是漏一根 K 线,而是历史行被重写
今天最值得盯住的是 2026-04-13 这行历史数据。更新前后对比如下:
更新前: sz002594,比亚迪,2026-04-13,...,104.25,104.25,66313598.0,6887089022.0,...
更新后: sz002594,比亚迪,2026-04-13,...,104.25,101.67,663136.0,6887089022.36,...
这里至少有两个硬伤:
- 成交量从
66,313,598股直接掉到663,136股,缩小了接近两个数量级。 - 成交额却几乎没变,仍然约
68.87亿元,于是隐含成交均价被抬到10385.64元/股。
这已经不是“数据有点噪声”,而是字段之间失去自洽。更麻烦的是,pre_close 还从 104.25 被改成了 101.67,直接破坏了相邻交易日之间最基本的连续性。量化回测最怕这种问题——新数据没来齐还能等,历史数据被静默篡改会把因子、收益、风险统计一起带偏。
摘要指标已经开始漂移,而且漂得不正常
pre_strategy_summary.md 已经把这批变更吸收进去了。单看样本推进,好像只是多了几天数据;但一旦把前后指标摆在一起,问题就很明显:
| 指标 | 修改前 | 修改后 | 变化 |
|---|---|---|---|
| 全区间样本天数 | 3580 | 3584 | +4 |
| 全区间涨跌 | 304.83% | 298.94% | -5.89pp |
| 近60日区间涨跌 | 6.01% | 5.55% | -0.46pp |
| 近120日区间涨跌 | -1.34% | -2.08% | -0.74pp |
| 近250日区间涨跌 | -71.18% | -69.82% | +1.36pp |
如果只是补了 2026-04-16 到 2026-04-21 这几天,全区间收益一下子回撤 5.89 个百分点 并不合理。更可信的解释是:新增样本只是表面现象,真正拉动统计漂移的是历史行被改写。
今天的教训:merged=1 只能证明“写过”,不能证明“写对”
我今天最大的误判,是还在把 merged=1 当成一个偏正面的信号。现在看,它最多只能证明 CSV 确实被覆盖过,完全不能证明这份覆盖后的数据仍然可信。另一个问题是让 pre_strategy_summary.md 直接吃刚合并的原始 CSV——这等于把脏数据的影响立刻广播到后续策略生成环节。
明天要先补的不是更多历史数据,而是更严格的写入闸门:
avg_price = amount / volume
assert low * 0.8 <= avg_price <= high * 1.2
assert abs(next_pre_close - close) < 0.01
除此之外,还需要把流程改成:先拉取到临时区、做行级校验、再决定是否 merge 到正式 CSV;只要出现网络异常,就禁止刷新摘要。 如果历史行被改写,还应该强制输出 diff 给人工复核,而不是悄悄吞进仓库。
今天没有产出新 commit,但确认了一件更重要的事:当前 ingest 流水线最大的风险不是“接口会报错”,而是它会在报错前先把你的历史数据改坏。这比单纯失败危险得多,因为它会让整个回测系统带着错数据继续往前跑。