实时市场数据API怎么选:先验覆盖,再测时效与成本

用户头像sh_***1145dp
2026-10-23 发布

实时市场数据API怎么选:先验覆盖,再测时效与成本

摘要: 接入股票、外汇、期货、指数或加密行情,怎样判断实时市场数据 API 是否适合项目?先把品种、字段和业务用途写成需求矩阵,再分别验证 REST 查询与 WebSocket 推送,最后用采样、重连测试和授权核对决定是否采购。能收到报价不代表有逐笔、完整盘口或可补齐的历史;接收时间与源时间之差也只有在时间口径明确、时钟同步后才有比较意义。

4df895150f28638068cab8cf254ee2a5.png

选型最容易出错的时刻,是收到第一条行情之后。接口返回成功,只证明这次请求或订阅产生了响应;它没有回答高峰期是否跟得上、断线后能否恢复、历史够不够,以及数据能否用于你的产品。

一个可执行的顺序是:先确认不可缺失的能力,再验证实际交付质量,最后比较同一使用范围下的总成本。 功能缺项不能靠低价抵消,授权未确认也不能靠技术接通代替。以下方法适用于行情看板、价格提醒、研究工具和数据服务集成;行情接口本身不等于下单或交易接口。

一、先列需求矩阵,覆盖必须具体到品种与字段

先从一个真实用例出发。自选股看板可能只需要最新价、涨跌幅和更新时间;价差提醒需要买卖报价及其时间;盘口分析需要明确档位、数量单位和更新方式;回测还需要对应粒度的历史、复权或合约连续化口径。不要把这几种任务统一写成“需要实时行情”。

把每条需求标为“必需”或“可选”,并为必需项写明缺失时如何处理。“待核实”是证据状态,不能自动变成“可选”。

需求维度 应写清的内容 验收证据
资产与身份 市场、品种、合约月份、代码、计价单位 代码映射和目标品种响应
字段与语义 最新价、买卖价、成交量、时间戳、盘口档位 字段字典和有效样本
更新与时段 事件推送或定频、常规与延长时段、日历 分时段采样记录
历史与口径 起止日期、日线或分钟、复权、连续合约规则 边界日期与分页查询
容量与用途 同时订阅数、请求量、用户规模、内部或对外展示 压力测试和书面授权

不同资产尤其容易在“字段同名”处产生误会。股票成交量可能使用股或手;期货必须区分具体到期合约与连续序列;指数值不等于可交易标的的成交价;加密资产要说明交易场所与交易对。外汇买卖报价流不能直接解释为集中订单簿,也不能把每次报价变化当作一笔已成交交易。

以 TickDB 作为多资产候选时,官方文档提供了 REST 和 WebSocket 接入,并按频道列出市场与字段。评估时仍应回到目标品种和频道:Ticker、Depth、Trade 的适用范围并不相同,支持某个市场的报价不推出该市场所有品种都有逐笔、深度或完整历史。

二、REST 与 WebSocket 按任务分工,频道权限单独验收

历史区间查询、首次加载和低频点查,优先验证 REST;连续报价、逐笔或盘口变化,优先验证 WebSocket。多数实时应用会同时使用两者,但历史回补、快照与推送能否衔接,必须由接口能力和时间或序列规则决定。

3f7a649159fae01780124858eb1718d1.png

图 1:查询与推送的职责分工示意。快照、回补和流式数据的衔接需验证,不能假定天然无缝。

REST 需要核对单次可查品种数、时间窗口、分页、限流、超时和错误响应。WebSocket 则要核对鉴权、订阅反馈、频道字段、单连接订阅数、总连接数、心跳以及重连后的重新订阅。

“连接已打开”不是“订阅已生效”。应记录订阅请求、成功或失败反馈,以及每个目标品种收到的第一条有效业务消息。若协议没有明确成功回执,就用文档规定的方式与首条有效数据共同判定,不能自造确认机制。

同样,“支持 WebSocket”不等于“提供完整盘口”。需要分别确认报价、逐笔成交、深度是哪些频道,深度是完整快照还是增量,以及覆盖档位与频率。TickDB 的官方 Depth 文档将其 timestamp 描述为服务端时间,而 Trade 文档使用成交时间;因此即使字段同名,也不能未经核实就放在同一张延迟排行榜里。

三、用可解释的样本验收时效、完整性与恢复

先固定采样条件:供应商、套餐、目标品种、频道、测试日期、交易时段、采集机器区域和网络环境。至少包含活跃与低活跃品种、开收盘附近和常规时段;夜盘或延长时段属于需求时,也要单独覆盖。测试长度由业务风险决定,一次短时试接不能代表长期可用性。

时间先分口径,再算分位数

每条消息保存原始内容、供应商时间字段、客户端接收时间和连接编号。明确时间字段表示成交发生、源处理、服务端发送,还是快照生成;统一单位与时区,并记录采集机器的时钟同步情况。无法确认字段含义时,只报告“到达时间与源时间之差”,不要称为交易所到客户端延迟。

用墙钟时间与源时间作差,用单调时钟测量本机处理耗时和重连耗时。负差值应作为时钟或口径异常保留;只给平均值会隐藏尾部积压,应同时报告样本量、P50、P95、P99及异常数量。分位数按品种、频道和时段拆开,避免低频品种与高频品种互相掩盖。

下面的标准库脚本读取已经标准化的 CSV,统计非负时间差分位数和时间回退。CSV 列为 symbol,channel,event_ms,recv_ms,时间统一为整数毫秒,并保持接收顺序。event_ms 是采集层归一化字段,只有源时间确实表示事件时间时才这样解释;否则应在报告中保留真实时间语义。

import csv, math, sys
from collections import defaultdict

