4、数据获取与清洗:用tushare/akshare搞定行情数据

做统计套利,第一步就是搞数据。这事儿听起来简单,但坑特别多。我刚开始做量化那会儿,光数据清洗就折腾了两周——拿到的日线数据里居然有未来数据,回测曲线漂亮得不像话,实盘直接翻车。嗯,从那以后我对数据环节就特别较真。

今天咱们就聊聊怎么用tushare和akshare拿数据,以及拿到手之后怎么处理。说白了,这两步做好了,后面的策略分析才有意义。

4.1 数据源的选择:tushare vs akshare

国内做量化,绕不开这两个库。我个人习惯是:tushare做主力,akshare做补充。为什么?

  • tushare:数据质量高,字段规范,适合做精细分析。但需要积分,免费版有调用限制。
  • akshare:数据源多,免费,适合快速验证。但偶尔会有数据缺失或格式不一致的问题。

你想想看,如果只是做策略原型,akshare完全够用。但真要跑实盘或者做严谨的回测,我建议用tushare。我在项目中遇到过akshare某只股票的复权数据突然断了一天,排查了半天才发现是源网站的问题。

核心原则:数据源可以混用,但同一策略必须用同一数据源,否则回测和实盘对不上。

4.2 用tushare获取行情数据

先装好库:

pip install tushare akshare pandas numpy

tushare需要token,去官网注册就能拿到。我个人习惯把token存在环境变量里,而不是硬编码在代码中。

import tushare as ts
import pandas as pd

# 初始化
pro = ts.pro_api('你的token')

# 获取日线数据
df = pro.daily(
    ts_code='000001.SZ',
    start_date='20230101',
    end_date='20231231',
    fields='ts_code,trade_date,open,high,low,close,vol'
)

print(df.head())

这里有个细节:fields参数可以指定字段,别一股脑全拉回来。我刚开始做的时候把几十个字段全要了,结果大部分用不上,还拖慢速度。

小技巧:tushare的daily接口默认返回未复权数据。做统计套利时,建议用adj_factor接口获取复权因子,自己算后复权。

4.3 用akshare获取数据

akshare更直接,不用token,但接口名有点怪。我经常记不住,所以写了个小封装:

import akshare as ak

# 获取A股日线
df_ak = ak.stock_zh_a_hist(
    symbol="000001",
    period="daily",
    start_date="20230101",
    end_date="20231231",
    adjust="qfq"  # 前复权
)

print(df_ak.head())

注意akshare返回的列名是中文,比如"日期"、"开盘"、"收盘"。做数据处理前最好统一转成英文,不然容易乱。我吃过这个亏——某次回测脚本里用了中文列名,换了个环境就报错。

对比项 tushare akshare
认证方式 Token 无需认证
数据质量 高,字段规范 中等,偶有异常
调用限制 积分制,免费版200次/分钟 无限制,但源网站可能反爬
复权数据 需手动计算 直接支持前/后复权
适用场景 严谨回测、实盘 快速验证、原型开发

4.4 数据清洗:处理缺失值和异常值

数据拿到手,别急着用。先看看有没有坑。我一般按这个流程走:

  1. 检查缺失值——停牌、节假日、数据源问题都会导致NaN
  2. 检查异常值——比如某天涨幅1000%,明显是数据错误
  3. 检查重复值——同一个交易日出现两条数据
  4. 检查时间序列连续性——有没有跳空的日子

4.4.1 缺失值处理

# 检查缺失
print(df.isnull().sum())

# 处理方式1:向前填充(适合停牌)
df['close'].fillna(method='ffill', inplace=True)

# 处理方式2:删除(适合少量缺失)
df.dropna(subset=['close'], inplace=True)

# 处理方式3:插值(适合短期缺失)
df['close'].interpolate(method='linear', inplace=True)

我个人习惯:停牌用前向填充,数据源问题用删除,短期缺失用插值。但要注意,插值会引入人为数据,做统计套利时要谨慎。我曾经用插值补了三天数据,结果那三天的协整关系全是假的。

避坑指南:千万不要用均值填充金融时间序列!股票价格有趋势性,均值填充会破坏自相关结构。我曾经见过有人这么干,回测收益翻倍,实盘亏成狗。

