问题场景

我在公司负责投研系统的行情数据模块,最近有一个新的需求:需要同时监控多只热门美股的实时逐笔成交,并把数据分发给下游的风控和策略服务。一开始我沿用了基于 REST 的轮询方案,但很快遇到两个棘手的麻烦:一是轮询频率稍高就触发 API 限流,二是两次请求之间的时间盲区导致丢单。这不是我想要的“实时”。

技术选型考量

替换方案必须满足三个条件:低延迟、全量推送、易集成。HTTP 轮询和长轮询都不达标,Server-Sent Events 虽然推送,但兼容性和控制力不如 WebSocket。最终我选择了 WebSocket 协议,并找了一个稳定、文档清晰的数据源做对接——我使用了 AllTick 的实时行情接口,它支持通过 WebSocket 订阅多只股票的 tick 流,推送格式为 JSON,容易解析。

最小的可行示例(MVP)

为了让团队快速验证可行性,我写了一个轻量级的 Python 脚本,完成连接、订阅和打印。代码如下:

import websocket
import json

def on_message(ws, message):
    data = json.loads(message)
    # 打印逐笔成交价格和量
    print(f"{data['symbol']} 价格: {data['price']} 成交量: {data['volume']}")

def on_open(ws):
    # 批量订阅活跃美股
    symbols = ["AAPL", "TSLA", "AMZN"]
    for symbol in symbols:
        ws.send(json.dumps({
            "action": "subscribe",
            "symbol": symbol
        }))

ws = websocket.WebSocketApp("wss://apis.alltick.co/ws/stock-tick",
                            on_message=on_message,
                            on_open=on_open)
ws.run_forever()

运行后,三只股票的每一笔成交都在毫秒级内推送到控制台。这也让团队对 WebSocket 方案的实时性有了直观感受。

数据落地与消费

光看控制台肯定不够,我们做了标准化处理:

  • 接入层:用 Python asyncio 将 WebSocket 推送解析后写入 Redis Pub/Sub,解耦生产与消费。
  • 存储层:按日期分表存入 PostgreSQL,每笔记录包含 symbol、价格、成交量、成交时间、买卖方向等。
  • 服务层:后端拉取 Redis 实时流,计算分时指标并通过 WebSocket 二次分发给前端组件。

避坑指南

  • 心跳保活:一定要开启 WebSocket 的 ping/pong 或定时发送心跳包,避免被中间代理关闭。
  • 重连策略:on_close 时执行退避重试,不能立即无限循环重连,防止击穿服务端。
  • 幂等去重:利用 tick 数据自带的 trade_id 做去重,避免统计时一笔成交计算两次。
  • 限流保护:即便是推送模式,也要在客户端做流速控制,以防极端行情下下游服务被冲垮。

总结

从轮询切换到 WebSocket,实时性得到了质的飞跃,也解决了限流困扰。如果你正在为实时行情数据抓取头疼,不妨尝试用 WebSocket 重新设计你的数据入口,投入并不大,但回报是研发效率和信号质量的明显提升。


EmilyLi
1 声望1 粉丝