groups = defaultdict(list)
with open(sys.argv[1], newline="", encoding="utf-8") as f:
    for row in csv.DictReader(f):
        groups[(row["symbol"], row["channel"])].append(row)

for key, rows in sorted(groups.items()):
    ages, negative, missing, regressions = [], 0, 0, 0
    high_water = None
    for row in rows:  # Input must preserve arrival order.
        try:
            event = int(row["event_ms"])
            recv = int(row["recv_ms"])
        except (ValueError, KeyError, TypeError):
            missing += 1
            continue
        age = recv - event
        negative += age < 0
        if age >= 0:
            ages.append(age)
        regressions += high_water is not None and event < high_water
        high_water = event if high_water is None else max(high_water, event)
    ages.sort()
    def pct(q):
        return ages[math.ceil(len(ages) * q) - 1] if ages else None
    print(key, {"rows": len(rows), "invalid_time": missing,
                "negative_age": negative, "time_regressions": regressions,
                "nonnegative_n": len(ages),
                "p50_ms": pct(.50), "p95_ms": pct(.95), "p99_ms": pct(.99)})

保存为 audit_samples.py,使用 python audit_samples.py samples.csv 运行。这里的代码用于离线采样分析,不连接供应商,也不测量网络丢包。负差值不进入分位数,必须连同数量单独报告;无有效非负样本时结果为 None,不应填成零。时间回退只提示需要调查,不能单凭它断定网络乱序或数据错误;订阅快照、修正消息和时间精度都可能影响结果。

完整性需要分母,消息少不等于丢包

如果协议提供序列号,先确认序列是全局、按品种还是按频道递增,以及重连是否重置,再检查缺口。没有序列号、可对账事件全集或可靠补数接口时,不能把收到的消息条数换算成“丢消息率”。WebSocket 的应用层缺消息也不等同于网络层丢包。

没有完整分母时,仍可验收必需字段缺失率、活跃时段静默区间、历史时间格覆盖及抽样一致性。静默不必然是故障:停牌、休市、低成交和仅推送变化值都可能正常。盘口增量丢失后的修复方式与报价快照不同;只补一条最新价无法重建漏掉的逐笔历史。

重连要恢复业务状态,再恢复“实时”标识

43fa9353b5860ceff7b10813cc975160.png

图 2:断线恢复验收示意。恢复连接、恢复订阅和恢复数据连续性是三个不同结果。

在测试环境主动断开连接,记录断线检测、重新鉴权、重新订阅、首条有效数据和状态同步各自用时。恢复后检查是否丢订阅、重复处理旧消息,或把陈旧缓存重新标成实时。需要增量状态的频道应按协议重新同步快照和序列;不能补齐的区间应在存储和界面中保留缺口标记。

再与独立权威来源抽样核对。比较前统一品种、时段、报价或成交类型、复权、时间精度和来源覆盖;不同场所或不同报价贡献源的价格并不必然相同。抽样核对能帮助定位问题,不能证明全量完整性。报告应区分文档声明、本次观察和仍未验证的部分。

四、把历史、授权和扩容费用放进同一张成本表

历史覆盖要按“品种 × 粒度 × 日期”检查。能查到五年前的日线,不代表能查到同一时期的分钟、逐笔或盘口。至少抽查最早所需日期、最近交易日和跨分页边界,并核对停牌、合约到期、复权、夏令时与交易日归属。

套餐比较必须按同一工作量计算。假设看板需要 300 个品种,每次 REST 请求可以查 50 个品种,每 5 秒轮询一次,那么仅基础轮询就需要 ceil(300 / 50) × 60 / 5 = 72 次请求/分钟;启动加载、重试和历史查询还要另算。这只是容量预算示例,不代表任何供应商的真实配额。改用 WebSocket 后,也仍需核对订阅计数方式、频道是否分别计数、连接配额和下游分发成本。

成本项目 必须确认的问题 需要留存的依据
API 与数据权限 哪些市场、频道、历史与并发包含在内 当前套餐说明与报价
数据使用授权 内部使用、对外展示、衍生结果、再分发是否允许 对应使用场景的书面条款
部署与冗余 备用源、流量、存储、连接和扩容怎样计费 同口径容量预算
实施与维护 代码映射、字段适配、监控和故障处理投入多少 工时估算与运维方案

建议用统一期间比较:总成本 = 订阅及额外数据费 + 授权费 + 基础设施与冗余费 + 实施维护投入。 不预设某项一定另收费,也不默认月费已包含全部使用权。工程上能把数据转发给用户,不意味着合同已允许再分发;“衍生指标”能否展示或销售也应单独确认。

五、验收结论应落到“通过、条件通过、不通过”

把前面的检查变成一页验收记录:需求项、阈值、证据、结果、限制和负责人。阈值由业务容忍度确定,并在测试前写好。例如看板刷新体验与逐笔研究的要求不同,不应共用一个未经论证的毫秒数。

  • 通过: 必需品种、字段、权限和容量均有证据;时效与恢复满足预定目标;总成本落在预算内。
  • 条件通过: 仅有业务明确接受的非关键限制,且写明使用范围、临时措施和复验日期。未核实的必需项不能按此放行。
  • 不通过: 必需能力缺失、关键质量目标不满足,或实际用途的授权仍不明确。

采购比较最终应保留同一天或同一有效期内的文档与报价、同条件的采样记录,以及重连和回补结果。无论候选是谁,只有这些证据能回答“它是否适合这个项目”;品种总数、成功建立连接或一个套餐价格都无法单独完成验收。

资料口径:TickDB 官方接入及 Ticker、Depth、Trade 文档,核对日期为 2026 年 10 月 23 日。文中提供选型方法与分析示例,未给出供应商在线性能测试成绩;具体覆盖、权限、授权与价格以采购时资料及目标场景验证为准。

评论