WebSocket 基本信息 — 现货
ZTDX 现货 WebSocket 的连接指南、鉴权说明、通道列表及协议规则。
基础地址
| 环境 | WebSocket 地址 |
|---|---|
| 测试网 (Sepolia) | wss://api-sepolia.p99.world/ws |
| 主网 | (尚未部署) |
现货 WebSocket 与合约 WebSocket 共用同一端点。单个连接可同时订阅任意组合的现货与合约通道。
连接说明
- 所有消息均为 JSON 文本帧(RFC 6455)。
- 每隔 30 秒发送一次
ping以保持连接。 - 单个连接支持多个并发订阅。
- 未知现货通道会返回
INVALID_CHANNEL错误;连接本身保持不断开。
连接示例
- JavaScript
- Python
const ws = new WebSocket('wss://api-sepolia.p99.world/ws');
ws.onopen = () => {
console.log('Connected');
// Public channel — no auth needed
ws.send(JSON.stringify({
type: 'subscribe',
channel: 'spot:depth:DFUSDT',
}));
// Keep-alive
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'ping' }));
}
}, 30000);
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
console.log('Received:', msg);
};
ws.onerror = (err) => console.error('WS error:', err);
ws.onclose = () => console.log('Disconnected');
import asyncio
import json
import websockets
async def main():
uri = 'wss://api-sepolia.p99.world/ws'
async with websockets.connect(uri) as ws:
print('Connected')
# Public channel — no auth needed
await ws.send(json.dumps({
'type': 'subscribe',
'channel': 'spot:depth:DFUSDT',
}))
async def heartbeat():
while True:
await asyncio.sleep(30)
await ws.send(json.dumps({'type': 'ping'}))
asyncio.create_task(heartbeat())
async for message in ws:
msg = json.loads(message)
print('Received:', msg)
asyncio.run(main())
消息格式
客户端 → 服务端
type | 描述 | 需鉴权 |
|---|---|---|
auth | 通过 EIP-712 签名或 listenKey 进行鉴权 | — |
auth_token | 通过 JWT Token 进行鉴权 | — |
subscribe | 订阅通道(可附带内联 token) | 仅私有通道 |
unsubscribe | 取消订阅通道 | 否 |
ping | 心跳 | 否 |
服务端 → 客户端
type | 描述 |
|---|---|
auth_result | 鉴权结果(success: true/false) |
subscribed | 订阅确认 |
unsubscribed | 取消订阅确认 |
pong | ping 的响应 |
error | 错误帧(code + message) |
spot_depth_snapshot | 完整订单簿快照(订阅 spot:depth:* 时推送) |
spot_depth_diff | 自上次更新以来的变化档位(差分) |
spot_trade | 单笔公开成交 |
spot_ticker | 24 小时滚动统计 |
spot_kline_snapshot | 最新 K 线(订阅 spot:kline:* 时推送) |
spot_kline_update | 当前周期内的实时 OHLCV 更新 |
spot_user_order | 已鉴权用户的订单生命周期事件 |
spot_user_balance | 已鉴权用户的余额行变更 |
所有推送帧均按以下结构封装:
{
"type": "spot_xxx",
"channel": "spot:depth:DFUSDT",
"data": { ... }
}
鉴权
鉴权仅对私有通道(spot:user:orders、spot:user:balances)必须。公开行情通道无需鉴权。
支持三种方 式(与合约 WebSocket 完全相同 — 完整载荷格式参见合约 WebSocket 基本信息)。最简单的是 JWT:
JWT(auth_token)
{ "type": "auth_token", "token": "eyJhbGciOiJIUzI1..." }
服务端响应:
{ "type": "auth_result", "success": true, "message": null }
失败时:
{ "type": "auth_result", "success": false, "message": "Invalid or expired token" }
EIP-712 签名(auth)
{
"type": "auth",
"address": "0xYourWalletAddress",
"signature": "0x...",
"timestamp": 1778400000
}
timestamp 为 UNIX 秒,须在服务器时间 5 分钟以内。
listenKey(auth)
{ "type": "auth", "listenKey": "a1b2c3d4e5f6..." }
通过 POST /fapi/v1/listenKey 获取 listenKey。长连接的 WebSocket 等同于隐式 keepalive — socket 保持开启时无需主动调用 PUT /fapi/v1/listenKey。
在 subscribe 中附带 Token
{ "type": "subscribe", "channel": "spot:user:orders", "token": "eyJhbGciOiJIUzI1..." }
服务端会在处理订阅前自动完成鉴权。
通道概览
| 通道 | 需鉴权 | 订阅时发快照 | 实时更新 |
|---|---|---|---|
spot:depth:{symbol} | — | 是 — 前 1000 档 | 每次订单簿变动推送差分 |
spot:trade:{symbol} | — | — | 每笔公开成交推送一条 |
spot:ticker:{symbol} | — | 是 — 当前 24 小时行情 | 每次成交 + 每 60 秒重算 |
spot:kline:{symbol}:{interval} | — | 是 — 最新 K 线 | 当前区间内每次成交后推送 |
spot:user:orders | 需鉴权 | — | 下单 / 成交 / 撤单 / 拒单 |
spot:user:balances | 需鉴权 | — | 每个受影响的 (token) 行 |
{symbol} 在 MVP 阶段为 DFUSDT。{interval} ∈ 1m / 5m / 15m / 1h / 4h / 1d — 参见 Enums。
订阅 / 取消订阅 / Ping
订阅
{ "type": "subscribe", "channel": "spot:depth:DFUSDT" }
响应:
{ "type": "subscribed", "channel": "spot:depth:DFUSDT" }
若该通道有快照,将在 subscribed 确认后立即推送。
取消订阅
{ "type": "unsubscribe", "channel": "spot:depth:DFUSDT" }
响应:
{ "type": "unsubscribed", "channel": "spot:depth:DFUSDT" }
Ping / Pong
{ "type": "ping" }
响应:
{ "type": "pong" }