# WebSocket Testing Guide - OrbiQuant Trading Platform ## Overview The OrbiQuant backend now supports real-time market data via WebSocket, powered by direct integration with Binance WebSocket streams. This guide explains how to test and use the WebSocket API. ## WebSocket Endpoint ``` ws://localhost:3000/ws ``` For production: ``` wss://your-domain.com/ws ``` ## Authentication (Optional) To access private channels (portfolio, orders, user-specific data), include a JWT token in the query string: ``` ws://localhost:3000/ws?token=YOUR_JWT_TOKEN ``` Public market data channels do not require authentication. ## Message Format ### Client to Server All messages must be valid JSON with a `type` field: ```json { "type": "subscribe", "channels": ["price:BTCUSDT"] } ``` ### Server to Client Server responses include a `type`, optional `channel`, and `timestamp`: ```json { "type": "price", "channel": "price:BTCUSDT", "data": { "symbol": "BTCUSDT", "price": 97523.45, "change24h": 2345.67, "changePercent24h": 2.47, "high24h": 98500.00, "low24h": 95000.00, "volume24h": 12345.67, "timestamp": 1701806400000 }, "timestamp": "2024-12-06T12:00:00.000Z" } ``` ## Available Channels ### 1. Price Updates (`price:`) Real-time price updates for a specific symbol (via Binance ticker stream). **Subscribe:** ```json { "type": "subscribe", "channels": ["price:BTCUSDT"] } ``` **Data received:** ```json { "type": "price", "channel": "price:BTCUSDT", "data": { "symbol": "BTCUSDT", "price": 97523.45, "change24h": 2345.67, "changePercent24h": 2.47, "high24h": 98500.00, "low24h": 95000.00, "volume24h": 12345.67, "timestamp": 1701806400000 } } ``` ### 2. Ticker Updates (`ticker:`) Full 24h ticker statistics (bid, ask, volume, etc.). **Subscribe:** ```json { "type": "subscribe", "channels": ["ticker:ETHUSDT"] } ``` **Data received:** ```json { "type": "ticker", "channel": "ticker:ETHUSDT", "data": { "symbol": "ETHUSDT", "price": 3650.00, "bid": 3649.50, "ask": 3650.50, "volume": 123456.78, "change": 125.50, "changePercent": 3.56, "high": 3700.00, "low": 3500.00, "open": 3524.50, "previousClose": 3524.50, "timestamp": "2024-12-06T12:00:00.000Z" } } ``` ### 3. Klines/Candlesticks (`klines::`) Real-time candlestick data at specified intervals. **Intervals:** `1m`, `3m`, `5m`, `15m`, `30m`, `1h`, `2h`, `4h`, `6h`, `12h`, `1d`, `3d`, `1w`, `1M` **Subscribe:** ```json { "type": "subscribe", "channels": ["klines:BTCUSDT:1m"] } ``` **Data received:** ```json { "type": "kline", "channel": "klines:BTCUSDT:1m", "data": { "symbol": "BTCUSDT", "interval": "1m", "time": 1701806400000, "open": 97500.00, "high": 97600.00, "low": 97400.00, "close": 97523.45, "volume": 123.45, "isFinal": false, "timestamp": "2024-12-06T12:00:00.000Z" } } ``` **Note:** `isFinal: true` indicates the candle is closed and will not change. ### 4. Trades (`trades:`) Individual trade executions as they happen. **Subscribe:** ```json { "type": "subscribe", "channels": ["trades:BTCUSDT"] } ``` **Data received:** ```json { "type": "trade", "channel": "trades:BTCUSDT", "data": { "symbol": "BTCUSDT", "price": 97523.45, "quantity": 0.5, "side": "buy", "timestamp": "2024-12-06T12:00:00.000Z" } } ``` ### 5. Depth/Order Book (`depth:`) Order book depth updates (top 10 levels by default). **Subscribe:** ```json { "type": "subscribe", "channels": ["depth:BTCUSDT"] } ``` **Data received:** ```json { "type": "depth", "channel": "depth:BTCUSDT", "data": { "symbol": "BTCUSDT", "bids": [ [97520.00, 1.5], [97519.00, 2.3] ], "asks": [ [97521.00, 0.8], [97522.00, 1.2] ], "timestamp": "2024-12-06T12:00:00.000Z" } } ``` ### 6. ML Signals (`signals:`) AI-powered trading signals (requires backend ML service). **Subscribe:** ```json { "type": "subscribe", "channels": ["signals:BTCUSDT"] } ``` ## Client Messages ### Subscribe ```json { "type": "subscribe", "channels": ["price:BTCUSDT", "ticker:ETHUSDT", "klines:SOLUSDT:5m"] } ``` ### Unsubscribe ```json { "type": "unsubscribe", "channels": ["price:BTCUSDT"] } ``` ### Ping (Keepalive) ```json { "type": "ping" } ``` **Response:** ```json { "type": "pong", "timestamp": "2024-12-06T12:00:00.000Z" } ``` ## Testing Tools ### 1. Using `wscat` (Node.js) Install: ```bash npm install -g wscat ``` Connect: ```bash wscat -c ws://localhost:3000/ws ``` Send messages: ``` > {"type":"subscribe","channels":["price:BTCUSDT"]} < {"type":"subscribed","channel":"price:BTCUSDT","timestamp":"..."} < {"type":"price","channel":"price:BTCUSDT","data":{...}} ``` ### 2. Using `websocat` (Rust) Install: ```bash # macOS brew install websocat # Linux cargo install websocat ``` Connect: ```bash websocat ws://localhost:3000/ws ``` ### 3. Using Browser JavaScript ```html WebSocket Test

