第三章:金融数据获取——用Tushare/Akshare搞定A股数据
数据是量化模型的血液,这话一点不夸张。我见过太多人把精力全花在策略设计上,结果数据源一塌糊涂,回测跑出来全是幻觉。今天咱们就聊聊怎么用Python把A股的日线、指数、行业板块数据稳稳拿到手。
3.1 数据源选哪个?Tushare vs Akshare
先说说这两个库的区别。Tushare是老牌选手,数据质量高,但需要注册获取token,部分接口有积分限制。Akshare是后起之秀,完全免费,接口更丰富,但偶尔会有数据延迟。
我个人习惯是:生产环境用Tushare,研究探索用Akshare。为什么?因为Tushare的数据经过清洗,字段规范,适合直接喂给模型。Akshare胜在方便,不用注册就能用,适合快速验证想法。
核心结论:
- Tushare:稳定、规范、有积分门槛
- Akshare:免费、灵活、偶尔抽风
- 建议两个都装,互为备份
3.2 安装与初始化
先装库,这个没什么好说的。但要注意版本,我遇到过因为版本太旧导致接口报错的情况。
# 安装
pip install tushare akshare pandas
# Tushare初始化
import tushare as ts
ts.set_token('你的token') # 去tushare.pro注册获取
pro = ts.pro_api()
# Akshare直接导入就行
import akshare as ak
小提示:Token建议写在配置文件里,别硬编码。我曾经把token直接写在代码里上传到GitHub,结果被全网爬了一遍……
3.3 获取A股日线数据
日线数据是轮动模型的基础。说白了,就是每天的开高低收、成交量这些。咱们先看Tushare怎么拿。
# Tushare获取日线
df = pro.daily(
ts_code='000001.SZ', # 平安银行
start_date='20240101',
end_date='20240301'
)
print(df.head())
这里有个坑:ts_code的格式是代码.交易所,SZ是深交所,SH是上交所。我刚开始做的时候老搞混,后来写了个映射表才解决。
再看看Akshare的写法,更直接一些:
# Akshare获取日线
df = ak.stock_zh_a_hist(
symbol="000001",
period="daily",
start_date="20240101",
end_date="20240301",
adjust="qfq" # 前复权
)
print(df.head())
注意:Akshare默认返回的是未复权数据。做量化一定要用复权数据,否则分红送股会把你搞晕。我见过有人用未复权数据跑回测,结果策略收益虚高30%。
3.4 获取指数数据
指数数据用于判断市场整体走势。轮动模型里,我们经常用沪深300、中证500、创业板指这些。
Tushare获取指数日线:
# 沪深300指数
df_index = pro.index_daily(
ts_code='000300.SH',
start_date='20240101',
end_date='20240301'
)
Akshare获取指数数据:
# 上证指数
df_index = ak.stock_zh_index_daily(
symbol="sh000001"
)
嗯,这里要注意:指数代码和个股代码的规则不一样。Tushare里指数代码后面加.SH或.SZ,Akshare里则是sh、sz前缀。你想想看,如果代码写错了,拿到的数据就是错的,模型再厉害也没用。
3.5 获取行业板块数据
行业板块数据是轮动模型的核心输入。我们得知道每个行业今天涨了多少,资金流向哪里。
Tushare提供了行业分类和板块行情:
# 获取行业分类
df_industry = pro.industry_classified(
src='sw' # 申万行业分类
)
# 获取行业板块日线
df_sector = pro.sector_daily(
ts_code='801010.SI', # 申万一级行业代码
start_date='20240101',
end_date='20240301'
)
Akshare的行业板块数据更丰富:
# 获取申万行业板块行情
df_sector = ak.stock_board_industry_hist(
symbol="半导体",
start_date="20240101",
end_date="20240301"
)
# 获取概念板块
df_concept = ak.stock_board_concept_hist(
symbol="人工智能",
start_date="20240101",
end_date="20240301"
)
避坑指南:我曾经用Akshare获取行业数据时,发现某些板块在特定日期返回空值。后来排查发现是接口数据更新延迟。建议做数据校验:如果某天数据为空,用前一天的数据填充,或者直接跳过。
3.6 数据存储与缓存
每次跑策略都去拉数据,效率太低了。我建议把数据存到本地,用的时候直接读。
import os
import pandas as pd
def save_data(df, filename):
"""保存数据到本地"""
path = f'./data/{filename}'
os.makedirs(os.path.dirname(path), exist_ok=True)
df.to_parquet(path) # parquet格式比csv快10倍
def load_data(filename):
"""从本地加载数据"""
path = f'./data/{filename}'
if os.path.exists(path):
return pd.read_parquet(path)
return None
为什么用parquet?因为量化数据动辄几百万行,csv读写太慢。我试过用csv存3年的全A股日线数据,加载要30秒,换成parquet只要2秒。
3.7 数据质量检查
数据拿到手,别急着用。先做一轮质量检查,这是血的教训换来的经验。
def check_data_quality(df):
"""数据质量检查"""
issues = []
# 检查缺失值
if df.isnull().sum().sum() > 0:
issues.append(f"存在{df.isnull().sum().sum()}个缺失值")
# 检查重复日期
if df['trade_date'].duplicated().any():
issues.append("存在重复日期")
# 检查价格异常
if (df['close'] <= 0).any():
issues.append("存在非正价格")
# 检查涨跌幅异常
if (df['pct_chg'].abs() > 20).any():
issues.append("存在涨跌幅超过20%的异常数据")
return issues
我曾经遇到过某只股票连续5天数据完全一样,明显是接口返回了缓存数据。如果不做检查,模型就会学到「这只股票不会波动」的错误规律。
3.8 知识体系总览
下面这张图概括了本章的核心逻辑:从数据源到存储,再到质量检查的完整流程。
3.9 实战:一键获取全量数据
最后,我分享一个自己常用的函数,把日线、指数、板块数据一次性拉下来:
def get_all_data(start_date, end_date):
"""一键获取轮动模型所需全部数据"""
data = {}
# 1. 获取沪深300成分股日线
hs300 = pro.index_weight(ts_code='000300.SH')
for code in hs300['con_code'].head(50): # 先取前50只
df = pro.daily(ts_code=code, start_date=start_date, end_date=end_date)
data[f'stock_{code}'] = df
# 2. 获取主要指数
indices = ['000300.SH', '000905.SH', '399006.SZ']
for idx in indices:
data[f'index_{idx}'] = pro.index_daily(ts_code=idx, start_date=start_date, end_date=end_date)
# 3. 获取申万一级行业
sectors = pro.industry_classified(src='sw')
for sector in sectors['industry_code'].unique()[:10]:
data[f'sector_{sector}'] = pro.sector_daily(ts_code=sector, start_date=start_date, end_date=end_date)
return data
这个函数我用了快两年,基本没出过问题。唯一要注意的是,Tushare有调用频率限制,如果数据量大,记得加个time.sleep()。
本章核心要点:
- Tushare和Akshare各有优劣,建议双持
- 日线、指数、板块数据是轮动模型的三大支柱
- 数据质量比策略本身更重要
- 本地缓存能大幅提升效率