3. 金融数据获取:Tushare/AkShare接口调用、数据缓存策略、多源数据合并、数据质量检查
做量化投研,数据就是你的弹药库。弹药不行,枪法再好也白搭。
这一章我们聊聊怎么搞到靠谱的金融数据。我这些年踩过的坑,基本都跟数据有关。数据源挂了、数据对不上、数据有缺失……嗯,都是血泪史。
3.1 Tushare 与 AkShare:两大主流数据源
国内做量化,绕不开两个库:Tushare 和 AkShare。我个人的习惯是,Tushare 用来拿股票、基金、指数这类标准化的金融数据,AkShare 则用来补一些另类数据,比如期货库存、宏观经济指标。
Tushare 调用示例
先注册个 token,然后就能愉快地调用了。注意,Tushare 的积分制度决定了你能拿到的数据量。我刚开始做的时候,积分不够,只能拿日线数据,后来才慢慢升级。
import tushare as ts
# 设置 token
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 更接地气,很多数据直接从财经网站爬下来。不过它更新频繁,有时候接口会变。我曾经遇到过,前一天还能跑的代码,第二天就报错了。所以,建议固定版本。
import akshare as ak
# 获取A股实时行情
df = ak.stock_zh_a_spot_em()
print(df.head())
3.2 数据缓存策略:别每次都去拉数据
你想想看,每次跑策略都去远程拉数据,网络延迟不说,还容易被限流。我个人的做法是:本地缓存 + 增量更新。
缓存策略设计
| 缓存层级 | 存储方式 | 适用场景 |
|---|---|---|
| 内存缓存 | dict / Redis | 高频访问的实时数据 |
| 文件缓存 | Parquet / CSV | 日线、分钟线等历史数据 |
| 数据库缓存 | SQLite / MySQL | 多策略共享的大规模数据 |
我一般用 Parquet 格式存历史数据,压缩率高,读取快。CSV 虽然通用,但大了之后读写慢得让人抓狂。
import pandas as pd
import os
def get_cached_data(file_path, start_date, end_date):
"""带缓存的日线数据获取"""
if os.path.exists(file_path):
# 读取本地缓存
df = pd.read_parquet(file_path)
# 检查是否需要更新
max_date = df['trade_date'].max()
if max_date < end_date:
# 增量拉取缺失数据
new_data = fetch_from_api(start_date=max_date, end_date=end_date)
df = pd.concat([df, new_data]).drop_duplicates()
df.to_parquet(file_path)
return df
else:
# 首次拉取全量数据
df = fetch_from_api(start_date, end_date)
df.to_parquet(file_path)
return df
3.3 多源数据合并:把碎片拼成拼图
做多因子策略时,你需要把不同来源的数据合并到一起。比如,Tushare 拿股票行情,AkShare 拿行业分类,再手动补一些财务数据。
合并的难点在于:时间对齐 和 代码映射。
时间对齐
不同数据源的交易日历可能不一样。比如,A股和港股节假日不同。我习惯先建一个统一的交易日历,然后做左连接。
# 假设 trade_cal 是统一的交易日历
trade_cal = pd.DataFrame({'trade_date': pd.date_range('2023-01-01', '2023-12-31')})
# 左连接,缺失值用前向填充
df_merged = trade_cal.merge(df_stock, on='trade_date', how='left')
df_merged = df_merged.ffill()
代码映射
同一个股票,不同数据源的代码可能不同。Tushare 用 '000001.SZ',AkShare 用 '000001'。我建了一个映射表,统一转成内部代码。
code_map = {
'000001.SZ': '000001',
'600000.SH': '600000',
# ...
}
3.4 数据质量检查:别让脏数据毁了你的策略
数据质量是量化投研的命门。我见过太多人,策略回测跑得飞起,实盘一塌糊涂。查到最后,发现是数据里有脏数据。
我总结了一套数据质量检查清单:
- 缺失值检查:有没有 NaN?占比多少?
- 异常值检查:价格有没有负数?涨跌幅有没有超过 100%?
- 重复值检查:有没有重复的日期-股票组合?
- 逻辑一致性检查:开盘价、最高价、最低价、收盘价是否合理?
- 时间连续性检查:交易日有没有跳空?
def check_data_quality(df):
"""数据质量检查"""
issues = []
# 缺失值
missing_pct = df.isnull().sum() / len(df)
if missing_pct.max() > 0.05:
issues.append(f"缺失值超过5%: {missing_pct[missing_pct > 0.05].index.tolist()}")
# 异常值
if (df['close'] <= 0).any():
issues.append("收盘价存在非正值")
# 重复值
if df.duplicated(subset=['trade_date', 'ts_code']).any():
issues.append("存在重复的日期-股票组合")
# 逻辑一致性
if (df['high'] < df['low']).any():
issues.append("最高价低于最低价")
return issues
知识体系总览
下面这张图,概括了本章的核心逻辑。从数据源到缓存,再到合并和质量检查,每一步都不能省。
说白了,数据获取这件事,七分靠工具,三分靠经验。工具选对了,经验攒够了,后面的事情就顺了。