第三章:金融数据获取——用yfinance、akshare、Tushare搞定股票、ETF与指数历史数据
做量化投资,第一步就是搞数据。没有数据,再牛的策略也是空中楼阁。
我个人习惯把数据获取比作「做饭前的买菜」。菜买不好,厨艺再好也白搭。今天咱们就聊聊怎么用Python把A股、港股、美股的股票、ETF和指数历史数据给「买」回来。
3.1 三大数据源,各有什么本事?
市面上数据源很多,但我重点推荐三个:yfinance、akshare、Tushare。它们各有侧重,我一般搭配着用。
| 数据源 | 覆盖范围 | 是否需要注册 | 数据质量 | 我的使用场景 |
|---|---|---|---|---|
| yfinance | 美股、全球ETF | 否 | 中等,偶尔有缺失 | 快速验证美股策略 |
| akshare | A股、港股、期货、基金 | 否 | 较好,接口丰富 | 日常A股数据采集 |
| Tushare | A股、指数、财务数据 | 是(需Token) | 优秀,字段完整 | 正式回测、生产环境 |
我的小建议:刚开始学的时候,先用yfinance和akshare,零门槛。等你要做严肃回测了,再上Tushare。别一上来就注册一堆账号,容易劝退。
3.2 yfinance:三行代码拿下美股数据
yfinance是我用过最「无脑」的库。你想想看,连注册都不用,直接pip安装就能用。
import yfinance as yf
# 下载苹果公司近1年日线数据
aapl = yf.download('AAPL', start='2024-01-01', end='2025-01-01')
print(aapl.head())
就这么简单。但这里有个坑——数据频率。yfinance默认返回的是日线,如果你想拿分钟线,得加参数。
# 获取5分钟线数据
aapl_5min = yf.download('AAPL', period='5d', interval='5m')
我曾经踩过的坑:yfinance对A股代码支持很差。比如你想拿「贵州茅台」,直接写'600519.SS'有时候能行,但经常返回空数据。所以,我一般只用它拿美股和全球ETF。
ETF怎么拿?跟股票一样,直接写代码就行。
# 标普500 ETF
spy = yf.download('SPY', start='2024-01-01', end='2025-01-01')
# 纳斯达克100 ETF
qqq = yf.download('QQQ', start='2024-01-01', end='2025-01-01')
3.3 akshare:A股数据的一站式解决方案
做A股量化,akshare是我的首选。它把东方财富、新浪财经等网站的数据接口都封装好了,用起来很顺手。
import akshare as ak
# 获取贵州茅台历史数据
stock_600519_df = ak.stock_zh_a_hist(symbol="600519", period="daily",
start_date="20240101", end_date="20250101",
adjust="qfq")
print(stock_600519_df.head())
注意看参数里的 adjust="qfq",这是前复权。做回测时一定要用复权数据,否则分红送股会把你搞晕。
ETF数据怎么拿?akshare也支持。
# 获取沪深300 ETF(510300)数据
etf_510300_df = ak.fund_etf_hist_em(symbol="510300", period="daily",
start_date="20240101", end_date="20250101",
adjust="qfq")
核心要点:akshare的接口名经常变。我去年写的一个脚本,今年跑就报错了。解决方案是——每次用之前,先打印一下
ak.__doc__ 看看最新接口。
3.4 Tushare:专业级数据,但需要一点耐心
Tushare的数据质量是最好的,但门槛也最高。你得先注册、申请Token,而且有些接口还有积分限制。
import tushare as ts
# 设置Token(第一次使用需要)
ts.set_token('你的token')
# 初始化接口
pro = ts.pro_api()
# 获取贵州茅台日线数据
df = pro.daily(ts_code='600519.SH', start_date='20240101', end_date='20250101')
print(df.head())
Tushare返回的数据格式很规范,字段名都是英文的,比如 trade_date、open、high、low、close、vol。做回测时,我一般用Tushare的数据做最终验证。
指数数据怎么拿?
# 获取沪深300指数数据
index_df = pro.index_daily(ts_code='000300.SH', start_date='20240101', end_date='20250101')
我的经验:Tushare的积分制度有点烦人。基础积分只能调200次/分钟,高频策略根本不够用。我的做法是——用akshare做日常探索,用Tushare做最终回测。
3.5 数据获取的核心逻辑:一张图说清楚
说了这么多,咱们用一张SVG图把整个数据获取的流程串起来。这样你脑子里就有个清晰的框架了。
3.6 实战:构建一个统一的数据获取函数
在实际项目中,我不会每次都写一堆重复代码。我习惯封装一个函数,根据参数自动选择数据源。
def get_history_data(symbol, source='akshare', start='20240101', end='20250101'):
"""
统一数据获取接口
:param symbol: 股票代码
:param source: 数据源('yfinance', 'akshare', 'tushare')
:param start: 开始日期
:param end: 结束日期
:return: DataFrame
"""
if source == 'yfinance':
import yfinance as yf
data = yf.download(symbol, start=start, end=end)
data.columns = ['open', 'high', 'low', 'close', 'adj_close', 'volume']
return data
elif source == 'akshare':
import akshare as ak
data = ak.stock_zh_a_hist(symbol=symbol, period='daily',
start_date=start, end_date=end, adjust='qfq')
data.rename(columns={
'开盘': 'open', '最高': 'high', '最低': 'low',
'收盘': 'close', '成交量': 'volume'
}, inplace=True)
return data[['open', 'high', 'low', 'close', 'volume']]
elif source == 'tushare':
import tushare as ts
pro = ts.pro_api()
data = pro.daily(ts_code=symbol, start_date=start, end_date=end)
data.rename(columns={
'open': 'open', 'high': 'high', 'low': 'low',
'close': 'close', 'vol': 'volume'
}, inplace=True)
return data[['trade_date', 'open', 'high', 'low', 'close', 'volume']]
else:
raise ValueError("不支持的数据源,请选择 yfinance / akshare / tushare")
# 使用示例
df_600519 = get_history_data('600519', source='akshare', start='20240101', end='20250101')
print(df_600519.head())
为什么这么封装?因为在实际回测中,你可能会换数据源。比如一开始用akshare做原型,后来发现数据有缺失,换成Tushare。如果代码写死了,改起来很痛苦。封装一层,换个参数就行。
3.7 避坑指南:我踩过的那些坑
做数据获取这么多年,我总结了几条血泪教训:
- 数据对齐问题:不同数据源的日期格式不一样。yfinance是datetime,akshare是字符串,Tushare是int。一定要统一成datetime格式再合并。
- 复权问题:做回测必须用复权数据。我见过有人用不复权数据做回测,结果策略收益虚高,实盘直接亏哭。
- 网络超时:数据获取时网络可能中断。我习惯加个重试机制,最多重试3次。
- 数据缓存:别每次都重新下载。把数据存到本地文件,下次直接读取,能省不少时间。
我曾经犯过的错:有一次我用yfinance拿港股数据,代码写的是'0700.HK',结果返回的数据全是NaN。后来才发现,yfinance对港股的支持很差,得用akshare或者直接去港交所官网拿。从那以后,我拿港股只用akshare。
好了,数据获取这块就聊到这儿。记住一个原则:数据质量决定回测质量。别嫌麻烦,多花点时间把数据搞干净,后面做策略会省心很多。