A股复权行情实战指南:Tushare pro_bar 前复权/后复权数据获取与量化回测应用
【免费下载链接】Vibe-Trading"Vibe-Trading: Your Personal Trading Agent"项目地址: https://gitcode.com/GitHub_Trending/vi/Vibe-Trading
Vibe-Trading 的数据技能库(agent/src/skills/tushare/SKILL.md)为 AI Agent 封装了完整的 Tushare 财经数据接口,其中 A 股复权行情是量化研究与回测最核心的行情数据之一。本文以 复权行情.md 为骨架,完整讲解ts.pro_bar()的复权算法、参数语义与调用示例,并结合仓库中 cn_adjust.py 与 tushare.py 的源码实现,说明前复权逻辑在真实回测流水线中的落地方式,帮助读者在 Agent 对话、量化建模与回测引擎中正确使用复权行情,避免"除权日机械缺口"污染收益率计算。
一、复权行情接口概览
复权行情通过 Tushare Pro 的通用行情接口pro_bar实现,属于集成开发接口:它并不直接返回现成的复权价格,而是在 SDK 层利用 复权因子接口(adj_factor) 提供的每日复权因子进行动态计算,因此:
- HTTP 方式无法调取:由于复权逻辑在 SDK 层完成,只能通过 Python SDK 调用;
- Python SDK 版本要求:
tushare >= 1.2.26; - 若需要静态复权行情(支持 HTTP 调用),可改用 股票技术面因子(专业版)接口.md),其输出参数中的
_qfq/_hfq即为已算好的前/后复权因子行情。
在 通用行情接口 的文档中,pro_bar被描述为"目前整合了股票(未复权、前复权、后复权)、指数、数字货币、ETF 基金、期货、期权的行情数据",其中复权类型只针对股票生效。
二、三种复权类型与算法
A 股因分红、送股、配股等公司行为(Corporate Action)会产生除权除息,导致除权日前后价格出现非市场化的"机械缺口"。为消除该缺口,需要将历史价格折算到统一的股本/价格基准上。pro_bar的adj参数支持三种模式:
| 类型 | 算法 | 参数标识 |
|---|---|---|
| 不复权 | 无 | 空或None |
| 前复权 | 当日收盘价 × 当日复权因子 / 最新复权因子 | qfq |
| 后复权 | 当日收盘价 × 当日复权因子 | hfq |
前复权(qfq)以"当前"为基准将历史价格向当前价格靠拢,使最近价格保持实际成交价,历史价格相应缩小,适合日常行情观察与回测;后复权(hfq)以历史最早点为基准持续累乘因子,价格曲线单调递增,能真实反映长期持有收益(含分红再投资),适合计算长期累计收益率。
仓库中 cn_adjust.py 的apply_qfq()正是前复权公式的等价实现:
ratio = series / series.iloc[-1] # 当日复权因子 / 最新复权因子 out[col] = out[col] * ratio # 当日价格 × ratio其ratio = series / series.iloc[-1]对应文档中的"当日复权因子 / 最新复权因子",四类价格列open/high/low/close全部乘以该比例,与qfq算法完全一致。同时该模块还额外处理了volume:成交量除以同一比例,使股本口径统一、由amount推算的 VWAP 与close的关系保持不变,而amount是现金额,保持原值不动。
三、接口参数详解
pro_bar的核心输入参数如下:
| 名称 | 类型 | 必选 | 描述 |
|---|---|---|---|
| ts_code | str | Y | 证券代码 |
| start_date | str | N | 开始日期(格式:YYYYMMDD) |
| end_date | str | N | 结束日期(格式:YYYYMMDD) |
| asset | str | Y | 资产类别:E 股票、I 沪深指数、C 数字货币、FT 期货、FD 基金、O 期权,默认 E |
| adj | str | N | 复权类型(只针对股票):None 未复权、qfq 前复权、hfq 后复权,默认 None |
| freq | str | Y | 数据频度:1MIN 表示 1 分钟(1/5/15/30/60 分钟)、D 日线,默认 D |
| ma | list | N | 均线,支持任意周期的均价和均量,输入任意合理 int 数值 |
几个关键语义:
adj仅对股票(asset='E')生效;指数、ETF、期货、期权等资产类别传入adj不参与复权计算;freq支持分钟级(1/5/15/30/60 分钟)以及日(D)、周(W)、月(M)K 线,分钟数据对积分有更高要求;ma均线为动态计算:例如取 5 日均线,start_date与end_date的跨度必须超过 5 日,且只支持单只股票(必须传入ts_code)。输出列形如ma_5(5 日均价)、ma_v_5(5 日均量)。
除上述参数外,通用行情接口 还补充了:
factors:股票因子(asset='E' 有效),支持tor换手率、vr量比;adjfactor:复权数据返回时是否附带复权因子列,True时返回adj_factor字段(该功能自 1.2.33 版本生效);ts_code不支持多值输入,多值输入会导致结果出现重复记录。
四、接口调用示例
4.1 日线复权
# 取000001的前复权行情 df = ts.pro_bar(ts_code='000001.SZ', adj='qfq', start_date='20180101', end_date='20181011') # 取000001的后复权行情 df = ts.pro_bar(ts_code='000001.SZ', adj='hfq', start_date='20180101', end_date='20181011')4.2 周线复权
# 取000001的周线前复权行情 df = ts.pro_bar(ts_code='000001.SZ', freq='W', adj='qfq', start_date='20180101', end_date='20181011') # 取000001的周线后复权行情 df = ts.pro_bar(ts_code='000001.SZ', freq='W', adj='hfq', start_date='20180101', end_date='20181011')4.3 月线复权
# 取000001的月线前复权行情 df = ts.pro_bar(ts_code='000001.SZ', freq='M', adj='qfq', start_date='20180101', end_date='20181011') # 取000001的月线后复权行情 df = ts.pro_bar(ts_code='000001.SZ', freq='M', adj='hfq', start_date='20180101', end_date='20181011')调用前需要先完成 token 初始化,两种方式任选其一:
import os import tushare as ts # 方式一:从环境变量读取(Agent 环境推荐,见 SKILL.md 的配置说明) token = os.getenv('TUSHARE_TOKEN') or ts.get_token() # 方式二:进程内全局设置一次,后续 pro_api 可不传 token ts.set_token('your_token') pro = ts.pro_api(token) df = ts.pro_bar(ts_code='000001.SZ', adj='qfq', start_date='20180101', end_date='20181011')返回结果为 pandas DataFrame,字段与对应的日线/周线/月线行情接口一致(如ts_code、trade_date、open、high、low、close、vol、amount等)。
五、复权机制的三个关键注意点
文档中特别强调了三点,直接影响数据解读与策略回测的正确性:
目前只支持 A 股的日线复权。分钟级数据不参与动态复权;周线、月线复权同样基于日线复权因子在 SDK 层聚合计算。港股与美股复权行情请分别使用 港股复权行情(
hk_daily_adj)与 美股复权行情(us_daily_adj)等独立接口。复权基准日是
end_date,而非"最近交易日"。Tushare 无论旧版接口还是 Pro 版行情接口,都以用户设定的end_date开始向前复权;而行情软件/财经网站通常以最近一个交易日为基准。例如今天是 2018 年 10 月 26 日,你查询 2018 年 1 月 5 日~9 月 28 日的前复权数据,Tushare 先取 9 月 28 日的复权因子并从该日开始复权,行情软件则从 10 月 26 日开始。这意味着同样的时间区间,不同查询时刻拿到的 qfq 数值可能不同——前复权价格是相对基准,不具备跨基准期的绝对可比性;同一模型内必须固定end_date(通常统一取"回测截止日"或"数据下载日"),才能保证全量标的的复权口径一致。复权采用"分红再投"模式计算。即假设分红款项继续按除权后价格买入股票,因此复权因子会在除权除息日向上跳升。仓库 cn_adjust.py 的注释也验证了这一点:复权因子是累积的,公司行为发生时因子上升——以 600519.SH 2022-06-30 除息日为例,因子从 7.4740 跳升至 7.5546。
六、仓库中的工程化落地:从接口到回测流水线
6.1 前复权在 Tushare Loader 中的实现
Vibe-Trading 的回测引擎通过 agent/backtest/loaders/tushare.py 接入 Tushare 数据。其_fetch_daily_frame()的实现路线是:
- 按证券类型路由到不同端点:A 股股票走
daily、ETF/LOF 走fund_daily、指数走index_daily、港股走hk_daily(美股/数字货币直接跳过并告警); - 股票与基金随后调用
adj_factor/fund_adj拉取同区间复权因子(tushare.py); - 调用
apply_qfq()完成前复权(tushare.py),复权因子不可用或异常时丢弃该标的而非返回未复权价格。
源码注释给出了未复权数据对收益率的污染程度(cn_adjust.py):以 Tushare 自身pct_chg为基准核对 2020-2024 年数据,300750.SZ 在 2023-04-26 除权日按未复权收盘价计算的收益为-41.82%,真实涨跌为+5.40%;300124.SZ 为 -34.26% 对 -1.01%;601012.SH 为 -24.21% 对 +6.46%。由于除权只会让价格向下跳空,该偏差恒为负值,是对横截面 IC 等指标的系统性污染而非随机噪声——这正是回测必须使用复权行情的原因。
6.2 测试用例验证复权正确性
agent/tests/test_tushare_loader.py 中TestFetchDailyFrameRouting对复权逻辑做了可复现的单元验证。例如test_stock_prices_are_corporate_action_adjusted:构造 2 送 1 拆分场景,复权因子序列为(1.0, 1.0, 2.0),原始收盘价为[10.5, 11.0, 11.5],前复权(向前对齐到最后一根 bar)后结果为[5.25, 5.5, 11.5]——即除权前价格按"当日因子/最新因子"折半,最后一根 bar 保持实际成交价。test_a_symbol_with_no_factors_is_dropped_not_returned_raw则验证了"无复权因子即丢弃标的"的防御逻辑,防止未复权价格混入回测。
6.3 与权限、限流相关的工程细节
- 积分门槛:复权因子接口 说明
adj_factor需要 2000 积分起、5000 积分以上可高频调取;分钟数据同样有独立积分要求,Agent 调用时应留意权限提示; - 限流退避:tushare.py 内置了限流识别与指数退避(
_RATE_LIMIT_BACKOFF_SECONDS = (5.0, 20.0, 40.0)),仅对"每分钟/每天访问次数"类配额拒绝重试,真正失败的调用(如代码不存在)立即抛出而非拖慢流程; - 交易日历对齐:日期一律使用
YYYYMMDD格式,交易日以上交所/深交所日历为准,可通过 交易日历接口 获取。
七、Agent 场景下的使用建议
在 Vibe-Trading 的 Agent 会话中调用复权行情,建议遵循以下实践:
- 统一复权基准:同一研究任务内固定
end_date为数据下载日或回测截止日,避免不同批次数据复权口径漂移; - 区分业务场景:计算累计收益、复利收益用
hfq;观察 K 线形态、贴近当前价格做技术指标用qfq;做除权事件研究(如分红前后收益)时则可能需要未复权数据配合事件日校准; - 批量拉取时控制频率:
pro_bar单标的单次调用即可覆盖全历史,批量提取需按积分档位控制调用节奏,或复用仓库中的退避重试逻辑; - 验证数据质量:可参照 test_tushare_loader.py 的思路,对重点标的的复权因子突变日(除权日)做抽查,确保价格序列在除权日前后连续无缺口。
八、延伸阅读
- 复权因子(adj_factor):复权因子的每日数据来源与提取方式;
- 通用行情接口(pro_bar):
pro_bar的完整参数、factors、adjfactor及输出指标说明; - 历史日线(daily):未复权行情接口;
- 股票技术面因子(专业版).md):支持 HTTP 调用的静态复权因子行情;
- Tushare Loader 源码 与 复权实现:仓库内前复权的工程化实现;
- Tushare Loader 测试:复权正确性与标的类型路由的验证用例。
【免费下载链接】Vibe-Trading"Vibe-Trading: Your Personal Trading Agent"项目地址: https://gitcode.com/GitHub_Trending/vi/Vibe-Trading
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考