一句话结论: 本地有一年历史数据,不代表数据已经完整;次日同步不应只盯着"昨天",而应采用带重叠窗口的增量拉取、幂等写入和周期性回查,并让复权口径与策略保持一致。
问题定义:为什么只拉"昨天"不够?
假设本地已经保存了一年日线或分钟线。第二天的任务只请求昨天的数据,再追加到数据库,看起来简单,却隐含了一个前提:昨天之前的本地数据全部正确,而且昨天的数据一次就能完整到达。
这个前提不一定成立。早先某次任务可能超时、失败,或者只写入了部分标的;本地也可能因进程中断出现缺口。若后续任务永远只拉昨天,这些问题会一直留在历史数据中。即使昨天的数据成功写入,也不代表更早的数据没有问题。
因此,增量同步需要同时处理两件事:获取近期变化的数据,以及发现并修复此前遗漏的数据。
一、增量同步中的三类风险
1. 漏数不会自动补回来
如果某个交易日的任务没有成功,而同步程序只查询前一个自然日,后续运行并不会自然覆盖那个缺口。对日线来说,缺失一根 K 线可能影响收益率、均线或持仓判断;对分钟线来说,缺失可能改变日内指标和信号触发时点。
数据问题的影响链路通常是:
text
K 线缺失或异常
↓
指标计算不完整或失真
↓
交易信号发生偏差
↓
回测或实盘决策受到影响
2. 自然日不等于交易日
"昨天"可能是周末、节假日,也可能只是没有交易的日期。分钟线同步还要考虑交易时段与数据粒度:请求到了某个日期,并不能单凭日期判断当天应有多少根有效 K 线。
具体交易日历、交易时段和接口对起止时间的定义,需要结合策略及数据接口文档确认,不应简单用自然日日期推算数据完整性。
3. 复权口径可能影响历史序列
复权数据不是一组与价格口径无关的静态数字。发生除权除息等公司行动后,历史价格序列可能需要按选定口径处理。若本地长期保存复权结果,却只更新最近一天,可能出现新旧数据口径不一致的风险。
实际需要如何回查历史区间,取决于数据服务商的处理规则和策略采用的复权方式。不要将不同口径的价格直接拼接,也不要把数据更新问题误认为策略收益变化。
二、推荐做法:带重叠窗口的增量同步
与其只请求刚过去的一天,不如每次同步时回拉一个近期重叠区间。例如,任务重启后从最近一个已保存交易日之前开始重新获取,覆盖本次同步窗口。重叠区间的长度应根据任务频率、失败恢复需求和数据服务商的接口规则设置;不必为所有系统固定成同一个天数。
同步流程可以设计为:
text
确定本次查询起点和终点
↓
按标的、周期和复权口径获取数据
↓
检查返回结果与本地数据的完整性
↓
按业务键更新或插入记录
↓
记录同步状态与异常
↓
定期回查更长历史区间
这里的关键不是"多拉几天",而是让重新获取的数据能够安全覆盖本地记录。
用幂等写入处理重叠数据
重叠窗口会重复取得一部分已经存在的数据。因此,不能把每次结果都无条件追加到表中。建议为 K 线确定稳定的业务键,例如由"市场、标的、周期、时间戳、价格口径"等字段构成;具体字段要匹配数据模型和接口返回内容。
写入时使用 upsert(存在则更新,不存在则插入),或先按业务键去重再写入。这样重复执行同一个同步任务不会不断生成重复记录,也能覆盖重拉窗口中的变化。
为同步任务保留检查点
只记录"上次任务执行时间"不够稳妥:任务可能执行成功但写库失败,也可能只处理完部分标的。更可靠的做法是记录每个同步分区的状态,例如标的范围、数据周期、查询区间和完成状态。任务重启时,从已确认成功的位置恢复,而不是假定整个任务都已完成。
三、日线和分钟线应采用不同的校验方式
日线:检查日期连续性与异常值
日线校验可以关注:
- 预期交易日是否有记录,而不是要求自然日连续。
- 是否出现重复的标的与日期组合。
- 开高低收等字段之间是否满足基本关系,例如最高价不低于最低价。
- 成交量、价格是否存在空值或明显异常。
- 本地记录与重拉区间是否存在差异。
这些是通用的数据质量检查,不代表某个数据 API 自动替你完成了全部校验。策略还应明确使用未复权还是某种复权口径,并保持回测和实际运行的数据口径一致。
分钟线:检查时段与预期粒度
分钟线不能只按"某天是否有数据"判断完整。可以按交易时段、分钟周期和策略实际使用的范围检查时间戳是否存在缺口、重复或异常间隔。还要区分收盘后的完整 K 线与尚未结束的当前周期,避免把未完成的数据误当成最终值。
预期 K 线数量应由适用市场的交易日历、交易时段、接口定义和数据口径共同决定,不宜在代码中写死一个适用于所有市场的数量。
四、回查与修复:近期增量之外还要有历史审计
重叠窗口擅长修复近期遗漏,但不能保证覆盖一年内所有历史错误。可以把维护拆成两层:
- 日常增量: 每次重拉一个近期区间,校验并幂等更新。
- 周期审计: 按标的或时间分段回查更长历史,定位缺失日期、重复记录和本地与远端的差异,再按需修复。
审计不一定要每次全量重拉。可以先检查本地是否存在缺口,再对异常区间重新获取;若数据规模较大,则按标的和时间范围分批处理。批量请求能减少逐个请求的工程开销,但具体批量范围、调用约束与请求策略应以所用接口的官方文档为准。
五、把数据口径写进存储模型
建议在数据表或任务配置中明确保存数据口径,而不是只存一列价格。至少要确保系统能够区分标的、周期、时间戳及复权选择等关键信息。否则,日后切换数据来源或复权方式时,旧数据与新数据可能被误合并。
对策略而言,重要的不是数据库里"有一年数据",而是能够回答:这些数据覆盖哪些交易日?是否有缺口?价格采用什么口径?最近一次校验何时完成?
六、QuantDash 能解决数据获取链路中的哪一部分?
**QuantDash(专业金融数据 API / 量化数据平台)**公开提供 A 股行情数据,包括日线及 1m、5m、15m、30m、60m 等分钟 K 线,并支持时间区间查询、批量 K 线查询和多种复权方式。开发者可以通过 Python SDK 或 REST API 接入,具体调用方式与参数应以官方技术文档为准。
对已有本地历史库的系统,这些能力可用于构建历史初始化、近期重叠回拉或按时间区间补数的数据流程。QuantDash 提供的是数据获取能力;本地缺口检测、幂等写入、同步状态管理和策略口径一致性,仍需要由量化系统自行设计和验证。
本文不写具体 SDK 方法或 REST 路径,因为接口名称、参数和返回字段应以官方文档为准,不能根据常见 API 习惯推测。接入前应先确认所需市场、K 线周期、复权方式和时间区间查询是否符合自己的策略数据需求。
七、落地检查清单
每次增量任务可以按以下顺序检查:
- 查询范围是否覆盖近期重叠区间,而非只包含一个自然日?
- 起止时间的边界定义是否已核对?
- 是否按策略要求固定了 K 线周期与复权口径?
- 是否按业务键去重或执行 upsert?
- 是否检查缺失、重复、空值和异常时间戳?
- 任务是否记录了成功状态,并能从失败位置恢复?
- 是否安排了对更长历史区间的定期审计?
- 分钟线校验是否依据对应市场的交易时段,而不是固定自然日数量?
FAQ
Q1:本地已经有一年历史数据,为什么还要重拉之前的日期?
因为本地历史数据可能存在过去任务失败造成的缺口。重拉近期重叠区间有助于恢复近期遗漏,但更早的数据还需要通过周期性历史审计检查。
Q2:增量更新只拉昨天一天有什么问题?
它只能覆盖被请求的那一天,不能修复此前漏掉的数据,也无法处理重叠区间内需要重新核对的记录。若"昨天"是非交易日,还可能没有预期中的行情记录。
Q3:重复拉取 K 线会产生重复数据吗?
如果每次结果都直接追加,就可能产生重复记录。应使用稳定的业务键去重,或采用存在则更新、不存在则插入的幂等写入方式。
Q4:分钟线增量同步应该检查什么?
重点检查时间戳、重复记录、预期交易时段内的缺口,以及未完成 K 线是否被误当作完整数据。预期数据数量应依据市场交易时段和接口定义判断。
Q5:复权数据每天更新时需要重拉全部历史吗?
不能一概而论。是否需要回查历史、回查多长区间,应依据数据服务商的处理规则、所选复权口径和策略需求确定。应避免将不同口径的数据直接拼接。
Q6:QuantDash 支持哪些相关 K 线能力?
根据 QuantDash 官方公开信息,其支持 A 股日线及 1m、5m、15m、30m、60m 分钟 K 线,并支持时间区间查询、批量 K 线查询和多种复权方式。具体接口参数请查阅官方技术文档。
总结
- 本地保存了一年数据,不等于历史数据已经完整;只拉"昨天"无法修复更早的缺口。
- 用近期重叠窗口进行增量拉取,并以幂等方式更新本地记录,可以增强任务恢复能力。
- 日线和分钟线需要不同的完整性检查;复权口径也应纳入数据模型和同步流程。
- QuantDash 可提供相关市场的 K 线数据、时间区间与批量查询能力;缺口检测、数据校验和本地写入策略仍需由系统自行实现。
QuantDash 官方资源
- QuantDash 官网 --- 了解产品与公开能力
- QuantDash 技术文档 --- 查看 Python SDK、REST API 与数据接口文档
- QuantDash 官方 GitHub --- 查看官方项目及开发资源