你以为难的是写策略。其实大多数人,倒在了第一张表上。
上一篇,你装好了环境,拉到了第一段 K 线数据。
那一刻挺爽的——满屏的数字哗啦啦地下来,开高低收量样样齐全,像模像样。
然后你想干点正经事:算一条 20 周期的均线。
结果呢?要么报了一个看不懂的错,要么算出来一条诡异的曲线,中间断了好几截,时间还跳来跳去。
你盯着屏幕,第一次产生了那个朴素的疑问:我这数据,到底干不干净?
这就是这一篇要解决的事。
【本篇定位】
这是「用 Python 做量化」的第 ② 篇。
上一篇我们把数据拉进来了。这一篇,我们要把它捋顺——把一团乱麻的原始行情,整理成一张干净、可信、能直接拿去算的表。
数据清洗不是量化的"杂活",它是整条流水线里,最容易被低估、却最致命的一环。
因为后面所有的指标、信号、回测,都长在这张表上。表是歪的,上面盖的楼再漂亮,也是危房。
在动手清洗之前,你得先有个心智模型:pandas 到底给了你一个什么东西。
答案是一张带标签的表格,它叫 DataFrame。
你可以把它想象成一张 Excel 表,但更聪明:
- • 每一行,是某一根 K 线(某个时间点的行情)。
- • 每一列,是一个字段:开盘价、最高价、最低价、收盘价、成交量——也就是行情世界里雷打不动的 OHLCV(Open / High / Low / Close / Volume)。
- • 最关键的是行的"标签":在量化里,我们几乎总是把时间设成这个标签。
当时间成为索引(pandas 里叫 DatetimeIndex),这张表就活了。
你可以说"给我 3 月 1 号到 3 月 10 号的数据",可以说"把这些 1 分钟线聚合成日线",可以让两个不同品种按时间对齐——这些操作之所以一行代码就能搞定,全靠时间这个索引在背后撑着。
df = df.set_index("time").sort_index()
这一行做了两件朴素的事:把时间那一列拎出来当索引,再按时间从早到晚排好序。
别小看"排序"。你拉下来的数据,顺序不一定是对的——尤其是从多个文件、多个接口拼起来的时候。一根 3 月 5 号的 K 线,可能莫名其妙地排在了 3 月 8 号后面。
时间不对,一切皆错。排序,是清洗的第一道工序,也是最容易被忘掉的一道。
⚠️ 真实的数据,从来不干净
如果数据天生整齐,这一篇就不用写了。
但真实行情里,几乎每一份原始数据都带着伤。我们挨个看,它们长什么样、为什么危险、怎么处理。
1️⃣ 缺失:那根没来的 K 线
行情不是分秒不差地按格子下发的。网络抖一下、交易所那头打个嗝、休市跳过一段——你的数据里就出现了缺口:某个本该有 K 线的时间点,是空的。
危险在哪?你算均线、算涨跌幅时,一个空值会像墨水滴进清水,顺着计算一路扩散,让后面一连串数字全变成"没有"。
怎么办?先看清有多少缺失、缺在哪。然后想清楚:是把这几行直接丢掉,还是用前一根的值补上。
这里有个反直觉的点:补缺要小心方向。 用"后面的值"去填"前面的空",等于让此刻偷看了未来——这正是我们后面要反复警惕的"未来数据"。所以在行情里,补值通常只能向前递补(拿过去补现在),绝不能拿未来补过去。
2️⃣ 重复:同一根 K 线,来了两次
拼接数据时极常见:两个文件首尾重叠,或者接口把同一根 K 线推送了两遍。
表面看人畜无害,实则要命——重复的 K 线会让成交量翻倍、让某个时间点的权重凭空变大,回测里它甚至可能让你"赚"两次同一笔钱。
df = df[~df.index.duplicated(keep="first")]
这一行的大白话是:同一个时间点如果出现了多次,只留第一根,其余的扔掉。 干净利落。
3️⃣ 乱序与对齐:时间轴必须是直的
前面说了排序。但还有更隐蔽的一种"对不齐":当你想把两个品种、或者两个不同周期的数据放在一起看,它们的时间点往往对不上。
A 在 9:01 有数据,B 在 9:01 没有;你硬把它们并排,就会错位——拿 A 的此刻去配 B 的彼刻,算出来的关系全是假的。
没对齐的两列数据,看起来在"一起",其实各说各话。
pandas 的索引机制能帮你按时间对齐:对齐之后空出来的格子,会老老实实显示成缺失,逼你正视它,而不是悄悄算错。
🔧 重采样:把 1 分钟,聚合成 1 小时
清洗之外,还有一件你迟早要做的事:换周期。
你手里可能是 1 分钟线,但策略想看小时线、日线。这个"把细的合成粗的"动作,叫重采样(resample)。
它不是简单地"每 60 根取 1 根"。OHLCV 各有各的聚合逻辑:
df.resample("1H").agg({"open":"first","high":"max","low":"min","close":"last","volume":"sum"})
这一行就是把上面那五句话翻译成了代码:按 1 小时分组,每组的开高低收量分别用 取首 / 取最大 / 取最小 / 取末 / 求和 的方式合并成一根新 K 线。
为什么强调这个?因为周期是策略的隐藏前提。同一套规则,跑在 1 分钟和跑在日线上,是两个完全不同的世界。能干净地在周期之间切换,你才谈得上"在合适的尺度上验证想法"。
到这一步,你手里的表才算"捋顺"了:时间为序、没有缺口黑洞、没有重复幽灵、周期清清楚楚。
而这,正好回扣「0.01手」的内核——从最小处起步,先把最基础的一环做扎实,再谈上层。 数据这一环你糊弄了,上面盖多高都白搭。
🪤 垃圾进,垃圾出
这一篇我最想钉进你脑子里的,是一句计算机领域的老话:
Garbage in, garbage out.垃圾进,垃圾出。
它的意思朴素得近乎残忍:喂进去脏数据,再精妙的模型也只会吐出脏结论。 漏斗不会净化垃圾,它只是把垃圾换了个形状流出来。
这句话,是连向第四季《回测的科学》第①篇《回测为什么会骗你》的一座桥。
那一篇讲的是:一份看起来收益惊人的回测,很可能从一开始就建立在错的数据上。 重复的 K 线、对不齐的时间、偷看了未来的填充——这些清洗阶段的疏漏,会变成回测里那条骗人的、漂亮得不真实的资金曲线。
所以请记住:你回测结论的可信度上限,在清洗数据这一步就已经被锁死了。
它不性感,没有策略那么让人兴奋。但它是地基。
别人盯着楼有多高,你先蹲下来,看看地基是不是平的。
📌 小结
把这一篇收成几条,钉在你写下一行代码之前:
- • DataFrame 是带行列标签的表:行是每根 K 线,列是开高低收量(OHLCV),把时间设成索引(DatetimeIndex),这张表才真正好用。
- • 清洗四步:设时间索引并排序 → 处理缺失 → 去掉重复 → 时间对齐。每一步都对应一类真实存在的"脏"。
- • 补值要防"偷看未来":只能拿过去补现在,绝不能拿未来补过去——这是后面"前视偏差"的第一个伏笔。
- • 重采样换周期:开取首、收取末、高取最大、低取最小、量求和;周期是策略的隐藏前提。
- • 垃圾进,垃圾出:回测能有多可信,从清洗这一步就决定了。
【下一篇预告】表捋顺了,接下来就该让它"开口算话"了。第 ③ 篇,我们聊向量化——为什么不用写一个个 for 循环,几行代码就能在整张干净的表上,一次性把所有指标算完。慢的写法和快的写法,差的不只是速度。
如果这篇帮你看清了"数据清洗"这件被低估的小事,点个赞、点个关注,让它能被更多还在跟脏数据较劲的人看到。
也欢迎在留言区说说:你拉数据时,踩过最坑的一次"脏数据"是什么样的?
本文仅为个人学习记录与编程笔记,所涉代码与方法均为技术科普,非交易建议,不构成任何操作建议。市场有风险,据此操作风险自负。