AllTick
-
股票美股港股股票市场数据实时市场数据金融数据 api

美股api怎么选才能避免数据延迟?WebSocket、REST和推送机制对比

美股API怎么选才能减少行情延迟?本文对比REST与WebSocket的数据获取方式,分析轮询等待、实时推送、断线重连和客户端处理对行情延迟的影响,并介绍如何使用AllTick订阅美股实时行情。

AllTick阅读 5 分钟

开发一个美股行情监控面板,最让人头疼的问题之一,就是 API 明明已经接入,股票价格却不能及时更新。有些行情需要等待下一次请求才能显示,有些股票价格长时间没有变化,还有些数据在服务端已经收到,却没有同步到前端页面。

这些问题并不一定意味着行情数据源延迟。对于金融科技开发者而言,真正需要检查的是从行情产生、API 传输到客户端展示的整个数据链路。

选择美股 API 时,REST 和 WebSocket 是两种常见的数据获取方式。它们在请求机制、更新时机和连接管理上存在区别。了解这些差异,才能避免不必要的轮询请求,并建立更稳定的美股实时推送系统。

美股行情延迟不一定来自 API

美股行情从数据源到达用户界面,通常要经过多个环节:

  1. 行情采集: 数据源产生新的成交或报价信息。
  2. 服务端处理: 行情数据经过整理和处理。
  3. 网络传输: 数据从服务端传输到开发者的应用服务器。
  4. 客户端处理: 应用解析行情消息,更新缓存、业务逻辑和前端页面。
    任何一个环节出现等待,都可能造成最终显示延迟。

例如,某个监控系统每隔 5 秒调用一次 REST API。即使 API 能够快速返回最新报价,如果价格刚好在两次请求之间发生变化,应用也只能等到下一次请求才能获取新数据。

在请求时间稳定、行情变化时机近似随机的情况下,这段轮询等待时间可能接近 0–5 秒,平均约为 2.5 秒。这还没有计算 HTTP 网络往返和服务端处理时间。

更重要的是,REST 查询通常返回请求时的最新数据快照,并不意味着能够获得两次请求之间的每一次价格变化。

因此,分析美股行情延迟时,需要区分三个时间:

  • tick_time:行情消息携带的事件时间。
  • received_at:应用服务器实际收到消息的时间。
  • rendered_at:前端完成行情展示的时间。
    将这三个时间分别记录,才能判断问题主要发生在行情传输,还是应用自身的处理环节。

需要注意,计算行情事件时间与本地接收时间之间的差值时,应先确认时间戳单位和时区,并保持服务器时钟同步。对于服务器内部的处理耗时,可以使用单调时钟测量,避免系统时间调整影响结果。

REST API和WebSocket应该怎么选

REST 和 WebSocket 并不是相互替代的关系,它们适合不同的数据获取需求。

对比维度REST APIWebSocket
数据获取方式客户端主动请求服务端主动推送
连接方式独立 HTTP 请求持续连接
更新时机请求发出后获取数据订阅后接收新消息
主要用途最新报价查询、历史 K 线实时 Tick、盘口更新
主要限制轮询间隔可能造成等待需要维护连接和订阅状态

REST API 适合按需获取行情。

例如,用户打开 AAPL.US 股票详情页时,应用可以调用 REST API 获取最新报价,或者查询历史 K 线初始化走势图。

这种方式不需要长期维护连接,接入逻辑相对简单,也方便将行情查询整合到现有后端服务中。

但如果应用需要持续跟踪数十只股票,采用高频轮询就会增加请求数量。请求频率还受到 API 套餐调用限制的影响。即使不断缩短轮询间隔,也无法保证每一次中间价格变化都被获取。

WebSocket 更适合连续行情更新。

WebSocket 建立连接后,客户端发送订阅请求,服务端便可以在有符合订阅条件的新行情时主动推送。

例如,一个美股监控面板同时订阅 AAPL.US、MSFT.US 和 NVDA.US,不需要为每只股票反复发起 HTTP 请求,而是可以通过持续连接接收对应的逐笔成交消息。

