WebSocket 行情断线重连:数据空窗、K线回补和状态校准

发布时间:2026/7/8 13:10:47
WebSocket 行情断线重连:数据空窗、K线回补和状态校准 摘要WebSocket 行情断线后重连成功日志显示一切正常。但事后对账发现有些品种少了几秒到十几秒的数据。连接恢复不等于数据恢复——重连只修好了通道断线期间的数据空窗、重连后的状态校准、K线回补的粒度边界都需要使用者侧主动处理。本文把一次断线重连拆成三层恢复框架给出一张五步检查卡梳理快照校准和 K 线回补的工程流程并用 TickDB 真实跑了一遍 REST ticker 快照、REST kline 回补和 WebSocket 订阅附上通用状态机示例和 FAQ。读完你会拿到一份可直接落地到监控脚本里的空窗处理方案。连接恢复只是第一步真正要确认的是状态有没有校准、空窗有没有标记、K线有没有回补。一、重连成功但数据少了几秒断线重连要分三层看通道恢复、当前状态恢复、缺失区间恢复。下午开盘前WebSocket 行情断了一次很快就重连成功了。日志显示连接状态恢复正常心跳也续上了。一切看起来都没问题。事后对账发现有些品种有几秒到十几秒的成交记录没回来。查程序日志没有漏接——那些数据根本就没到过这一端。流式行情就像一根水管。断线是水管裂了重连是接上了一根新水管但裂开那段时间流出去的水已经没了。不能默认认为服务端会为客户端断线期间自动续播历史是否支持补发、回放或历史恢复要以具体数据源文档和实测为准。恢复连接只是重新建立了通道不代表中间的数据已经回来。空窗那段时间里发生了什么只能另外想办法查。这件事触及了行情监控里一个容易被跳过的环节连接状态恢复不等于数据状态恢复。把两者混在一起可能让分析框架把“数据沉默”误判为“市场平静”。二、三层恢复框架连接、状态、数据一次断线重连的过程拆开来看有三层。每一层恢复的内容不同忽略任何一层都可能留下隐患。三层之间有严格的依赖顺序通道没恢复快照拉不到快照没校准回补窗口定不准。层级恢复内容重连后能看到什么看不到什么常见误区连接层物理通道WebSocket 握手成功心跳恢复断线期间通道是空白的日志显示重连成功就认为一切正常状态层当前快照重连后第一条行情的价格和状态断线前的状态是否已经变化不做快照校准直接把断线前后的价格连起来用数据层断线期间的历史重连后的实时推送断线期间成交了几笔、盘口变动了几次以为 K 线回补能替代逐笔明细三层逐层往下大多数行情库的日志只覆盖到第一层。第二层需要主动用快照做状态校准第三层需要确认回补粒度是否满足分析需求。后两层如果忽略可能把“数据缺失导致的跳变”当成市场信号。三层恢复每一层回答一个不同的问题连接层回答“通道还在吗”状态层回答“现在是什么状况”数据层回答“中间漏了什么”。三层都答完这次重连才算真正处理完。三、断线后必须记录四个时间戳行情 timestamp 和本地检测时间不能混用否则你会误判空窗长度。重连流程启动前或同时必须把空窗起点落盘。记录空窗与触发重连可以并行但不能只重连不留痕。没有这些标记事后无法区分“市场没动静”和“数据没回来”。字段含义记录时机disconnect_detected_at本地检测到断线的时间心跳超时或连接断开时写入last_seen_ts断线前最后一条行情数据的 timestamp断线时从本地缓存读取reconnected_at本地 WebSocket 重连成功时间重连握手完成后写入first_seen_ts重连后第一条行情数据的 timestamp重连后第一条数据到达时写入这四个字段分属两条时间线disconnect_detected_at和reconnected_at是本地检测时间标记监控系统感知到断线和恢复的时刻。last_seen_ts和first_seen_ts是行情数据时间戳标记行情流本身的断点和续点。本地检测时间和行情时间必须分开存不能互相替代——两者差异本身就是判断延迟和时钟同步问题的重要线索。没有时间戳的空窗复盘时就是一笔糊涂账。四个字段写入后空窗区间就有了明确的边界。后续做回补、做分析、做健康标记都以这个区间为基准。四、重连后的三步处理重连成功后按以下顺序执行三步操作。顺序不能乱先定位当前状态再回补历史缺口最后标记异常区间。第一步快照校准重连后第一条行情可能与断线前最后一条之间存在跳跃。比如断线前最后一条价格 100重连后首条快照 102。这 2 块钱的差值可能包含中间三笔未收到的成交——真实涨幅可能是 1.5而不是 2。如果不做校准直接把 100 和 102 连起来算涨跌幅结论就偏了。处理方式通过 REST ticker 快照接口拉取当前完整状态作为重连后的新起点。快照校准的目的是确认“现在是什么状态”不是补回断线期间的变化。断线前的价格和状态不再直接参与后续计算。第二步K 线回补空窗期间的分钟级、小时级或日级 K 线通过 REST kline 接口拉回补上。回补后分钟级别的时间序列看起来重新连续了。但回补之前要确认三件事回补的 interval 和实时订阅的 interval 是否一致。回补的 symbol 和断线前是否完全一致。回补的数据和断线前最后一条 K 线之间有没有重叠或二次缺口。重复回补要用gap_start gap_end symbol interval四个字段去重。回补是对齐时间序列的缺口不是填补数据的完整。第三步健康标记空窗区间标记为“待核验”不按正常连续数据参与指标计算、告警判断或自动化流程。分析时可以把空窗区间单独剔除也可以带着标记看整体趋势——但标记不能省略。没有标记的空窗复盘时就是静默的数据污染。五、K 线回补的边界补得回 OHLC补不回逐笔过程K线回补能补回聚合结果但补不回断线期间的逐笔过程。K 线回补是常见操作但它有自己的边界。回补方式能补回什么补不回来什么K 线回补OHLC 四个聚合点、成交量盘口变化过程、价格触点的确切时间、大单先后次序是否需要补回那些缺失的信息取决于分析框架依赖的是聚合结果还是过程细节。判断标准很简单缺的这段数据如果只看 K 线就能回答问题那它就是够的如果不能就需要知道缺的是什么。K 线回补不等于逐笔数据完整恢复。接口按粒度返回数据使用者判断粒度是否满足当前分析需求。这两层职责不能混淆。六、通用状态机示例以下是一个断线重连处理的通用状态机骨架使用 Python 演示。这不是生产代码不绑定任何特定数据源的端点或字段。fromenumimportEnumfromdatetimeimportdatetime,timezonefromtypingimportOptionalclassConnState(Enum):CONNECTEDconnectedDISCONNECTEDdisconnectedRECONNECTINGreconnectingclassGapRecovery:断线空窗处理状态机骨架。通用工程示例非生产代码。def__init__(self):self.stateConnState.CONNECTED self.disconnect_detected_at:Optional[datetime]Noneself.last_seen_ts:Optional[int]Noneself.reconnected_at:Optional[datetime]Noneself.first_seen_ts:Optional[int]Noneself.stream_healthyTrueself.gap_review_requiredFalsedefon_disconnect(self,last_ts:int): 断线时调用记录本地检测时间和最后一条行情时间戳。 记录空窗与触发重连可以并行。 self.stateConnState.DISCONNECTED self.disconnect_detected_atdatetime.now(timezone.utc)self.last_seen_tslast_ts self.stream_healthyFalsedefon_reconnecting(self):进入重连状态。self.stateConnState.RECONNECTINGdefon_reconnected(self,first_ts:int): 重连成功后调用记录重连时间和首条行情时间戳触发校准流程。 三步处理顺序不能乱。 self.stateConnState.CONNECTED self.reconnected_atdatetime.now(timezone.utc)self.first_seen_tsfirst_ts# 三步处理顺序不能乱self._calibrate_state()# 1. 快照校准self._backfill_klines()# 2. K 线回补self._mark_gap_for_review()# 3. 健康标记def_calibrate_state(self):快照校准通过 REST ticker 获取当前完整状态作为新起点。# 实际实现调用 REST ticker 或类似快照接口# 不与断线前价格直接做差值计算passdef_backfill_klines(self): K 线回补通过 REST kline 接口拉取断线期间的聚合历史。 回补前检查 interval 一致性、symbol 一致性、去重。 # 实际实现调用 REST kline 接口# 回补后检查是否有二次缺口passdef_mark_gap_for_review(self): 空窗区间标记为待核验。 连接恢复了但这段空窗仍需要核验。 self.stream_healthyTrueself.gap_review_requiredTruepropertydefgap_duration_sec(self)-Optional[float]:ifself.disconnect_detected_atandself.reconnected_at:return(self.reconnected_at-self.disconnect_detected_at).total_seconds()returnNone状态机要点断线时同时记录disconnect_detected_at和last_seen_ts分属本地检测时间和行情时间两条线。重连成功后按顺序执行快照校准 → K 线回补 → 健康标记。stream_healthy True表示连接和推送已恢复gap_review_required True表示空窗区间仍需核验——两者独立表达。回补前检查 interval 一致性和 symbol 一致性回补后检查是否有二次缺口。空窗区间始终标记为“待核验”不按正常连续数据参与指标计算、告警判断或自动化流程。七、用 TickDB 实际跑一遍快照、K线和 WebSocket 订阅上面讲了方法论和通用状态机。下面用 TickDB 真实跑一遍三种接口看看快照校准、K线回补和 WebSocket 订阅各自能做什么、不能做什么。1. REST ticker重连后做快照校准TickDB REST ticker 真实调用截图用于重连后获取当前行情快照建立新的状态基准。WebSocket 重连后第一件事不是立刻把断线前后的价格连起来算而是先重新取一次当前快照确认“现在是什么状态”。使用 TickDB REST/v1/market/tickerHeader 使用X-API-Key请求一个真实 symbol如AAPL.US。返回结构里重点观察code、message、data[]、symbol、type、last_price、timestamp。这张截图能证明的不是“行情一定连续”而是快照查询可以返回结构化字段重连后可以用当前快照重新建立状态基准last_price和timestamp需要作为字段被核对而不是直接默认可信。快照校准回答“现在是什么状态”不是补回断线期间的变化。一次 ticker 成功也不代表全市场都可用。2. REST kline对空窗做聚合级回补TickDB REST kline 真实调用截图K线回补提供 OHLC 聚合数据不能还原逐笔过程。K线回补只能补聚合结果不能补回逐笔过程。它适合恢复时间序列的连续性但不能还原断线期间每一笔成交和盘口变化。使用 TickDB REST/v1/market/kline参数包括symbol、interval、limit。返回结构里重点观察code、message、data.symbol、data.interval、data.klines[]、每根 K 线里的time/open/high/low/close/volume。这张截图能证明K线接口可以按 interval 返回聚合历史回补前必须确认 symbol 和 interval回补后还要检查是否存在重叠、二次缺口或粒度不匹配K线回补不是逐笔恢复补得回 OHLC补不回逐笔过程。3. WebSocket ticker实时订阅入口TickDB WebSocket 真实订阅截图WebSocket 是实时订阅入口不是断线历史自动回放入口。WebSocket 是实时数据流入口。它负责持续推送当前订阅的数据但它不是断线历史回放工具。使用 TickDB WebSocket 实时入口连接成功后会返回cmdconnected订阅 ticker 后返回结构为cmdtickerdatadata里可以观察symbol、type、last_price、timestamp。这张截图能证明WebSocket 可以作为实时订阅入口返回结构是cmd data订阅成功不等于断线期间数据会被自动补回客户端仍然需要自己记录空窗、做快照校准、做 K线回补和健康标记。八、TickDB 在这类系统中的位置经过以上真实调用验证TickDB 在断线重连场景里的价值不是自动修复空窗而是提供三类可组合的数据入口WebSocket实时订阅入口用于持续接收行情。断线检测和空窗记录的起点。REST ticker快照查询入口用于重连后做当前状态校准。返回结构化字段供逐项核对。REST kline聚合历史入口用于对空窗做 K线级回补。按 interval 返回 OHLC 数据。TickDB 不自动修复断线空窗。真正的空窗处理逻辑仍然在使用者侧记录断线时间、记录最后一条行情 timestamp、记录重连成功时间、记录重连后第一条行情 timestamp、做快照校准、做 K线回补、标记空窗区间、决定这段数据是否能参与后续指标、告警或自动化流程。本文不能把一次实测外推成延迟、SLA、稳定性、全市场可用或断线自动恢复能力。行情接入层提供的是数据入口不是自动诊断。九、常见问题FAQQ1WebSocket 重连成功为什么数据还是少了重连只恢复了传输通道。不能默认认为服务端会为客户端断线期间自动续播历史是否支持补发、回放或历史恢复要以具体数据源文档和实测为准。空窗期间的数据必须主动记录和回补。Q2重连后第一步应该做什么记录重连成功时间reconnected_at和重连后首条行情数据的 timestampfirst_seen_ts然后立刻通过 REST ticker 快照接口拉取当前完整状态作为新起点。不要直接把重连后第一条数据和断线前最后一条做差值计算——中间可能有未收到的成交差值不代表真实市场波动。Q3K 线回补能补回什么补不回什么K 线回补能补回分钟/小时/日级别的 OHLC 聚合点和成交量。补不回盘口变化过程、每笔成交的确切时间、大单先后次序。如果你的分析只需要 OHLCK 线回补就够了如果需要过程细节需要确认缺失的信息是否影响分析结论。Q4怎样防止空窗被误当成市场平静用disconnect_detected_at、last_seen_ts、reconnected_at、first_seen_ts划定空窗边界空窗区间内的所有数据标注为“待核验”不按正常连续数据参与指标计算、告警判断或自动化流程。分析时可以选择剔除空窗区间也可以带着标记看整体趋势——但不能不标记。Q5TickDB 能自动处理断线空窗吗不能。TickDB 提供 WebSocket、REST ticker、REST kline 这些数据入口不替使用者自动完成空窗诊断。空窗的记录、回补粒度的判断、健康标记的写入都需要使用者在自己的监控脚本中实现。本文不能把一次实测外推成延迟、SLA、稳定性、全市场可用或断线自动恢复能力。Q6快照校准和 K 线回补有什么区别快照校准回答“现在是什么状态”取的是重连后当前时刻的一张完整快照通过 REST ticker 实现。K 线回补回答“中间大致发生了什么”拉的是断线期间的历史聚合数据通过 REST kline 实现。两者互补——先校准当前再回补历史顺序不能反过来。十、发布前检查清单断线时是否记录了disconnect_detected_at和last_seen_ts重连后是否记录了reconnected_at和first_seen_ts本地检测时间和行情时间是否分开存储重连后是否通过 REST ticker 快照接口做了状态校准K 线回补前是否检查了 interval 一致性和 symbol 一致性回补后是否检查了二次缺口或重复覆盖空窗区间是否标记为“待核验”stream_healthy和gap_review_required是否独立维护你现在的监控里重连成功之后有没有记录空窗的起止时间戳本地检测时间和行情时间有没有分开存 本文以 TickDB 作为统一行情 API 接入示例WebSocket 用于实时订阅REST ticker 用于快照校准REST kline 用于聚合级回补。本文仅讨论行情监控的工程方法不构成投资建议。文中截图仅展示调用链路与字段结构不用于讨论价格涨跌不构成实时报价或投资建议。标签WebSocket, 行情断线重连, 数据空窗, K线回补, 状态校准, TickDB