第四章:金融数据获取——从Tushare到AkShare的实战之路
数据是量化交易的基石,这话一点不夸张。我见过太多人把精力全花在策略上,结果数据源出了问题,回测跑得飞起,实盘一塌糊涂。今天咱们就聊聊怎么把数据这关过好。
核心要点:本章覆盖数据获取、清洗、存储三大环节。你会掌握Tushare和AkShare两个主流库,学会处理常见的数据坑,并选择最适合的存储方式。
4.1 为什么选Tushare和AkShare?
国内做量化,绕不开这两个库。我个人习惯是:需要高频数据或机构级数据时用Tushare Pro,日常研究、快速验证用AkShare。为什么这么分?
- Tushare Pro:数据质量高,覆盖全面,但需要积分(说白了就是付费)。适合做严肃的回测和实盘。
- AkShare:完全免费,接口丰富,更新快。但数据源来自公开网站,偶尔会有格式问题。适合学习和快速原型。
我在项目中遇到过这样的情况:用AkShare抓了半年的日线数据,回测收益曲线漂亮得不行。结果一核对,发现某几天数据因为网站改版漏掉了。嗯,从那以后我养成了双源校验的习惯。
4.2 安装与基础配置
先装库,这步没什么难度:
# 安装Tushare
pip install tushare
# 安装AkShare(建议用最新版)
pip install akshare --upgrade
用Tushare需要注册获取token。你想想看,免费的东西往往最贵——这里的「贵」体现在你需要花时间申请权限。不过流程很简单:
import tushare as ts
# 设置token(去tushare.pro官网注册获取)
ts.set_token('你的token_here')
pro = ts.pro_api()
小技巧:我习惯把token写在环境变量里,而不是硬编码在代码中。这样换机器或分享代码时不会泄露密钥。
4.3 实战:获取股票数据
4.3.1 用Tushare获取日线数据
获取某只股票的历史日线,代码很简洁:
# 获取平安银行(000001.SZ)2023年全年日线数据
df = pro.daily(
ts_code='000001.SZ',
start_date='20230101',
end_date='20231231'
)
print(df.head())
返回的字段包括:trade_date、open、high、low、close、vol、amount等。注意,Tushare默认按日期降序排列,我一般会手动排序:
df = df.sort_values('trade_date')
4.3.2 用AkShare获取实时行情
AkShare的实时数据接口很丰富。比如获取A股实时行情:
import akshare as ak
# 获取A股实时行情数据
df_real = ak.stock_zh_a_spot_em()
print(df_real.head())
这里有个坑——AkShare返回的列名是中文。我曾经直接拿去做计算,结果报错半天才发现是列名编码问题。建议第一时间重命名:
df_real.columns = ['代码', '名称', '最新价', '涨跌幅', ...] # 按实际列数调整
注意:AkShare的数据源是东方财富等网站,如果对方接口调整,你的代码可能突然失效。我建议每次运行前检查一下返回的列数是否正常。
4.4 数据清洗与预处理
拿到原始数据只是第一步。真实的数据往往千疮百孔——缺失值、异常值、格式问题,应有尽有。我总结了一套标准流程:
4.4.1 处理缺失值
股票数据最常见的缺失是停牌日。比如某股票停牌一周,那几天的数据就是空的。处理方法:
# 检查缺失值
print(df.isnull().sum())
# 前向填充(用上一个交易日的数据填充)
df.fillna(method='ffill', inplace=True)
# 或者直接删除缺失行(如果缺失不多)
df.dropna(inplace=True)
我个人习惯用前向填充。为什么?因为停牌期间信息没有变化,用前值填充最合理。但如果是财务数据缺失,我会用插值法。
4.4.2 处理异常值
你想想看,一只股票突然涨了1000%,这正常吗?大概率是数据错误。我常用的方法是:
# 用3倍标准差法检测异常
mean = df['close'].mean()
std = df['close'].std()
df = df[(df['close'] > mean - 3*std) & (df['close'] < mean + 3*std)]
不过要注意,新股上市首日涨跌幅可能很大,别误杀了。我曾经就犯过这个错,把一只刚上市的新股数据全删了,回测结果直接少了一段。
4.4.3 统一日期格式
Tushare返回的日期是字符串,AkShare可能是datetime。统一转换成标准格式:
df['trade_date'] = pd.to_datetime(df['trade_date'])
df.set_index('trade_date', inplace=True)
把日期设为索引,后续做时间序列分析会方便很多。
4.5 数据存储:CSV、Excel还是HDF5?
数据清洗完了,得存起来。三种方式各有优劣,我直接给你对比:
| 存储方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| CSV | 通用性强,任何工具都能打开 | 不支持多表,读写慢,无压缩 | 小数据量、临时分析 |
| Excel | 可视化好,支持多Sheet | 速度慢,有行数限制(104万行) | 数据量小、需要人工查看 |
| HDF5 | 读写快,支持压缩,支持大数据 | 需要额外库,不直观 | 大规模数据、高频数据 |
我的建议是:日常研究用CSV,生产环境用HDF5。Excel我基本不用,除非要给不懂代码的同事看。
4.5.1 CSV存储示例
df.to_csv('stock_000001.csv', encoding='utf-8-sig')
# 用utf-8-sig编码,避免Excel打开乱码
4.5.2 HDF5存储示例
# 需要安装:pip install tables
df.to_hdf('stock_data.h5', key='000001', mode='a')
# 读取
df_read = pd.read_hdf('stock_data.h5', key='000001')
HDF5支持按key存储多个DataFrame,我习惯把不同股票存到同一个文件的不同key下,读取时按需加载,速度飞快。
避坑指南:我曾经把全市场5000只股票的日线数据存到一个CSV文件里,结果文件超过2GB,打开一次要等5分钟。后来改用HDF5,按股票代码分key存储,读取单只股票的数据只需毫秒级。
4.6 本章知识体系
下面这张图帮你理清整个数据获取与处理的流程:
从数据源到最终策略,每一步都有讲究。别想着一步到位,先把数据基础打牢。
本章小结:
- Tushare适合严肃场景,AkShare适合快速验证
- 数据清洗是重中之重,缺失值和异常值必须处理
- 存储方式按需选择,大数据量优先考虑HDF5
- 养成双源校验的习惯,避免数据错误导致策略失效
好了,数据获取这块就聊到这儿。记住,好的策略需要好的数据支撑。下一章咱们会把这些数据用起来,开始构建第一个量化策略。
公众号:蓝海数据掘金营,微信deep3321