这减少了重复请求的开销,也省去了轮询等待时间。

不过,WebSocket 并不意味着没有延迟。行情上游更新、网络路由、消息排队以及前端渲染仍然会影响最终显示效果。它解决的是数据交付机制的问题,而不是消除整个数据链路中的所有延迟。

使用REST初始化行情 再通过WebSocket持续更新

对于需要同时展示历史行情和实时价格的应用,通常没有必要只选择一种接口。

更实用的方案是让 REST 和 WebSocket 分别承担不同任务。

美股实时行情数据流
美股实时行情数据流

实际接入时,REST API 可以负责首次加载股票信息和历史行情,WebSocket 则负责后续的实时成交更新。

例如,开发者可以先获取 AAPL.US 最近的历史 K 线,再订阅该股票的实时 Tick 数据。收到新成交消息后,应用更新最新价格,并根据业务需求处理对应的图表展示。

这里还有一个容易忽略的问题:WebSocket 断开后,重新连接并不代表断线期间的数据已经自动补齐。

重新连接成功后,应用应该重新发送完整订阅列表,并通过 REST 获取最新快照,校准当前显示状态。如果业务要求完整保留断线期间的每一笔 Tick,还需要具备相应的历史逐笔补齐数据来源,不能把最新报价查询当成完整 Tick 历史回放。

使用AllTick订阅美股实时行情

对于需要接入美股逐笔成交行情的开发者,AllTick 提供独立的股票 WebSocket 数据接口。

美股代码采用带市场后缀的格式,例如 AAPL.US、MSFT.US 和 NVDA.US。股票和外汇、加密货币等品种使用不同的 WebSocket 网关,接入时不能混用。

以订阅美股最新成交数据为例,主要涉及以下协议:

操作cmd_id作用
成交订阅请求22004提交股票订阅列表
成交订阅应答22005确认订阅请求
成交行情推送22998接收实时 Tick
心跳请求22000维持连接
心跳应答22001确认心跳

这些协议可以在 AllTick 官方 WebSocket 接入文档中核对。

下面使用 Python 展示一个基本的美股实时订阅实现。示例包含订阅确认、心跳以及连接关闭后的重新连接。

安装依赖:

text
pip install websocket-client

配置 API Token 后运行:

text
import os
import json
import time
import threading
from datetime import datetime, timezone

import websocket

TOKEN = os.environ["ALLTICK_API_TOKEN"]

WS_URL = (
    "wss://quote.alltick.co/"
    "quote-stock-b-ws-api?token=" + TOKEN
)

SYMBOLS = [
    {"code": "AAPL.US"},
    {"code": "MSFT.US"},
    {"code": "NVDA.US"}
]


def run_connection():
    heartbeat_stop = threading.Event()
    heartbeat_started = threading.Event()

    def send_heartbeat(ws):
        while not heartbeat_stop.wait(10):
            if not ws.sock or not ws.sock.connected:
                return

            heartbeat = {
                "cmd_id": 22000,
                "seq_id": 2,
                "trace": "heartbeat",
                "data": {}
            }

            ws.send(json.dumps(heartbeat))

    def on_open(ws):
        subscribe = {
            "cmd_id": 22004,
            "seq_id": 1,
            "trace": "us_stock_sub",
            "data": {
                "symbol_list": SYMBOLS
            }
        }

        ws.send(json.dumps(subscribe))
        print("Subscription request sent")

    def on_message(ws, message):
        try:
            response = json.loads(message)
        except json.JSONDecodeError:
            print("Invalid JSON message")
            return

        cmd_id = response.get("cmd_id")

        # Check subscription response
        if cmd_id == 22005:
            if response.get("ret") == 200:
                print("Subscription confirmed")

                if not heartbeat_started.is_set():
                    heartbeat_started.set()

                    threading.Thread(
                        target=send_heartbeat,
                        args=(ws,),
                        daemon=True
                    ).start()
            else:
                print("Subscription failed:", response)

        # Receive real-time trade updates
        elif cmd_id == 22998:
            tick = response.get("data", {})

            received_at = datetime.now(
                timezone.utc
            ).isoformat(timespec="milliseconds")

            print({
                "symbol": tick.get("code"),
                "price": tick.get("price"),
                "tick_time": tick.get("tick_time"),
                "sequence": tick.get("seq"),
                "received_at": received_at
            })

    def on_error(ws, error):
        print("WebSocket error:", error)

    def on_close(ws, status_code, message):
        heartbeat_stop.set()
        print("Connection closed:", status_code)

    ws = websocket.WebSocketApp(
        WS_URL,
        on_open=on_open,
        on_message=on_message,
        on_error=on_error,
        on_close=on_close
    )

    ws.run_forever()
    heartbeat_stop.set()


