跳到主要内容

WebSocket 行情推送 (WebSocket)

AXBlade 提供实时全量数据推送服务,通过 WebSocket 连接获取市场深度、行情及个人账户变动通知。


1. 连接地址

环境WebSocket URL
主网wss://api.axblade.io/ws
测试网wss://testnet.axblade.io/ws
本地开发ws://localhost:8080/ws

连接建立后,需要进行心跳协议维护以保持连接:

  • Ping: 客户端发送 {"type": "ping"}
  • Pong: 服务器返回 {"type": "pong"}

2. 身份认证 (Auth)

对于需要权限的频道(如持仓、订单更新),必须在订阅前进行认证。

方式一:发送 JWT Token

{
"type": "auth_token",
"token": "<your_jwt_token>"
}

方式二:EIP-712 签名认证

{
"type": "auth",
"address": "0x...",
"signature": "0x...",
"timestamp": 1702400000
}

认证响应

{
"type": "auth_result",
"success": true,
"message": null
}

3. 订阅频道 (Subscription)

订阅

{"type": "subscribe", "channel": "ticker:HYPEUSDT"}

取消订阅

{"type": "unsubscribe", "channel": "ticker:HYPEUSDT"}

订阅响应

{
"type": "subscribed",
"channel": "ticker:HYPEUSDT"
}

4. 公开频道

行情 (Ticker)

{"type": "subscribe", "channel": "ticker:HYPEUSDT"}

消息格式:

{
"type": "ticker",
"symbol": "HYPEUSDT",
"last_price": "25.45",
"mark_price": "25.44",
"index_price": "25.43",
"price_change_24h": "0.50",
"price_change_percent_24h": "2.00",
"high_24h": "26.00",
"low_24h": "24.50",
"volume_24h": "1000000.00",
"volume_24h_usd": "25450000.00",
"open_interest_long": "5000000",
"open_interest_short": "4500000",
"funding_rate_long_1h": "-0.0010%",
"funding_rate_short_1h": "+0.0010%"
}

更新间隔: 每 2 秒

订单簿 (Orderbook)

{"type": "subscribe", "channel": "orderbook:HYPEUSDT"}

消息格式:

{
"type": "orderbook",
"symbol": "HYPEUSDT",
"bids": [
{"price": "25.45", "size": "100.5"},
{"price": "25.44", "size": "200.3"}
],
"asks": [
{"price": "25.46", "size": "150.2"},
{"price": "25.47", "size": "180.1"}
],
"timestamp": 1704067200000
}

更新间隔: 每 500ms 或有变化时

最新成交 (Trades)

{"type": "subscribe", "channel": "trades:HYPEUSDT"}

消息格式:

{
"type": "trade",
"id": "1704067200000-abc123",
"symbol": "HYPEUSDT",
"price": "25.45",
"amount": "10.5",
"side": "buy",
"timestamp": 1704067200000
}

K 线 (K-Line)

{"type": "subscribe", "channel": "kline:HYPEUSDT:1m"}

支持周期: 1m, 5m, 15m, 30m, 1h, 4h, 1d

消息格式:

{
"type": "kline",
"channel": "kline:HYPEUSDT:1m",
"data": {
"time": 1704067260,
"open": "25.45",
"high": "25.48",
"low": "25.44",
"close": "25.47",
"volume": "500.2",
"is_final": false
}
}

5. 私有频道 (需认证)

持仓变动 (Positions)

{"type": "subscribe", "channel": "positions"}

消息格式:

{
"type": "position",
"id": "550e8400-e29b-41d4-a716-446655440000",
"symbol": "HYPEUSDT",
"side": "long",
"size": "10.0",
"entry_price": "25.50",
"mark_price": "26.00",
"liquidation_price": "23.10",
"unrealized_pnl": "5.00",
"leverage": 10,
"margin": "25.50",
"updated_at": 1704067200000,
"event": "updated"
}

事件类型:

  • opened - 新开仓
  • updated - 仓位更新
  • closed - 平仓
  • liquidated - 强制平仓

