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

选型最容易出错的时刻,是收到第一条行情之后。接口返回成功,只证明这次请求或订阅产生了响应;它没有回答高峰期是否跟得上、断线后能否恢复、历史够不够,以及数据能否用于你的产品。
一个可执行的顺序是:先确认不可缺失的能力,再验证实际交付质量,最后比较同一使用范围下的总成本。 功能缺项不能靠低价抵消,授权未确认也不能靠技术接通代替。以下方法适用于行情看板、价格提醒、研究工具和数据服务集成;行情接口本身不等于下单或交易接口。
一、先列需求矩阵,覆盖必须具体到品种与字段
先从一个真实用例出发。自选股看板可能只需要最新价、涨跌幅和更新时间;价差提醒需要买卖报价及其时间;盘口分析需要明确档位、数量单位和更新方式;回测还需要对应粒度的历史、复权或合约连续化口径。不要把这几种任务统一写成“需要实时行情”。
把每条需求标为“必需”或“可选”,并为必需项写明缺失时如何处理。“待核实”是证据状态,不能自动变成“可选”。
| 需求维度 | 应写清的内容 | 验收证据 |
|---|---|---|
| 资产与身份 | 市场、品种、合约月份、代码、计价单位 | 代码映射和目标品种响应 |
| 字段与语义 | 最新价、买卖价、成交量、时间戳、盘口档位 | 字段字典和有效样本 |
| 更新与时段 | 事件推送或定频、常规与延长时段、日历 | 分时段采样记录 |
| 历史与口径 | 起止日期、日线或分钟、复权、连续合约规则 | 边界日期与分页查询 |
| 容量与用途 | 同时订阅数、请求量、用户规模、内部或对外展示 | 压力测试和书面授权 |
不同资产尤其容易在“字段同名”处产生误会。股票成交量可能使用股或手;期货必须区分具体到期合约与连续序列;指数值不等于可交易标的的成交价;加密资产要说明交易场所与交易对。外汇买卖报价流不能直接解释为集中订单簿,也不能把每次报价变化当作一笔已成交交易。
以 TickDB 作为多资产候选时,官方文档提供了 REST 和 WebSocket 接入,并按频道列出市场与字段。评估时仍应回到目标品种和频道:Ticker、Depth、Trade 的适用范围并不相同,支持某个市场的报价不推出该市场所有品种都有逐笔、深度或完整历史。
二、REST 与 WebSocket 按任务分工,频道权限单独验收
历史区间查询、首次加载和低频点查,优先验证 REST;连续报价、逐笔或盘口变化,优先验证 WebSocket。多数实时应用会同时使用两者,但历史回补、快照与推送能否衔接,必须由接口能力和时间或序列规则决定。

图 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 的应用层缺消息也不等同于网络层丢包。
没有完整分母时,仍可验收必需字段缺失率、活跃时段静默区间、历史时间格覆盖及抽样一致性。静默不必然是故障:停牌、休市、低成交和仅推送变化值都可能正常。盘口增量丢失后的修复方式与报价快照不同;只补一条最新价无法重建漏掉的逐笔历史。
重连要恢复业务状态,再恢复“实时”标识

图 2:断线恢复验收示意。恢复连接、恢复订阅和恢复数据连续性是三个不同结果。
在测试环境主动断开连接,记录断线检测、重新鉴权、重新订阅、首条有效数据和状态同步各自用时。恢复后检查是否丢订阅、重复处理旧消息,或把陈旧缓存重新标成实时。需要增量状态的频道应按协议重新同步快照和序列;不能补齐的区间应在存储和界面中保留缺口标记。
再与独立权威来源抽样核对。比较前统一品种、时段、报价或成交类型、复权、时间精度和来源覆盖;不同场所或不同报价贡献源的价格并不必然相同。抽样核对能帮助定位问题,不能证明全量完整性。报告应区分文档声明、本次观察和仍未验证的部分。
四、把历史、授权和扩容费用放进同一张成本表
历史覆盖要按“品种 × 粒度 × 日期”检查。能查到五年前的日线,不代表能查到同一时期的分钟、逐笔或盘口。至少抽查最早所需日期、最近交易日和跨分页边界,并核对停牌、合约到期、复权、夏令时与交易日归属。
套餐比较必须按同一工作量计算。假设看板需要 300 个品种,每次 REST 请求可以查 50 个品种,每 5 秒轮询一次,那么仅基础轮询就需要 ceil(300 / 50) × 60 / 5 = 72 次请求/分钟;启动加载、重试和历史查询还要另算。这只是容量预算示例,不代表任何供应商的真实配额。改用 WebSocket 后,也仍需核对订阅计数方式、频道是否分别计数、连接配额和下游分发成本。
| 成本项目 | 必须确认的问题 | 需要留存的依据 |
|---|---|---|
| API 与数据权限 | 哪些市场、频道、历史与并发包含在内 | 当前套餐说明与报价 |
| 数据使用授权 | 内部使用、对外展示、衍生结果、再分发是否允许 | 对应使用场景的书面条款 |
| 部署与冗余 | 备用源、流量、存储、连接和扩容怎样计费 | 同口径容量预算 |
| 实施与维护 | 代码映射、字段适配、监控和故障处理投入多少 | 工时估算与运维方案 |
建议用统一期间比较:总成本 = 订阅及额外数据费 + 授权费 + 基础设施与冗余费 + 实施维护投入。 不预设某项一定另收费,也不默认月费已包含全部使用权。工程上能把数据转发给用户,不意味着合同已允许再分发;“衍生指标”能否展示或销售也应单独确认。
五、验收结论应落到“通过、条件通过、不通过”
把前面的检查变成一页验收记录:需求项、阈值、证据、结果、限制和负责人。阈值由业务容忍度确定,并在测试前写好。例如看板刷新体验与逐笔研究的要求不同,不应共用一个未经论证的毫秒数。
- 通过: 必需品种、字段、权限和容量均有证据;时效与恢复满足预定目标;总成本落在预算内。
- 条件通过: 仅有业务明确接受的非关键限制,且写明使用范围、临时措施和复验日期。未核实的必需项不能按此放行。
- 不通过: 必需能力缺失、关键质量目标不满足,或实际用途的授权仍不明确。
采购比较最终应保留同一天或同一有效期内的文档与报价、同条件的采样记录,以及重连和回补结果。无论候选是谁,只有这些证据能回答“它是否适合这个项目”;品种总数、成功建立连接或一个套餐价格都无法单独完成验收。
资料口径:TickDB 官方接入及 Ticker、Depth、Trade 文档,核对日期为 2026 年 10 月 23 日。文中提供选型方法与分析示例,未给出供应商在线性能测试成绩;具体覆盖、权限、授权与价格以采购时资料及目标场景验证为准。