金融数据获取:使用yfinance、Tushare、AkShare等库获取股票历史行情数据,处理复权、缺失值

量化分析的第一步永远是数据。无论你的策略逻辑多么精妙、回测框架多么高效,如果底层行情数据存在复权错误、缺失值未处理或字段口径不一致,最终的回测结果都将失真,甚至得出完全相反的结论。本章将聚焦于Python生态中最常用的三个金融数据库——yfinance、Tushare和AkShare,深入讲解如何获取股票历史行情数据,并重点解决复权因子计算与缺失值处理这两个核心工程问题。我们将从数据源特性对比、API调用规范、数据清洗流程到实战案例拆解,构建一套完整、可复用的数据获取与预处理流水线。

金融数据获取与预处理工程链路 数据源层 yfinance (Yahoo) Tushare Pro AkShare (公开源) 获取与标准化层 参数配置 (日期/代码) 字段统一 (OHLCV) 时区与索引处理 核心处理层 复权因子计算 缺失值识别与填充 异常值检测 输出层 DataFrame (标准格式) 存储至CSV/Parquet/DB 质量保障与校验 · 交易日历对齐 · 复权因子单调性检查 · 数据完整性报告 · 断点重连与重试机制 核心目标:构建一个可靠、可复现、口径一致的历史行情数据管道 复权处理不当 = 策略信号失真 | 缺失值未处理 = 回测结果偏差

核心原理:三大数据源与复权机制的本质

在开始编写代码之前,理解数据源的本质差异和复权机制的原理至关重要。yfinance、Tushare和AkShare虽然都能返回OHLCV(开盘、最高、最低、收盘、成交量)数据,但它们的底层数据来源、更新频率、字段定义和复权处理方式存在显著差异。

yfinance 非官方地抓取Yahoo Finance的数据,无需注册,适合快速原型验证和海外市场数据获取。其返回的DataFrame索引为DatetimeIndex,包含Adj Close列(前复权收盘价)。但Yahoo的复权因子计算逻辑不透明,且在中国大陆网络环境下访问不稳定。

Tushare Pro 是国内最专业的量化数据平台之一,需要注册并获取,积分制访问不同权限的数据。其pro_bar接口支持复权因子(qfq、hfq)的直接计算,数据质量高,字段规范,但积分门槛限制了高频或全量数据的获取。

AkShare 是一个开源爬虫库,聚合了东方财富、新浪财经等公开数据源。接口丰富、免费无限制,但数据格式因源而异,需要较多的清洗工作,且接口变动频繁。

复权机制的核心在于处理上市公司分红、送股、配股等事件对股价造成的非交易性跳空。前复权(qfq)以当前价格为基准,调整历史价格,保证价格连续性,适合技术分析;后复权(hfq)以上市首日价格为基准,适合计算真实收益率。不复权(raw)数据则保留原始价格,但会因除权除息产生价格缺口,直接用于回测会产生虚假的收益信号。

数据源认证方式复权支持数据质量适用场景
yfinance无需Key仅前复权(Adj Close)中等,偶有缺失海外市场、快速验证
Tushare Pro+积分qfq/hfq/raw高,字段规范国内A股、专业回测
AkShare无需Key需自行计算中等,格式多样免费爬取、多源对比

操作流程:从API调用到数据清洗的标准流水线

构建一个健壮的数据获取流程,需要遵循“配置-获取-校验-清洗-存储”的五步方法论。以下以获取贵州茅台(600519.SH)近一年的日线数据为例,展示三种库的标准调用方式。

# 1. yfinance 调用示例
import yfinance as yf
df_yf = yf.download("600519.SS", start="2023-01-01", end="2024-01-01", auto_adjust=True)
# auto_adjust=True 自动返回前复权数据,但会丢失原始OHLC

# 2. Tushare Pro 调用示例
import tushare as ts
ts.set_('你的')
pro = ts.pro_api()
df_ts = pro.daily(ts_code='600519.SH', start_date='20230101', end_date='20240101')
# 获取复权因子
adj_factor = pro.adj_factor(ts_code='600519.SH', start_date='20230101', end_date='20240101')
# 合并后自行计算前复权价格:qfq_close = close * (adj_factor / latest_adj_factor)

# 3. AkShare 调用示例
import akshare as ak
df_ak = ak.stock_zh_a_hist(symbol="600519", period="daily", start_date="20230101", end_date="20240101", adjust="qfq")
# adjust参数支持qfq/hfq/"",但返回的列名为中文

