2、数据获取基础:使用Tushare/AkShare获取A股日线行情数据、数据清洗与预处理
做量化交易,第一步就是搞定数据。没有数据,再牛的策略也是空中楼阁。
我个人习惯把数据获取比作「做饭前的买菜」。菜不新鲜,或者买错了,后面炒菜再厉害也白搭。今天我们就聊聊怎么用 Python 把 A 股的日线行情数据「买」回来,再「洗」干净。
2.1 两大主流数据源:Tushare vs AkShare
国内做量化,绕不开这两个库。我当年刚入行时,数据源还靠手动下载 Excel,现在想想真是原始人。
| 对比项 | Tushare | AkShare |
|---|---|---|
| 数据丰富度 | 非常全面,含财务、因子等 | 覆盖广,包含另类数据 |
| 使用门槛 | 需注册获取 token,部分接口收费 | 开源免费,pip install 即用 |
| 数据质量 | 较高,有专业团队维护 | 依赖爬虫,偶有异常值 |
| 适合场景 | 专业研究、实盘策略 | 快速原型、学习练手 |
说白了,如果你只是自己研究玩玩,AkShare 完全够用。但如果是做产品或者跑实盘,我建议用 Tushare Pro,数据更稳。
我的小建议:两个库可以搭配使用。Tushare 拿核心数据,AkShare 做补充验证。我在项目中就经常这样干,万一一个接口挂了,另一个还能顶上。
2.2 实战:用 Tushare 获取日线数据
先装库:pip install tushare。然后去官网注册,拿到你的 token。
import tushare as ts
# 初始化(token 换成你自己的)
pro = ts.pro_api('你的token')
# 获取平安银行 2024年1月 日线数据
df = pro.daily(
ts_code='000001.SZ',
start_date='20240101',
end_date='20240131'
)
print(df.head())
输出长这样:
ts_code trade_date open high low close pre_close change pct_chg vol amount
0 000001.SZ 20240131 9.50 9.55 9.30 9.35 9.48 -0.13 -1.37 123456 1.17e+09
1 000001.SZ 20240130 9.60 9.65 9.45 9.48 9.58 -0.10 -1.04 98765 9.38e+08
嗯,这里要注意:Tushare 返回的字段名是英文的,vol 是成交量(手),amount 是成交额(元)。我刚开始做回测时,就搞混过单位,结果算出来的仓位全错了。
2.3 实战:用 AkShare 获取日线数据
AkShare 更简单,不用注册,直接装库就能用。
import akshare as ak
# 获取平安银行日线数据
df = ak.stock_zh_a_hist(
symbol="000001",
period="daily",
start_date="20240101",
end_date="20240131",
adjust="qfq" # 前复权
)
print(df.head())
输出字段是中文的,看着更亲切:
日期 开盘 收盘 最高 最低 成交量 成交额 振幅 涨跌幅 涨跌额 换手率
0 2024-01-31 9.50 9.35 9.55 9.30 123456 1.17e+09 2.64 -1.37 -0.13 0.85
核心区别:Tushare 返回的是原始数据,需要你自己处理复权。AkShare 默认返回前复权数据,对回测更友好。我个人建议做策略回测时用前复权,做实时交易用后复权。
2.4 数据清洗:把脏数据洗干净
数据拿到手,别急着用。你想想看,网络波动、停牌、除权除息……各种情况都会导致数据异常。我曾经有一次回测跑出来年化 200%,兴奋得不行,结果发现是数据里混入了空值,算收益率时全乱了。
清洗步骤一般分三步:
- 处理缺失值——停牌日的数据通常是 NaN
- 处理异常值——比如某天涨幅超过 100% 这种明显错误
- 统一格式——日期转 datetime,数值转 float
import pandas as pd
# 假设 df 是从 Tushare 拿到的原始数据
df = df.sort_values('trade_date') # 按日期排序
# 1. 检查缺失值
print(df.isnull().sum())
# 2. 填充或删除缺失值
# 停牌日:用前一天的收盘价填充
df['close'].fillna(method='ffill', inplace=True)
# 3. 处理异常值:涨幅超过 ±10% 的标记为异常
df['pct_chg'] = df['pct_chg'].astype(float)
df.loc[df['pct_chg'].abs() > 10, 'pct_chg'] = None
# 4. 日期统一
df['trade_date'] = pd.to_datetime(df['trade_date'])
print(df.info())
避坑指南:我曾经遇到过某只股票连续停牌一个月,复牌后直接跌停。如果用前向填充,那一个月的数据全是同一个价格,回测里看起来风平浪静,实盘直接爆仓。所以停牌超过 5 天的,我建议直接删除那段时间的数据。
2.5 数据预处理:为策略分析做准备
数据洗干净了,接下来就是「加工」环节。说白了,就是把原始数据变成能直接喂给策略的格式。
常用的预处理操作:
- 计算收益率:
df['return'] = df['close'].pct_change() - 计算移动平均线:
df['ma5'] = df['close'].rolling(5).mean() - 计算成交量变化率:
df['vol_ratio'] = df['vol'] / df['vol'].shift(1) - 标记主力资金流向:结合大单数据(这个后面章节会细讲)
# 完整预处理示例
def preprocess_stock_data(df):
"""数据预处理函数"""
# 排序
df = df.sort_values('trade_date').reset_index(drop=True)
# 计算收益率
df['daily_return'] = df['close'].pct_change()
# 计算均线
df['ma5'] = df['close'].rolling(5).mean()
df['ma20'] = df['close'].rolling(20).mean()
# 计算成交量均线
df['vol_ma5'] = df['vol'].rolling(5).mean()
# 标记放量(成交量超过5日均量2倍)
df['volume_surge'] = (df['vol'] > df['vol_ma5'] * 2).astype(int)
return df
df_clean = preprocess_stock_data(df)
print(df_clean[['trade_date', 'close', 'daily_return', 'volume_surge']].tail())
2.6 本章知识体系总览
下面这张图,是我自己总结的数据获取与处理流程。每次做新项目,我都会先过一遍这个框架。
我的经验:数据清洗这一步,往往比写策略还花时间。我一般会写一个通用的清洗函数,把停牌处理、异常值过滤、复权计算都封装好。这样每次拿到新数据,跑一遍函数就行,省心。
好了,数据基础就聊到这儿。记住一句话:垃圾数据进,垃圾策略出。把数据搞扎实了,后面的分析才能站得住脚。
公众号:蓝海资料掘金营,微信deep3321