订单状态变动 (Orders)

{"type": "subscribe", "channel": "orders"}

消息格式:

{
"type": "order",
"id": "550e8400-e29b-41d4-a716-446655440000",
"symbol": "HYPEUSDT",
"side": "buy",
"order_type": "limit",
"price": "25.50",
"amount": "10.0",
"filled_amount": "5.0",
"status": "partially_filled",
"updated_at": 1704067200000,
"event": "filled"
}

余额变动 (Balance)

{"type": "subscribe", "channel": "balance"}

消息格式:

{
"type": "balance",
"token": "0x572E474C3Cf364D085760784F938A1Aa397a8B9b",
"symbol": "USDT",
"available": "1000.00",
"frozen": "100.00",
"total": "1100.00"
}

6. 错误消息

{
"type": "error",
"code": "AUTH_REQUIRED",
"message": "Authentication required for private channels"
}
错误码说明
INVALID_MESSAGEJSON 解析失败
AUTH_REQUIRED私有频道需要认证
INVALID_SIGNATUREEIP-712 签名验证失败
TIMESTAMP_EXPIRED认证时间戳过期 (5分钟内有效)
INVALID_CHANNEL未知的频道格式

7. 连接限制

限制
最大订阅数/连接10
消息速率限制100 条/秒
连接超时30 秒 (需心跳维持)

8. TypeScript 示例

class AXBladeWebSocket {
private ws: WebSocket;
private jwtToken: string;
private subscriptions: Set<string> = new Set();

constructor(url: string, jwtToken: string) {
this.jwtToken = jwtToken;
this.ws = new WebSocket(url);
this.setupHandlers();
}

private setupHandlers() {
this.ws.onopen = () => {
console.log('Connected');
this.authenticate();
};

this.ws.onmessage = (event) => {
const message = JSON.parse(event.data);
this.handleMessage(message);
};

this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
};

this.ws.onclose = () => {
console.log('Disconnected');
};
}

private authenticate() {
this.send({
type: 'auth_token',
token: this.jwtToken
});
}

private handleMessage(message: any) {
switch (message.type) {
case 'auth_result':
if (message.success) {
console.log('Authenticated');
this.resubscribe();
} else {
console.error('Auth failed:', message.message);
}
break;
case 'subscribed':
console.log('Subscribed to:', message.channel);
break;
case 'ticker':
console.log('Ticker:', message.symbol, message.last_price);
break;
case 'orderbook':
console.log('Orderbook:', message.symbol);
break;
case 'trade':
console.log('Trade:', message.symbol, message.price);
break;
case 'position':
console.log('Position:', message.symbol, message.unrealized_pnl);
break;
case 'order':
console.log('Order:', message.id, message.status);
break;
case 'balance':
console.log('Balance:', message.symbol, message.available);
break;
case 'error':
console.error('Error:', message.code, message.message);
break;
}
}

subscribe(channel: string) {
this.subscriptions.add(channel);
this.send({ type: 'subscribe', channel });
}

unsubscribe(channel: string) {
this.subscriptions.delete(channel);
this.send({ type: 'unsubscribe', channel });
}

private resubscribe() {
for (const channel of this.subscriptions) {
this.send({ type: 'subscribe', channel });
}
}

private send(message: object) {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(message));
}
}

startHeartbeat(intervalMs: number = 15000) {
setInterval(() => {
this.send({ type: 'ping' });
}, intervalMs);
}

close() {
this.ws.close();
}
}

// 使用示例
const ws = new AXBladeWebSocket('wss://api.axblade.io/ws', jwtToken);

// 订阅公开频道
ws.subscribe('ticker:HYPEUSDT');
ws.subscribe('orderbook:HYPEUSDT');
ws.subscribe('kline:HYPEUSDT:1m');

// 订阅私有频道 (需认证)
ws.subscribe('positions');
ws.subscribe('orders');
ws.subscribe('balance');

// 启动心跳
ws.startHeartbeat();