获取数据后,必须进行统一的格式标准化。首先将日期列转换为统一的DatetimeIndex,并按照时间升序排序。其次,统一列名为小写英文(open, high, low, close, volume)。最后,检查索引的连续性——A股市场有法定节假日和周末休市,需要与交易日历对齐,识别出因停牌或数据缺失导致的空值。

关键操作:复权因子的正确应用

Tushare的adj_factor接口返回的是累积复权因子。计算前复权价格时,不能简单地将所有历史价格乘以同一个因子,而应使用factor / factor_latest的比例。例如,某股票当前复权因子为10,一年前为8,则一年前的价格应乘以8/10=0.8。后复权则乘以factor / factor_first。yfinance的auto_adjust虽然方便,但无法获取原始价格,对于需要同时使用复权和未复权数据的策略(如计算股息率)存在局限。

案例拆解:构建一个完整的A股数据管道

假设我们需要为沪深300成分股构建一个日线级别的回测数据库,要求包含前复权价格、成交量,并处理停牌导致的缺失值。我们选择Tushare Pro作为主数据源,因为其数据质量最稳定。

背景与约束: 本地服务器定时任务每日18:00运行,需要增量更新数据。网络带宽有限,单次请求限制5000行。策略回测需要至少3年的历史数据。

初始现象与目标: 直接使用pro.daily()获取的数据存在两个问题:一是停牌日数据缺失,导致DataFrame行数少于实际交易日;二是未复权价格在除权日出现跳空,直接计算收益率会产生虚假的负收益。

分析判断过程: 我们决定采用“先获取不复权数据+复权因子,再自行计算前复权价格”的策略。这样既保留了原始价格信息,又能灵活切换复权方式。对于缺失值,我们使用交易日历(pro.trade_cal())生成完整的日期序列,然后对停牌日进行标记。

实际操作步骤:

  1. 获取交易日历,生成2021-2024年的完整交易日列表。
  2. 循环获取每只股票的daily数据和adj_factor数据,合并后计算前复权价格。
  3. 使用df.reindex(full_trade_days)将数据对齐到完整交易日,缺失的OHLC填充为NaN,volume填充为0。
  4. 对于停牌超过5个交易日的股票,在数据库中标记is_suspended=True,回测时跳过这些时段。
  5. 将清洗后的数据追加写入Parquet文件,按股票代码分区存储。

结果对比与复盘: 处理前,直接使用原始数据回测一个简单的均线策略,年化收益率为-15%(因除权跳空导致虚假卖出信号)。处理后,同一策略的年化收益率为+8.5%,与Wind终端的数据核对一致。关键经验是:复权因子必须与价格数据同步更新,如果某日公司进行了大比例分红,而我们的因子表未更新,会导致后续所有价格计算错误。

风险提示: 不要盲目信任API返回的“复权”数据。yfinance的auto_adjust在遇到拆股时会自动调整,但遇到分红时调整逻辑不透明。AkShare的adjust参数在不同接口间行为不一致。最稳妥的方式是获取原始价格+复权因子,自行计算。

常见误区与总结复盘

误区一:忽略复权因子的时效性。 复权因子是随时间变化的。今天获取的前复权数据,在明天公司分红后,历史价格会整体变化。因此,回测数据必须一次性生成并固化,不能每次回测时实时获取,否则结果不可复现。

误区二:将所有缺失值都填充为前值。 停牌和缺失是两回事。停牌期间不应有交易,填充前值会引入未来信息(look-ahead bias)。对于停牌,应保留NaN并标记;对于日内短暂缺失(如数据源返回空值),可以使用前值填充,但需在日志中记录。

误区三:忽视成交量与价格的匹配。 在除权日,成交量也会进行相应调整(如送股后成交量放大)。如果只复权价格不复权成交量,会导致量价关系失真。Tushare的daily接口返回的vol是手数,在复权时无需调整,但需注意单位一致性。

误区四:数据源切换导致的口径不一致。 不同数据源的OHLC定义可能不同(如是否包含集合竞价)。在构建多源备份时,必须定义统一的数据字典,并在写入数据库前进行字段映射和校验。

经验总结: 一个生产级的数据管道应包含三层校验:第一层是完整性校验(行数是否匹配交易日历);第二层是逻辑校验(high >= max(open, close),low <= min(open, close));第三层是统计校验(收益率分布是否在合理范围内,如单日涨跌幅不超过20%)。建议将数据获取与策略回测解耦,数据管道独立运行并输出质量报告。