3、数据获取与清洗:股票数据源介绍与预处理
做量化回测,数据就是你的弹药。弹药不行,枪法再好也白搭。我见过太多人把时间花在策略优化上,结果数据源一换,收益曲线直接变形。今天咱们就把数据获取和清洗这块硬骨头啃下来。
3.1 主流股票数据源介绍
国内做量化,常用的数据源就三个:Tushare、AKShare、Yahoo Finance。我个人的习惯是,A股用Tushare或AKShare,港股美股用Yahoo Finance。下面逐个说说。
Tushare
老牌数据平台,数据质量高,但需要注册获取token。免费版有调用频率限制,不过个人学习完全够用。我记得刚开始用Tushare时,被那个token搞晕过,后来发现其实就是个API密钥,存到环境变量里就行。
import tushare as ts
ts.set_token('你的token')
pro = ts.pro_api()
# 获取日线数据
df = pro.daily(ts_code='000001.SZ', start_date='20230101', end_date='20231231')
print(df.head())
AKShare
开源免费,接口丰富,更新快。说白了就是爬虫封装,但人家封装得好,用起来顺手。我项目中做实时数据监控时,经常用AKShare,因为它不需要token,直接pip安装就能用。
import akshare as ak
# 获取A股日线数据
df = ak.stock_zh_a_hist(symbol="000001", period="daily",
start_date="20230101", end_date="20231231", adjust="qfq")
print(df.head())
Yahoo Finance
国际通用,覆盖全球市场。但有个坑——它经常被墙,需要科学上网。另外,Yahoo的数据有时会有延迟,做日内交易的朋友要小心。我一般用它来拉美股数据,比如苹果、特斯拉这些。
import yfinance as yf
# 获取苹果股票数据
aapl = yf.download('AAPL', start='2023-01-01', end='2023-12-31')
print(aapl.head())
3.2 数据字段说明
拿到数据后,先别急着跑策略。你得搞清楚每个字段是什么意思。常见的日线数据字段如下:
| 字段名 | 含义 | 说明 |
|---|---|---|
| open | 开盘价 | 当日第一笔成交价 |
| high | 最高价 | 当日最高成交价 |
| low | 最低价 | 当日最低成交价 |
| close | 收盘价 | 当日最后一笔成交价 |
| volume | 成交量 | 当日成交股数 |
| amount | 成交额 | 当日成交金额(元) |
你想想看,如果拿到的数据里close是空值,那你的策略还怎么算收益率?所以数据清洗这一步,省不了。
3.3 数据清洗流程
数据清洗,说白了就是给数据「洗澡」。我总结了一套标准流程,你照着做就行:
- 检查数据类型——确保日期是datetime,价格是float,成交量是int
- 处理缺失值——看看有没有NaN,有的话要处理
- 去重——同一只股票同一天出现两次,肯定有问题
- 排序——按日期升序排列,这是回测的基本要求
- 复权处理——这个后面单独讲
核心原则:清洗后的数据,必须能直接用于回测,不需要再手动调整。
3.4 缺失值处理
为什么会缺失?原因很多:停牌、数据源没更新、节假日等等。我遇到过最离谱的一次,某只股票连续停牌三个月,中间全是NaN。如果你直接dropna(),那三个月的数据就没了,回测结果肯定不准。
常见的处理方法有三种:
- 向前填充(ffill):用上一个交易日的数据填充。适合停牌的情况,因为停牌期间价格不变。
- 向后填充(bfill):用下一个交易日的数据填充。适合数据源延迟的情况。
- 插值法:用前后数据做线性插值。适合少量缺失的情况。
import pandas as pd
# 假设df是日线数据,包含NaN
# 向前填充(推荐用于股票数据)
df.fillna(method='ffill', inplace=True)
# 或者用插值法
df.interpolate(method='linear', inplace=True)
# 检查是否还有缺失值
print(df.isnull().sum())
我的建议:对于股票日线数据,优先用ffill。因为股票停牌期间,价格确实不变。用插值反而会引入虚假的价格变动。
3.5 复权价格计算
复权,是量化回测里最容易踩坑的地方。我曾经因为没做复权,回测结果看起来年化50%,实盘一跑直接亏成狗。为什么会这样?因为股票会分红、送股、配股,这些事件会导致价格出现「跳空」。不复权的话,你的策略会误以为价格跌了,实际上只是除权除息。
复权有两种方式:
- 前复权:调整历史价格,让价格连续。当前价格不变,历史价格按比例调整。适合回测,因为能看到真实的收益率。
- 后复权:调整当前价格,让历史价格不变。适合看长期走势,但当前价格会失真。
我个人做回测时,一律用前复权。Tushare和AKShare都提供了复权接口,直接调用就行。
# Tushare前复权
df = pro.daily(ts_code='000001.SZ', start_date='20230101',
end_date='20231231', adj='qfq')
# AKShare前复权
df = ak.stock_zh_a_hist(symbol="000001", period="daily",
start_date="20230101", end_date="20231231",
adjust="qfq")
注意:如果你从Yahoo Finance下载数据,它默认是后复权。记得用 yf.download(..., auto_adjust=True) 来获取调整后的价格。
3.6 知识体系总览
下面这张图,是我自己画的数据获取与清洗流程。你照着这个框架走,基本不会出大问题。
嗯,到这里,数据获取与清洗的核心内容就讲完了。你可能会问,这些步骤看起来简单,但实际做起来会不会有坑?说实话,坑肯定有。比如不同数据源的字段名不一样,Tushare叫trade_date,AKShare叫日期,你得自己映射。再比如复权因子,有些数据源不直接提供,需要自己算。但这些都属于「熟练工」的范畴,多踩几次坑就记住了。
一句话总结:数据清洗花的时间,永远值得。干净的数据是策略回测的基石,别在这上面偷懒。