OrbiQuant WebSocket Test

``` ### 4. Using Python ```python import asyncio import websockets import json async def test_websocket(): uri = "ws://localhost:3000/ws" async with websockets.connect(uri) as websocket: # Subscribe to channels await websocket.send(json.dumps({ "type": "subscribe", "channels": ["price:BTCUSDT", "klines:BTCUSDT:1m"] })) # Listen for messages while True: message = await websocket.recv() data = json.loads(message) print(f"Received: {data['type']}") if 'data' in data: print(f" Data: {data['data']}") asyncio.run(test_websocket()) ``` ## WebSocket Stats Endpoint Check WebSocket server statistics: ```bash curl http://localhost:3000/api/v1/ws/stats ``` **Response:** ```json { "success": true, "data": { "connectedClients": 5, "activeChannels": ["price:BTCUSDT", "klines:ETHUSDT:1m"], "quoteStreams": 0, "signalStreams": 2, "binanceStreams": 3, "binanceActiveStreams": ["btcusdt@ticker", "ethusdt@kline_1m"], "priceCache": 2 } } ``` ## Common Symbols - `BTCUSDT` - Bitcoin/USDT - `ETHUSDT` - Ethereum/USDT - `BNBUSDT` - Binance Coin/USDT - `SOLUSDT` - Solana/USDT - `XRPUSDT` - Ripple/USDT - `DOGEUSDT` - Dogecoin/USDT - `ADAUSDT` - Cardano/USDT - `AVAXUSDT` - Avalanche/USDT ## Error Handling ### Connection Errors If connection fails, check: 1. Backend server is running on port 3000 2. WebSocket path is `/ws` 3. No firewall blocking the connection ### Subscription Errors ```json { "type": "error", "channel": "price:INVALID", "data": { "message": "Failed to fetch quote for INVALID" } } ``` ### Authentication Errors For private channels without valid token: ```json { "type": "error", "channel": "portfolio:user123", "data": { "message": "Authentication required for this channel" } } ``` ## Best Practices 1. **Heartbeat**: Send ping every 30 seconds to keep connection alive 2. **Reconnection**: Implement exponential backoff for reconnections 3. **Subscription Limit**: Don't subscribe to too many symbols at once (max 50 per client) 4. **Clean Disconnect**: Unsubscribe before closing connection 5. **Error Handling**: Always handle `error` messages from server ## Example: Complete Trading Dashboard ```javascript class TradingDashboard { constructor() { this.ws = null; this.subscriptions = new Set(); this.reconnectAttempts = 0; this.maxReconnectAttempts = 5; } connect() { this.ws = new WebSocket('ws://localhost:3000/ws'); this.ws.onopen = () => { console.log('Connected to trading server'); this.reconnectAttempts = 0; this.resubscribe(); }; this.ws.onmessage = (event) => { const msg = JSON.parse(event.data); this.handleMessage(msg); }; this.ws.onclose = () => { console.log('Disconnected from server'); this.attemptReconnect(); }; this.ws.onerror = (error) => { console.error('WebSocket error:', error); }; // Heartbeat setInterval(() => this.ping(), 30000); } subscribe(channel) { this.subscriptions.add(channel); if (this.ws?.readyState === WebSocket.OPEN) { this.ws.send(JSON.stringify({ type: 'subscribe', channels: [channel] })); } } unsubscribe(channel) { this.subscriptions.delete(channel); if (this.ws?.readyState === WebSocket.OPEN) { this.ws.send(JSON.stringify({ type: 'unsubscribe', channels: [channel] })); } } resubscribe() { if (this.subscriptions.size > 0) { this.ws.send(JSON.stringify({ type: 'subscribe', channels: Array.from(this.subscriptions) })); } } ping() { if (this.ws?.readyState === WebSocket.OPEN) { this.ws.send(JSON.stringify({ type: 'ping' })); } } attemptReconnect() { if (this.reconnectAttempts >= this.maxReconnectAttempts) { console.error('Max reconnect attempts reached'); return; } const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000); this.reconnectAttempts++; console.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`); setTimeout(() => this.connect(), delay); } handleMessage(msg) { switch (msg.type) { case 'connected': console.log('Server says: connected', msg.data); break; case 'price': this.updatePrice(msg.data); break; case 'kline': this.updateChart(msg.data); break; case 'ticker': this.updateTicker(msg.data); break; case 'trade': this.addTrade(msg.data); break; case 'error': console.error('Server error:', msg.data); break; case 'pong': // Heartbeat acknowledged break; default: console.log('Unknown message type:', msg.type); } } updatePrice(data) { console.log(`Price update: ${data.symbol} = $${data.price}`); // Update UI } updateChart(data) { console.log(`Kline update: ${data.symbol} ${data.interval}`); // Update chart } updateTicker(data) { console.log(`Ticker update: ${data.symbol}`); // Update ticker display } addTrade(data) { console.log(`New trade: ${data.symbol} ${data.side} ${data.quantity} @ ${data.price}`); // Add to trades list } disconnect() { if (this.ws) { this.ws.close(); this.ws = null; } } } // Usage const dashboard = new TradingDashboard(); dashboard.connect(); dashboard.subscribe('price:BTCUSDT'); dashboard.subscribe('klines:ETHUSDT:1m'); dashboard.subscribe('trades:SOLUSDT'); ``` ## Troubleshooting ### No Data Received 1. Check if Binance API is accessible from your server 2. Verify symbol format (must be uppercase, e.g., `BTCUSDT`) 3. Check backend logs for connection errors ### High Latency 1. Ensure server is geographically close to Binance servers 2. Check network connection quality 3. Reduce number of subscriptions ### Disconnections 1. Implement heartbeat/ping mechanism 2. Check server logs for errors 3. Verify no rate limiting from Binance ## Support For issues or questions: - Check backend logs: `npm run dev` (shows real-time logs) - WebSocket stats endpoint: `GET /api/v1/ws/stats` - Server health: `GET /health` --- **Last Updated:** December 6, 2024 **Backend Version:** 0.1.0 **WebSocket Protocol:** RFC 6455