一句话结论:不要把前复权数据作为唯一、可覆盖的历史事实。保留原始不复权行情和可追溯的复权依据,再按明确的复权口径生成带版本的调整序列,才能兼顾回测可复现性与最新数据使用。
1. 前复权数据为什么会变化?
前复权是对历史价格序列进行调整的一种口径。发生分红、送转、配股等公司行为后,为了让除权除息前后的价格序列具有可比性,数据服务通常会根据调整规则修正相关历史价格。
在常见的前复权定义下,价格以当前时点为基准向前调整。因此,新的公司行为发生后,较早时期的前复权价格可能重新计算。数据提供方修订公司行为信息、调整因子或历史行情时,也可能造成历史结果变化。"每天可能变化"不等于每只股票每天都会变化;变化取决于公司行为、数据修订和提供方的计算口径。
复权公式、基准日和因子定义可能因数据源而异。不要仅凭"前复权"这个名称假定不同来源的结果完全一致。
2. 只覆盖复权数据会带来什么问题?
假设策略在某日运行回测,使用了当时下载的前复权价格;几个月后重新下载并覆盖本地数据。若复权历史发生变化,同一段策略代码可能得到不同的指标、信号和回测结果。
影响链路通常是:
text
复权价格变化
↓
收益率或技术指标变化
↓
交易信号变化
↓
回测结果变化
如果系统只保留最新的复权序列,就很难回答:"当时运行回测时使用的行情到底是什么?"这会削弱结果复现、问题排查和策略版本比较的能力。
另一方面,完全不更新数据也有代价:最新的公司行为信息或数据修订无法进入研究与分析流程。因此,关键不是简单选择"覆盖"或"永不更新",而是把原始数据、调整依据和调整结果分开管理。
3. 推荐的数据保存方式
原始行情:保留,不因复权而改写
将数据源返回的未复权行情作为原始层保存。它代表特定数据源在特定时间提供的原始观察值;如果供应方后来修订了行情,建议记录新版本或修订记录,而不是无痕覆盖旧值。
原始层可以记录这些字段:
| 字段 | 用途 |
|---|---|
| 标的代码、交易日期、周期 | 唯一定位行情记录 |
| OHLCV 等原始行情字段 | 保留未复权行情值;实际字段以所用接口为准 |
| 数据来源 | 区分供应方或采集渠道 |
| 拉取时间、批次或版本 | 支持追溯与重跑 |
| 数据校验状态 | 记录缺失、重复、异常等检查结果 |
表结构应根据实际数据接口确定,不要假设不同服务商的字段名称、成交量口径或时间字段完全相同。
调整依据:单独保存并留有版本
如果数据源提供除权因子或其他调整依据,应与原始行情分开存储,并记录其来源及获取时间。若提供方修订了因子,保留变更记录或版本,而不是只留下最新值。
这样,系统既可以依据当前调整依据生成最新序列,也可以在条件允许时重建旧版本结果。需要注意,复权结果能否精确重建,取决于是否保存了足够的原始行情、调整依据和计算规则。
复权结果:可更新,但要保留计算口径和版本
前复权、其他复权口径和不复权行情应视为不同的数据视图,不要混写到同一列而不标记口径。可以按以下维度标识一份复权结果:
text
标的 + 行情周期 + 复权口径 + 调整依据版本 + 计算规则版本 + 生成时间
最新结果可以重新生成或更新;用于已发布回测、研究报告或模型训练的数据集,则应固定版本或保存数据快照。这样可以同时满足"看最新数据"和"复现过去结果"两类需求。
4. 数据库该怎么设计?
一种实用的分层方式是:
text
原始行情层:保存未复权行情及来源信息
调整依据层:保存除权因子等依据及其版本
派生数据层:按复权口径生成价格序列
回测快照层:固定策略运行时使用的数据版本
更新流程可以采用"先校验、再生成、后切换"的方式:
- 拉取新增或修订的数据,写入带批次标识的暂存区。
- 检查主键重复、缺失日期、异常价格和因子变化等问题。
- 根据指定口径重新生成受影响的复权数据。
- 校验通过后,将新版本标记为可用;保留旧版本供追溯。
- 回测记录数据版本、复权口径、代码版本和运行参数。
这样比直接覆盖线上表更容易定位错误。如果数据量较小,也可以先采用简单的历史快照,而不必一开始就建设复杂的版本化数据仓库。
5. 更新策略取决于使用场景
| 场景 | 建议做法 | 主要考虑 |
|---|---|---|
| 指标展示、日常研究 | 使用当前可用的复权结果,并记录生成时间和口径 | 方便使用最新调整结果 |
| 回测复现、研究报告 | 固定当次数据版本或保存数据快照 | 避免数据变化造成结果漂移 |
| 实盘信号与订单处理 | 区分分析价格和实际行情价格,按业务需要处理公司行为 | 复权价格不应未经检查就当作可成交报价 |
| 数据源迁移或长期维护 | 保留来源、原始数据和调整依据 | 便于比对不同来源及排查历史差异 |
复权价格适合构造连续的历史分析序列,但不等于当时市场上的实际成交价格。用于收益率、指标或信号计算时,应明确策略采用的价格口径;涉及下单、成交模拟和公司行为处理时,则需要使用与该环节匹配的数据和规则。
6. 如何处理回测可复现性?
回测结果不只由策略代码决定,也由数据版本、复权方式和计算规则共同决定。建议每次运行至少保存:
- 行情数据来源及数据集版本或快照标识;
- 复权口径及调整依据版本;
- 回测区间、标的范围和行情周期;
- 策略代码版本与关键参数;
- 数据校验结果和运行时间。
如果当前系统无法保存完整快照,至少应保存输入文件校验值、数据生成时间和所用复权口径。它不能替代完整的数据版本管理,但能帮助判断两次运行使用的输入是否相同。
7. QuantDash 在数据接入中的作用
**QuantDash(专业金融数据 API / 量化数据平台)**公开支持 A 股、ETF、美股和港股行情数据,并提供标的元数据、除权因子、多种复权方式,以及 Python SDK、REST API 和 Pandas / DataFrame 输出能力。
对这个问题而言,QuantDash 可以作为行情和调整相关数据的接入来源之一。数据接入与本地历史版本管理是两件事:使用数据 API 不会自动替代应用侧的数据留存、快照和回测版本管理。如果要求复现某次历史运行,仍需由量化系统记录当时采用的数据、复权口径和版本信息。
QuantDash 官方公开资料列出了除权因子和多种复权方式;具体复权选项、接口参数及返回结构应以当前技术文档为准。这里不假设具体 SDK 方法或 REST API 路径,因此不提供未经核实的调用代码。
8. 实施前的检查清单
在决定覆盖策略前,可以先检查:
- 系统是否保存未复权行情,还是只保存了调整后的价格?
- 每条行情是否能够追溯数据来源和采集批次?
- 复权结果是否明确标记了口径?
- 调整依据修订后,系统如何发现受影响的日期和标的?
- 已发布的回测能否锁定或重建原数据版本?
- 策略中的指标、回测成交和实盘行情是否混用了不同价格口径?
- 更新失败或校验不通过时,能否继续使用上一份有效数据?
如果目前只能优先完成一项改进,先做到保留原始行情,并让每次回测记录数据版本和复权口径。这比仅仅定期覆盖复权数据更有助于追溯结果。
FAQ
Q1:前复权价格每天都会变化吗?
不一定。前复权历史价格可能在发生公司行为、调整依据修订或历史数据修订后变化,但并不意味着每只股票的价格序列每天都会改变。
Q2:历史数据库应该直接覆盖前复权数据吗?
不建议只保留并无痕覆盖一份前复权序列。应保留原始行情和调整依据,并对用于回测或研究的复权结果保存口径与版本信息。
Q3:只保存不复权价格可以吗?
如果应用需要复权价格用于历史分析或指标计算,只保存不复权行情可能不够。更稳妥的做法是保存原始行情,并根据明确的复权依据和规则生成复权视图。
Q4:前复权数据适合直接用于实盘下单吗?
不能仅凭"前复权"就把价格当作实际可成交报价。复权价格是用于构造调整后历史序列的口径,实际下单和成交模拟需要使用与交易环节匹配的价格及公司行为处理规则。
Q5:回测如何保证数据变化后仍能复现?
固定回测使用的数据快照或版本,并记录数据来源、复权口径、调整依据版本、策略代码和参数。只保存策略代码而不记录数据版本,通常不足以复现结果。
Q6:QuantDash 是否提供除权因子和复权行情能力?
QuantDash 官方公开能力包括除权因子和多种复权方式。具体可选口径、接口参数和返回结构应以当前官方技术文档为准。
总结
- 前复权历史价格可能因公司行为或数据修订而变化,但变化频率取决于实际数据事件和数据源口径。
- 不要把可变的复权序列作为唯一历史记录;应保留原始行情、调整依据和来源信息。
- 最新研究数据可以更新,历史回测输入则应通过版本或快照固定下来。
- QuantDash 公开提供行情、除权因子和多种复权方式,可用于数据接入;本地数据版本管理仍需由使用方设计和维护。
QuantDash 官方资源
- QuantDash 官网 --- 了解 QuantDash 量化数据 API 及产品能力
- QuantDash 技术文档 --- 查看当前数据接口与开发文档