第三章:数据获取与清洗——量化策略的“原材料”处理
做量化交易,数据就是你的命根子。这话一点不夸张。
我见过太多人,策略逻辑写得天花乱坠,结果一跑实盘就崩。为什么?数据源选错了,或者数据没洗干净。说白了,你拿脏数据去训练模型,出来的结果能靠谱吗?
这一章,我们就来聊聊数据获取与清洗。我会把我在项目中踩过的坑、积累的经验,都摊开来跟你讲。
3.1 数据源选择:选对“水源”很重要
数据源就像水源。水源干净,后面的事就省心。水源浑浊,你后面再怎么过滤也费劲。
目前国内用得比较多的,主要有三个:Tushare、Baostock、yfinance。我一个个说。
3.1.1 Tushare
Tushare 是国内量化圈的老牌数据源。数据全,更新快,但门槛也高。
- 优点:股票、基金、期货、宏观经济,几乎全覆盖。数据质量高,字段丰富。
- 缺点:需要积分。免费用户只能拿基础数据,高级接口要花钱买积分。我刚开始做的时候,为了省积分,愣是手动爬了一周数据……后来发现,时间成本比积分贵多了。
- 适合场景:专业策略、需要高频或深度数据的场景。
重要提醒:Tushare 的 token 要妥善保管。我有个朋友把 token 直接写死在代码里,结果代码传到 GitHub 上,被人拿去刷接口,一天就超限了。
3.1.2 Baostock
Baostock 是免费的,而且不需要注册。对新手特别友好。
- 优点:免费、无门槛、数据覆盖A股历史行情。接口简单,几行代码就能拿到数据。
- 缺点:数据更新有延迟,字段不如 Tushare 丰富。实时数据基本没有。
- 适合场景:学习、回测、低频策略。
我个人习惯用 Baostock 做快速验证。比如我想测试一个简单的均线策略,用 Baostock 拿数据,5分钟就能跑起来。但如果要上实盘,我会换 Tushare。
3.1.3 yfinance
yfinance 是雅虎财经的 Python 接口。主要拿美股数据。
- 优点:免费、全球市场覆盖、接口简单。拿美股数据首选。
- 缺点:国内访问不稳定,经常断连。数据质量参差不齐,有些股票的历史数据会有缺失。
- 适合场景:美股策略、全球资产配置。
我的建议:如果你做A股,优先选 Tushare 或 Baostock。做美股,yfinance 够用。但别只依赖一个数据源,最好备一个“备胎”。我在实盘中就遇到过 Tushare 接口临时维护,全靠 Baostock 顶上去。
3.2 数据清洗与预处理:脏数据是策略的“隐形杀手”
数据拿到手,别急着用。先洗一洗。
你想想看,交易所的数据也会有错误。比如某一天某只股票停牌,但数据源可能给你返回一个0或者空值。如果你不处理,模型会以为那天股价是0,直接崩掉。
数据清洗,我一般做这几步:
3.2.1 处理缺失值
缺失值是最常见的问题。处理方法有三种:
- 删除:如果缺失值不多,直接删掉那一行。简单粗暴。
- 填充:用前一天的数值填充(向前填充),或者用均值填充。我个人习惯用向前填充,因为金融数据有连续性。
- 插值:用线性插值或多项式插值。适合数据量少、缺失值分布均匀的情况。
# 向前填充示例
import pandas as pd
df['close'].fillna(method='ffill', inplace=True)
注意:千万不要用0填充股价数据。我曾经见过有人这么干,结果策略回测收益率高得离谱,一查才发现是填充了0导致计算收益率时出现无穷大。
3.2.2 处理异常值
异常值,比如某天股价突然涨了1000倍,或者成交量突然为0。这些很可能是数据错误。
我常用的方法是:
- 3σ原则:超出均值±3倍标准差的数据,视为异常。
- IQR方法:四分位距法,超出Q1-1.5IQR或Q3+1.5IQR的数据,视为异常。
- 业务规则:比如涨跌幅超过20%的,直接标记出来人工审核。
3.2.3 去重与对齐
数据源有时会重复推送同一时间点的数据。去重是必须的。
另外,不同数据源的时间戳可能不一致。比如 Tushare 用东八区,yfinance 用 UTC。对齐时间戳,否则你的策略会“时空错乱”。
# 去重示例
df.drop_duplicates(subset=['date', 'code'], keep='last', inplace=True)
# 时间对齐
df['date'] = pd.to_datetime(df['date']).dt.tz_localize('Asia/Shanghai')
3.3 特征工程基础:从数据中“挖”出信号
特征工程,说白了就是把原始数据变成模型能理解的“语言”。
原始数据只有价格、成交量这些。但模型需要的是趋势、动量、波动率这些“高级特征”。
3.3.1 常见特征类型
| 特征类型 | 示例 | 说明 |
|---|---|---|
| 价格特征 | 收盘价、开盘价、最高价、最低价 | 最基础的原始数据 |
| 衍生特征 | 涨跌幅、振幅、换手率 | 由原始数据计算得到 |
| 统计特征 | 移动平均、标准差、最大值、最小值 | 反映一段时间内的统计规律 |
| 技术指标 | RSI、MACD、布林带 | 经典的技术分析工具 |
| 时间特征 | 星期几、月份、季度 | 捕捉时间周期效应 |
3.3.2 特征构建实战
我一般会先构建几个“必选特征”:
- 收益率:当日收盘价 / 前一日收盘价 - 1。这是最核心的特征。
- 波动率:过去N天收益率的标准差。反映风险。
- 动量:过去N天的累计收益率。反映趋势。
- 成交量变化:当日成交量 / 过去N天平均成交量。反映资金活跃度。
# 特征构建示例
import numpy as np
# 收益率
df['return'] = df['close'].pct_change()
# 波动率(20天)
df['volatility'] = df['return'].rolling(window=20).std()
# 动量(20天)
df['momentum'] = df['close'] / df['close'].shift(20) - 1
# 成交量变化
df['volume_ratio'] = df['volume'] / df['volume'].rolling(window=20).mean()
经验之谈:特征不是越多越好。我见过有人一口气造了200个特征,结果模型过拟合得一塌糊涂。我的原则是:先造10-20个核心特征,跑一遍模型,再根据结果逐步添加。贪多嚼不烂。
3.4 本章知识体系总览
下面这张图,是我自己总结的数据获取与清洗的完整流程。你可以把它当作一个“检查清单”。
这张图把整个流程串起来了。从数据源选择开始,到最终拿到干净、有特征的数据,每一步都不能跳过。
嗯,这里要注意:特征工程不是一劳永逸的。市场在变,特征也要跟着迭代。我每季度都会重新审视一遍特征集,看看哪些失效了,哪些需要新增。
好了,数据获取与清洗就讲到这里。记住一句话:数据质量决定策略上限。花80%的时间在数据上,都不为过。