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_MESSAGE | JSON 解析失败 |
AUTH_REQUIRED | 私有频道需要认证 |
INVALID_SIGNATURE | EIP-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();