# Reconnect and resubscribe after disconnection
while True:
    try:
        run_connection()
    except KeyboardInterrupt:
        print("Application stopped")
        break
    except Exception as error:
        print("Connection failed:", error)

    time.sleep(3)

这段代码主要处理三个环节。

首先,建立股票专用 WebSocket 连接,并发送 22004 成交订阅请求。服务端返回 22005 且状态正常后,才启动应用层心跳线程。

其次,收到 22998 消息时,提取股票代码、成交价格、行情时间戳和序列号,同时记录本地接收时间。这些信息可以用于后续的延迟监控。

最后,如果连接关闭,程序会重新连接,并在 on_open 中重新提交订阅列表。

生产环境还应增加退避重连、心跳响应超时检测、订阅失败告警、消息缓存和日志持久化。示例中的固定 3 秒重连间隔仅用于展示基本流程,不适合直接作为大规模生产系统的完整容错策略。

还有两个与 AllTick 接入直接相关的限制需要注意:

  • 同一 WebSocket 再次发送订阅请求时,会覆盖之前的订阅列表。增加股票时,需要将所有仍然需要订阅的代码一起提交。
  • WebSocket 不支持 K 线推送。如果应用需要历史 K 线或最新 K 线,应通过 HTTP/REST 接口获取,而不是等待 WebSocket 推送。

判断美股行情延迟 应该检查哪些指标

接口连接成功只是接入的开始。对于长期运行的行情监控系统,更重要的是观察数据是否持续、及时地到达客户端。

建议重点检查三个方面。

行情时间戳与消息接收时间

记录每条行情的 tick_time 和应用服务器接收时间。如果行情时间持续前进,但消息接收时间明显滞后,需要进一步检查网络和服务端处理环节。计算差值前,必须确认时间戳格式、时区和服务器时钟。

消息处理与页面更新时间

如果服务器已经及时收到消息,但前端价格仍然没有变化,问题可能出在消息队列积压、客户端状态更新或页面渲染。可以分别记录消息接收和前端渲染时间,避免把应用内部处理延迟误判成行情源延迟。

订阅状态与套餐限制

检查当前订阅的股票代码是否完整,WebSocket 是否正常维持连接,以及套餐是否支持对应的产品数量和连接数。

例如,AllTick 的 All US Stocks 套餐当前列出约 11,000 只美股、10 个 WebSocket 连接,以及每分钟 1,200 次 API 调用。对于需要覆盖大规模美股品种的应用,选择套餐时应同时考虑代码覆盖范围、连接数量和请求频率。

AllTick 股票 API 产品页面目前展示约 150ms 的延迟参考指标。开发者在实际部署时,仍应根据服务器所在区域、网络环境和客户端处理情况进行端到端测试,不能直接将产品页面的指标理解为所有用户环境下的固定显示延迟。

对于以实时行情展示为主要需求的系统,REST 负责初始化和按需查询,WebSocket 负责持续接收成交更新,是一种更容易维护的数据接入方式。关键不在于单纯提高请求频率,而在于让数据获取机制与应用的实时更新需求相匹配。

正在开发美股行情监控系统的团队,可以先查看 AllTick 股票 API 产品介绍,再根据业务需求阅读 REST API 官方文档 和 WebSocket 接入教程,使用实际订阅品种验证行情更新和连接稳定性。

立即开始接入市场数据

几秒内生成免费 API 密钥,通过一个端点连接所有市场。