跳到主要内容

WebSocket 行情推送

状态:已实现。

通过 WebSocket 由服务端推送的行情数据,采用 Binance Spot 的流格式。公开、无需鉴权,以按 IP 的连接数上限而非请求权重进行限流。

端点​

URL用途帧格式
wss://api.rocky.exchange/ws/<stream>单个流裸帧
wss://api.rocky.exchange/stream?streams=<a>/<b>/<c>组合流(以 / 分隔){"stream":"<name>","data":<frame>}

沙盒主机见你的 集成包(Integration Pack)。

可用的流​

流频率页面
<symbol>@depth5、@depth10、@depth20每 250 ms 一次订单簿快照有限档深度信息
<symbol>@trade每笔成交逐笔交易
<symbol>@kline_1m有未收盘 K 线时每 1 秒一次,收盘时另推一次K 线与 Ticker
<symbol>@ticker每 1 秒K 线与 Ticker
<symbol>@depth(增量深度)—空缺

流名​

<symbol>@<kind>,其中 <symbol> 为小写化且保留连字符的市场交易对:

cbtc-usdcb@trade ✔
ceth-cbtc@depth10 ✔
CBTC-USDCB@trade ✖ uppercase anywhere is refused
cbtcusdcb@trade ✖ the hyphen is part of the name
cbtc-usdcb@depth ✖ diff depth is not implemented
cbtc-usdcb@kline_5m ✖ only kline_1m

这是与 Binance 命名唯一一处刻意的不同——Binance 的交易对没有分隔符(btcusdt@trade)。Rocky 保留连字符,因为去掉它会让不同的资产对发生冲突。帧本身携带规范的大写交易对("s":"CBTC-USDCB"),与所有 REST 响应一致。

交易对集合即实时的 exchangeInfo 列表(ledger.markets 中处于 active 状态的现货市场),每 60 秒刷新;已下市的市场在订阅时被拒绝。已下市交易对上已打开的 @depth* 流会被关闭(当连接上的所有流都已关闭时,连接随之结束);已打开的 @trade、@kline_1m 与 @ticker 流则只是不再有数据。

连接治理​

限制值超出时的行为
每连接的流数32(按请求数计,去重前)关闭 1008
每客户端 IP 的并发连接数16(默认值;运营方可配置,豁免 IP 不受限)upgrade 阶段返回 HTTP 429 {"code":-1003,…}——没有 101
服务端 ping 间隔20 秒—
容忍的静默时长60 秒(连续三次未回 pong)服务端关闭连接
缓冲帧数每个流 256 帧,外加每连接 256 帧的队列慢消费者会跳过帧(见下文)
  • 服务端每 20 秒发送一次 WebSocket ping。请以 pong 回应(所有主流客户端库都会自动处理)。任何入站帧——pong、ping 或文本——都算作存活证明。
  • 代理超时为 300 秒,因此一个空闲但持续 ping 的连接可以无限期保持。
  • 停止读取的对端同样处理:某一帧在 60 秒内无法写出时,服务端关闭连接。
  • 跟不上的连接不会对其他订阅者施加背压:它错过的帧会被丢弃,并从当前帧继续。对深度流来说这是正确的恢复方式(过时的订单簿毫无价值);对 @trade 则意味着非常慢的客户端可能错过成交,应通过 REST 对账。

关闭码 1008 的原因​

不合法的订阅会在 upgrade 之后以关闭帧(代码 1008,「policy violation」)拒绝,以便原因可读——否则浏览器客户端只能看到一个不透明的握手失败。

原因文本成因
no streams requested/stream 未带 streams=,或列表为空/全空。
too many streams: N requested, 32 allowed列表超过 32 项。
unknown stream: <name>未知交易对、不支持的类型、大小写错误、列表成员为空,或增量深度/不支持周期的名字。会引用出问题的名字(截断到 96 字节)。一个坏名字会拒绝整个列表。

协议说明​

  • 没有订阅/取消订阅协议。 流列表由 URL 固定。你发送的文本或二进制帧会被忽略(不算错误);要更改流,请打开新连接。
  • 组合列表中的重复名字会被合并;每一帧你只收到一次。
  • 组合流的帧在 stream 中原样回显你订阅时使用的名字。
  • 没有 listenKey / 用户数据流;订单与账户状态只能通过 REST 获取。

示例​

import asyncio, json, websockets # pip install websockets

async def main():
url = "wss://api.rocky.exchange/stream?streams=cbtc-usdcb@depth5/cbtc-usdcb@trade"
async with websockets.connect(url) as ws: # ping/pong handled by the library
async for raw in ws:
msg = json.loads(raw)
print(msg["stream"], msg["data"])

asyncio.run(main())

与 Binance 的差异​

  • 流名为小写带连字符(cbtc-usdcb@trade)。
  • 没有 SUBSCRIBE / UNSUBSCRIBE / LIST_SUBSCRIPTIONS 消息;没有带 id 标记的响应。
  • 没有 @aggTrade、@bookTicker、@miniTicker、!ticker@arr、!miniTicker@arr、@depth / @depth@100ms 增量流、1m 以外的 @kline_<interval>,或 @avgPrice。
  • 没有用户数据流,也没有通过 WebSocket 下单的 /ws-api。
  • 成交 id 为 UUID 字符串。
  • 连接上限为每 IP 16 个(Binance:每 5 分钟 300 个);在 upgrade 阶段以 HTTP 429 拒绝。
  • 深度流为 250 ms 快照(Binance:100 ms / 1000 ms),其 lastUpdateId 是时间戳。