4.4.2 异常值检测

异常值怎么找?我常用两种方法:

  • 3σ原则:超过均值±3倍标准差的数据视为异常
  • IQR方法:低于Q1-1.5*IQR或高于Q3+1.5*IQR的数据视为异常
# IQR方法示例
Q1 = df['close'].quantile(0.25)
Q3 = df['close'].quantile(0.75)
IQR = Q3 - Q1

lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 标记异常
df['is_outlier'] = (df['close'] < lower_bound) | (df['close'] > upper_bound)

# 查看异常数据
print(df[df['is_outlier']])

但要注意,金融数据本身就有厚尾特征,很多看似异常的值其实是真实波动。我一般会结合业务逻辑判断——比如某只股票突然涨了20%,如果是财报发布日,那可能是真的;如果是普通交易日,大概率是数据错误。

4.5 数据重采样与对齐

统计套利经常需要处理不同频率的数据。比如,你拿到的股票数据是日线,但指数数据是5分钟线。这时候就需要重采样和对齐。

4.5.1 重采样

把高频数据转成低频,或者反过来。我常用的是resample方法:

# 假设有5分钟数据,转成日线
df_5min = pd.read_csv('5min_data.csv', parse_dates=['time'])
df_5min.set_index('time', inplace=True)

# 重采样为日线
df_daily = df_5min.resample('D').agg({
    'open': 'first',
    'high': 'max',
    'low': 'min',
    'close': 'last',
    'volume': 'sum'
})

这里有个坑:重采样时一定要指定聚合函数。如果不指定,pandas会报错或者用默认的mean,那开盘价就变成了一天中所有开盘价的均值,完全不对。

4.5.2 数据对齐

多只股票做配对交易时,必须保证时间戳对齐。我一般用mergejoin

# 假设有两只股票的数据
df_a = pd.read_csv('stock_a.csv', parse_dates=['date'])
df_b = pd.read_csv('stock_b.csv', parse_dates=['date'])

# 内连接:只保留共同交易日
df_aligned = pd.merge(
    df_a[['date', 'close']],
    df_b[['date', 'close']],
    on='date',
    how='inner',
    suffixes=('_a', '_b')
)

print(f"对齐后数据量: {len(df_aligned)}")

为什么要用内连接?因为如果某只股票停牌,另一只正常交易,那天的价差数据就是假的。我刚开始做配对交易时用了外连接,结果回测里出现了大量"完美套利机会",实盘根本不存在。

核心要点:数据对齐时,宁可少数据,不要假数据。缺失的交易日直接剔除,比用填充数据更安全。

4.6 本章知识体系

下面这张图总结了数据获取与清洗的核心流程。我画的时候特意把"清洗"环节放大了——因为在实际项目中,80%的时间都花在这上面。

数据获取与清洗核心流程 数据源选择 tushare / akshare 数据获取 日线 / 分钟线 / 复权 数据清洗(核心环节) 缺失值 → 异常值 → 重复值 前向填充 / 删除 / 插值 重采样与对齐 高频→低频 / 多股票时间戳对齐 / 内连接 vs 外连接 清洗后的数据 可用于统计套利策略分析 注意: 清洗环节占 80%工作量 关键原则: 宁可少数据 不要假数据

4.7 实战小贴士

最后分享几个我踩过的坑:

  • 数据缓存:每次跑策略都重新拉数据,既慢又浪费积分。我习惯把原始数据存成parquet格式,读取快,压缩率高。
  • 版本管理:数据文件加上日期后缀,比如stock_000001_20230101_20231231.parquet。这样回测结果可复现。
  • 数据校验:清洗完后,随机抽几天和行情软件对比一下。我吃过一次亏——某次复权因子算错了,整个回测白跑。
我的习惯:每次拿到新数据,先画个收盘价曲线图。肉眼扫一遍,比任何统计检验都管用。曲线突然断崖或者跳空,一眼就能看出来。

数据这块就聊到这儿。记住一句话:垃圾进,垃圾出。数据质量决定了策略的天花板,别在这上面省功夫。

专注资料整理