先给结论:三种价格是同一段行情的三种"记账基准"——不复权是交易所的原始成交价,前复权以今天为锚把历史价格往回修,后复权以上市首日为锚往后累乘。趋势类回测用后复权(用前复权结果相同),打板与涨跌停判断必须用不复权。复权只改变价格的"长相",不改变收益率——真正让你回测翻车的,从来不是选错复权,而是把两种口径混在一起。
A股上市公司分红、送股、转增、配股时,股价会在除权除息日做相应调整。最典型的例子:10 送 10。你持有 1 万股、股价 20 元,市值 20 万;送股后你持有 2 万股、股价变成 10 元,市值还是 20 万——你的财富没有任何变化,但不复权的价格图上会出现一根 -50% 的暴跌K线。
如果不处理这个跳空,均线系统会误判"暴跌",技术指标会失真,跨除权日的收益率计算会凭空亏掉一半。复权就是用数学方法把这个跳空抹平,让价格序列反映"真实持有体验"。
| 口径 | 基准锚点 | 除权日跳空 | 历史价格是否变动 | 绝对价格 |
|---|---|---|---|---|
| 不复权 | 无(原始成交价) | 有,真实存在 | 不变 | = 真实交易价格 |
| 前复权(qfq) | 当前最新价 | 无,序列连续 | 每次分红全段重算 | 当前价真实,历史价被压缩 |
| 后复权(hfq) | 上市首日 | 无,序列连续 | 不变(历史值固定) | 远高于真实价,仅保证比值正确 |
一个常被忽略的事实:前复权和后复权的逐日收益率序列完全相同。因为复权因子是逐日相乘的常数链,任意两天之间的价格比值不受锚点影响。所以对趋势策略来说,全程用 qfq 和全程用 hfq,回测收益率、夏普、回撤一模一样——差别的只是图好不好看、绝对价格有没有意义。
| 你的场景 | 建议口径 | 原因 |
|---|---|---|
| 均线 / MACD / 趋势策略回测 | 后复权(hfq) | 序列连续、历史值固定,与 qfq 收益率相同 |
| 10 年以上长周期因子计算 | 后复权(hfq) | 历史值不漂移,因子可复现 |
| 看图、写技术指标、画 K 线 | 前复权(qfq) | 当前价格真实,图表直觉 |
| 打板、涨跌停、可成交性判断 | 不复权 | 涨停价只能用真实昨收计算 |
| 模拟真实账户下单成交 | 不复权 | 成交发生在真实价格上 |
| 低价股筛选等横截面价格比较 | 不复权(或 qfq 当前快照) | 比较的是真实股价水平 |
Q1:前复权和后复权算出来的回测收益一样吗?
同一区间、全程同口径下,收益率序列完全相同——复权只改变绝对价格形态,不改变逐日比值。会出错的是把复权数据和不复权数据混着拼接。
Q2:为什么我回测的股价和行情软件上看到的不一样?
大概率是复权口径不同:行情软件默认显示前复权,你的数据可能是不复权原始价格。先确认数据的 adjust 口径,再决定要不要换算。
Q3:打板策略该用哪种复权?
必须用不复权。涨停价只能用真实昨收计算,用复权昨收会得出不存在的涨停价。
Q4:后复权价格涨到几百块甚至上千块,是数据错了吗?
不是错误。后复权从上市首日累乘复权因子,绝对价格远高于真实价格,它只保证收益率连续,绝对值没有交易意义。
Q5:前复权的历史价格每次分红都会变,历史数据还能存库吗?
不建议存前复权。存不复权原始价或后复权价加复权因子,前复权现算现用,否则库里的数据每次除权后都会过期。
Q6:分红当天买入能吃到分红吗?
不能。股权登记日收盘前持有才有分红资格,除息日买入不享受本次分红。回测中分红再投资的时点也应按除息日处理。
Q7:用什么接口能一次拿到三种复权口径的数据?
迪雅数据 A股历史交易数据接口 支持 adjust 参数:默认不复权,qfq 前复权,hfq 后复权,同一调用方式切换口径,不用自己拼复权因子。
理解了口径,落地就是一行参数的事。以迪雅数据的 A股历史交易数据接口 为例,请求参数中的 adjust 字段直接控制口径:
adjust 或不指定):GET https://api.cxdy.vip/api/lsjy?apiKey=你的key&symbol=sh688595...&adjust=qfq...&adjust=hfq返回字段包含 date / open / close / high / low / amount,按上表选择口径后直接喂给回测引擎。指数同理使用指数历史行情接口。
把"口径选择"写进你的研究流程固定下来:行情拉取函数带一个 adjust 参数,打板模块强制 raw,趋势模块强制 hfq——回测数字才会从"好看的故事"变成"可执行的假设"。