Strategy Intermediate

WebSocket Real-time Trading Monitor System Development

Sentinel Team · 2026-03-09
WebSocket Real-time Trading Monitor System Development

WebSocket Real-time Trading Monitor System Development

Quick Navigation: This article deeply explores the complete application of WebSocket in trading systems, from Socket.io architecture design to React integration, providing an authoritative guide for cryptocurrency real-time monitoring system development. Estimated reading time: 15 minutes.


Why Do Trading Systems Need WebSocket?

In the world of automated trading, time is money. When Bitcoin prices fluctuate in milliseconds, the latency of HTTP polling can mean missed trading opportunities or unnecessary risks.

According to the WebSocket RFC 6455 specification, WebSocket provides full-duplex, low-latency communication channels, the technical foundation of real-time trading systems.

HTTP Polling vs WebSocket Comparison

| Feature | HTTP Polling | WebSocket | Impact on Trading Systems |

|:---|:---|:---|:---|

| Connection Method | New connection per request | Single long connection | Reduced connection overhead |

| Latency | 100-500ms | 10-50ms | 10x improvement |

| Server Push | Not supported | Native support | Real-time market updates |

| Bandwidth Usage | High (repeated HTTP headers) | Low (data only) | Save 70%+ bandwidth |

| Real-time | Pseudo real-time | True real-time | Critical trading timing |

| Scalability | Poor (connection limited) | Good (supports 10K+ connections) | Support multi-user |

Key Insight: Professional-grade trading systems must use WebSocket. HTTP polling is only suitable for low-frequency data (like position reports updated once per minute).


WebSocket Core Concepts and Protocol

WebSocket Handshake Process

Client                          Server
   │                              │
   │  1. HTTP Upgrade Request      │
   │ ───────────────────────────> │
   │  GET /ws HTTP/1.1            │
   │  Upgrade: websocket          │
   │  Connection: Upgrade         │
   │  Sec-WebSocket-Key: xxx      │
   │                              │
   │  2. Protocol Upgrade Response │
   │ <─────────────────────────── │
   │  HTTP/1.1 101 Switching      │
   │  Upgrade: websocket          │
   │  Sec-WebSocket-Accept: yyy   │
   │                              │
   │  3. WebSocket Connection Established │
   │ <══════════════════════════> │
   │      Full-duplex Data Transmission   │

Advantages of Socket.io

While native WebSocket is already powerful, Socket.io provides additional features needed in production environments:

| Feature | Native WebSocket | Socket.io | Value for Trading Systems |

|:---|:---:|:---:|:---|

| Auto Reconnect | ❌ Manual implementation | ✅ Built-in | Auto recovery when network unstable |

| Fallback | ❌ None | ✅ HTTP long polling | Old browser/firewall compatibility |

| Room Mechanism | ❌ Manual implementation | ✅ Built-in | Trading pair subscription channels |

| Broadcast | ❌ Manual implementation | ✅ Built-in | System announcement push |

| Middleware | ❌ Manual implementation | ✅ Built-in | Auth and permission control |

| Binary Support | ✅ Supported | ✅ Supported | Efficient data transmission |


Trading System WebSocket Architecture Design

Overall Architecture Diagram

┌─────────────────────────────────────────────────────────────┐
│                        Client (React)                        │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
│  │ PriceFeed   │  │ BotMonitor  │  │  NotificationCenter │  │
│  │   Hook      │  │    Hook     │  │       Hook          │  │
│  └──────┬──────┘  └──────┬──────┘  └──────────┬──────────┘  │
│         │                │                    │             │
│         └────────────────┼────────────────────┘             │
│                          │                                   │
│                   ┌──────┴──────┐                           │
│                   │ Socket.io   │                           │
│                   │   Client    │                           │
│                   └──────┬──────┘                           │
└──────────────────────────┼──────────────────────────────────┘
                           │ WebSocket
┌──────────────────────────┼──────────────────────────────────┐
│                     Server (Node.js)                         │
│                   ┌──────┴──────┐                           │
│                   │ Socket.io   │                           │
│                   │   Server    │                           │
│                   └──────┬──────┘                           │
│         ┌────────────────┼────────────────┐                 │
│         │                │                │                 │
│    ┌────┴────┐     ┌────┴────┐     ┌────┴────┐            │
│    │ Price   │     │  Bot    │     │ Notification│         │
│    │ Service │     │ Service │     │   Service   │         │
│    └────┬────┘     └────┬────┘     └─────┬─────┘          │
│         │               │                │                 │
│    ┌────┴────┐     ┌────┴────┐     ┌────┴────┐            │
│    │ Redis   │     │ PostgreSQL│    │  Firebase  │         │
│    │ Pub/Sub │     │  (State)  │    │  (Push)   │         │
│    └─────────┘     └─────────┘    └───────────┘          │
└─────────────────────────────────────────────────────────────┘

Channel Design Principles

// Channel naming conventions
const CHANNELS = {
  // Public channels (no auth required)
  PUBLIC: {
    PRICES: 'price:public',           // Public market data
    ANNOUNCEMENTS: 'announcement',     // System announcements
  },
  
  // User private channels (auth required)
  USER: {
    NOTIFICATIONS: (userId: string) => `user:${userId}:notifications`,
    BALANCE: (userId: string) => `user:${userId}:balance`,
  },
  
  // Bot channels (authorization required)
  BOT: {
    STATUS: (botId: string) => `bot:${botId}:status`,
    TRADES: (botId: string) => `bot:${botId}:trades`,
    POSITIONS: (botId: string) => `bot:${botId}:positions`,
    LOGS: (botId: string) => `bot:${botId}:logs`,
  },
  
  // Trading pair channels (dynamic subscription)
  SYMBOL: {
    TICKER: (symbol: string) => `symbol:${symbol}:ticker`,
    ORDERBOOK: (symbol: string) => `symbol:${symbol}:orderbook`,
    TRADES: (symbol: string) => `symbol:${symbol}:trades`,
  },
};

Socket.io Server Implementation

Basic Architecture

// server/websocket/index.ts
import { Server } from 'socket.io';
import { createAdapter } from '@socket.io/redis-adapter';
import { createClient } from 'redis';

export function createWebSocketServer(httpServer) {
  const io = new Server(httpServer, {
    cors: {
      origin: process.env.FRONTEND_URL,
      credentials: true,
    },
    // Performance tuning
    pingTimeout: 60000,
    pingInterval: 25000,
    transports: ['websocket', 'polling'],
  });
  
  // Redis adapter (multi-server scaling)
  const pubClient = createClient({ url: process.env.REDIS_URL });
  const subClient = pubClient.duplicate();
  io.adapter(createAdapter(pubClient, subClient));
  
  // Middleware: Authentication
  io.use(async (socket, next) => {
    try {
      const token = socket.handshake.auth.token;
      const user = await verifyToken(token);
      socket.data.user = user;
      next();
    } catch (err) {
      next(new Error('Authentication error'));
    }
  });
  
  // Connection handling
  io.on('connection', (socket) => {
    console.log(`Client connected: ${socket.id}`);
    
    // Register event handlers
    registerPriceHandlers(socket);
    registerBotHandlers(socket);
    registerNotificationHandlers(socket);
    
    // Disconnect handling
    socket.on('disconnect', (reason) => {
      console.log(`Client disconnected: ${socket.id}, reason: ${reason}`);
    });
  });
  
  return io;
}

Price Push Service

// server/websocket/handlers/price.ts
export function registerPriceHandlers(socket: Socket) {
  // User subscribes to specific trading pairs
  socket.on('price:subscribe', (symbols: string[]) => {
    symbols.forEach((symbol) => {
      socket.join(`symbol:${symbol}:ticker`);
    });
    
    // Immediately push current prices
    symbols.forEach(async (symbol) => {
      const price = await getLatestPrice(symbol);
      socket.emit('price:update', { symbol, ...price });
    });
  });
  
  // Unsubscribe
  socket.on('price:unsubscribe', (symbols: string[]) => {
    symbols.forEach((symbol) => {
      socket.leave(`symbol:${symbol}:ticker`);
    });
  });
}

// Broadcast when external price service pushes
export function broadcastPriceUpdate(io: Server, symbol: string, data: PriceData) {
  io.to(`symbol:${symbol}:ticker`).emit('price:update', {
    symbol,
    timestamp: Date.now(),
    ...data,
  });
}

Bot Monitoring Service

// server/websocket/handlers/bot.ts
export function registerBotHandlers(socket: Socket) {
  const userId = socket.data.user.id;
  
  // Subscribe to all user's bots
  socket.on('bot:subscribe', async () => {
    const bots = await getUserBots(userId);
    
    bots.forEach((bot) => {
      socket.join(`bot:${bot.id}:status`);
      socket.join(`bot:${bot.id}:trades`);
      socket.join(`bot:${bot.id}:positions`);
    });
    
    socket.emit('bot:subscribed', bots.map((b) => b.id));
  });
  
  // Subscribe to specific bot
  socket.on('bot:subscribe:one', async (botId: string) => {
    // Permission check
    const hasAccess = await checkBotAccess(userId, botId);
    if (!hasAccess) {
      socket.emit('error', { message: 'Access denied' });
      return;
    }
    
    socket.join(`bot:${botId}:status`);
    socket.join(`bot:${botId}:trades`);
    socket.join(`bot:${botId}:positions`);
    socket.join(`bot:${botId}:logs`);
    
    // Push current status
    const status = await getBotStatus(botId);
    socket.emit('bot:status', { botId, ...status });
  });
}

// Broadcast when bot status changes
export function broadcastBotStatus(io: Server, botId: string, status: BotStatus) {
  io.to(`bot:${botId}:status`).emit('bot:status', {
    botId,
    timestamp: Date.now(),
    ...status,
  });
}

// Broadcast on new trade
export function broadcastBotTrade(io: Server, botId: string, trade: Trade) {
  io.to(`bot:${botId}:trades`).emit('bot:trade', {
    botId,
    timestamp: Date.now(),
    trade,
  });
}

React Client Integration

WebSocket Manager Encapsulation

// src/api/websocket.ts
import { io, Socket } from 'socket.io-client';
import { useEffect, useRef, useCallback } from 'react';

class WebSocketManager {
  private socket: Socket | null = null;
  private reconnectAttempts = 0;
  private maxReconnectAttempts = 5;
  private listeners: Map<string, Set<Function>> = new Map();
  
  connect(token: string) {
    if (this.socket?.connected) return;
    
    this.socket = io(process.env.VITE_WS_URL, {
      auth: { token },
      transports: ['websocket', 'polling'],
      reconnection: true,
      reconnectionAttempts: this.maxReconnectAttempts,
      reconnectionDelay: 1000,
      reconnectionDelayMax: 5000,
    });
    
    this.socket.on('connect', () => {
      console.log('WebSocket connected');
      this.reconnectAttempts = 0;
    });
    
    this.socket.on('disconnect', (reason) => {
      console.log('WebSocket disconnected:', reason);
      if (reason === 'io server disconnect') {
        // Server-initiated disconnect, manual reconnect needed
        setTimeout(() => this.connect(token), 1000);
      }
    });
    
    this.socket.on('error', (error) => {
      console.error('WebSocket error:', error);
    });
    
    // Re-register all listeners
    this.listeners.forEach((callbacks, event) => {
      callbacks.forEach((callback) => {
        this.socket?.on(event, callback);
      });
    });
  }
  
  disconnect() {
    this.socket?.disconnect();
    this.socket = null;
  }
  
  subscribe(event: string, callback: Function) {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, new Set());
      this.socket?.on(event, callback);
    }
    this.listeners.get(event)!.add(callback);
    
    return () => this.unsubscribe(event, callback);
  }
  
  unsubscribe(event: string, callback: Function) {
    this.listeners.get(event)?.delete(callback);
    this.socket?.off(event, callback);
  }
  
  emit(event: string, data?: any) {
    this.socket?.emit(event, data);
  }
  
  isConnected() {
    return this.socket?.connected ?? false;
  }
}

export const wsManager = new WebSocketManager();

React Hooks Encapsulation

// src/hooks/useWebSocket.ts
export function useWebSocket() {
  useEffect(() => {
    const token = localStorage.getItem('token');
    if (token) {
      wsManager.connect(token);
    }
    
    return () => {
      wsManager.disconnect();
    };
  }, []);
  
  return {
    subscribe: wsManager.subscribe.bind(wsManager),
    emit: wsManager.emit.bind(wsManager),
    isConnected: wsManager.isConnected.bind(wsManager),
  };
}

// Price subscription Hook
export function usePriceSubscription(symbols: string[]) {
  const [prices, setPrices] = useState<Record<string, Price>>({});
  
  useEffect(() => {
    if (symbols.length === 0) return;
    
    // Subscribe
    wsManager.emit('price:subscribe', symbols);
    
    // Listen for updates
    const unsubscribe = wsManager.subscribe('price:update', (data) => {
      setPrices((prev) => ({
        ...prev,
        [data.symbol]: data,
      }));
    });
    
    return () => {
      unsubscribe();
      wsManager.emit('price:unsubscribe', symbols);
    };
  }, [symbols.join(',')]);
  
  return prices;
}

// Bot monitoring Hook
export function useBotMonitor(botId: string) {
  const [status, setStatus] = useState<BotStatus | null>(null);
  const [trades, setTrades] = useState<Trade[]>([]);
  const [position, setPosition] = useState<Position | null>(null);
  
  useEffect(() => {
    if (!botId) return;
    
    wsManager.emit('bot:subscribe:one', botId);
    
    const unsubStatus = wsManager.subscribe('bot:status', (data) => {
      if (data.botId === botId) setStatus(data);
    });
    
    const unsubTrade = wsManager.subscribe('bot:trade', (data) => {
      if (data.botId === botId) {
        setTrades((prev) => [data.trade, ...prev].slice(0, 100));
      }
    });
    
    const unsubPosition = wsManager.subscribe('bot:position', (data) => {
      if (data.botId === botId) setPosition(data.position);
    });
    
    return () => {
      unsubStatus();
      unsubTrade();
      unsubPosition();
    };
  }, [botId]);
  
  return { status, trades, position };
}

Want to learn more React integration techniques? Check out React 18 Automated Trading Interface Development Guide.


Performance Optimization Strategies

Data Compression and Throttling

// Price data compression
interface CompressedPrice {
  s: string;  // symbol
  p: number;  // price
  v: number;  // volume
  t: number;  // timestamp
}

// Compress before sending
function compressPrice(data: PriceData): CompressedPrice {
  return {
    s: data.symbol,
    p: data.price,
    v: data.volume,
    t: Date.now(),
  };
}

// Throttling (only send last one within 100ms)
import { throttle } from 'lodash';

const throttledBroadcast = throttle(
  (io, symbol, data) => broadcastPriceUpdate(io, symbol, data),
  100,
  { leading: false, trailing: true }
);

Connection Pool Management

// Limit connections per user
const userConnections: Map<string, Set<string>> = new Map();

io.use(async (socket, next) => {
  const userId = socket.data.user.id;
  
  if (!userConnections.has(userId)) {
    userConnections.set(userId, new Set());
  }
  
  const connections = userConnections.get(userId)!;
  
  // Limit 3 simultaneous connections
  if (connections.size >= 3) {
    // Disconnect oldest connection
    const oldestSocketId = connections.values().next().value;
    const oldestSocket = io.sockets.sockets.get(oldestSocketId);
    oldestSocket?.disconnect(true);
    connections.delete(oldestSocketId);
  }
  
  connections.add(socket.id);
  
  socket.on('disconnect', () => {
    connections.delete(socket.id);
  });
  
  next();
});

Error Handling and Monitoring

Reconnection Strategy

// Exponential backoff reconnection
const reconnectStrategy = {
  attempts: 0,
  maxAttempts: 10,
  baseDelay: 1000,
  
  getDelay() {
    const delay = this.baseDelay * Math.pow(2, this.attempts);
    return Math.min(delay, 30000); // Max 30 seconds
  },
  
  reset() {
    this.attempts = 0;
  },
  
  increment() {
    this.attempts = Math.min(this.attempts + 1, this.maxAttempts);
  },
};

// Usage
socket.on('disconnect', () => {
  const delay = reconnectStrategy.getDelay();
  reconnectStrategy.increment();
  
  setTimeout(() => {
    socket.connect();
  }, delay);
});

socket.on('connect', () => {
  reconnectStrategy.reset();
});

Monitoring Metrics

// Connection statistics
const metrics = {
  connections: 0,
  messagesPerSecond: 0,
  reconnections: 0,
  errors: 0,
};

io.on('connection', (socket) => {
  metrics.connections++;
  
  socket.on('disconnect', () => {
    metrics.connections--;
  });
});

// Calculate message volume per second
let messageCount = 0;
io.on('connection', (socket) => {
  const originalEmit = socket.emit;
  socket.emit = function(...args) {
    messageCount++;
    return originalEmit.apply(this, args);
  };
});

setInterval(() => {
  metrics.messagesPerSecond = messageCount;
  messageCount = 0;
  
  // Send to monitoring system
  console.log('WebSocket Metrics:', metrics);
}, 1000);

Real-world Case: Sentinel Bot's WebSocket Architecture

Performance Data

| Metric | Value | Notes |

|:---|:---:|:---|

| Simultaneous Connections | 10,000+ | Single server |

| Message Latency | < 50ms | P95 |

| Reconnection Success Rate | 99.8% | After network flash |

| CPU Usage | 15% | At full load |

| Memory Usage | 2GB | 10K connections |

Architecture Decisions

Why choose Socket.io?
├── Auto-reconnect mechanism saves development time
├── Room mechanism simplifies subscription management
├── Redis adapter supports horizontal scaling
└── Rich middleware ecosystem

Why not native WebSocket?
├── Need to implement reconnect logic manually
├── No built-in room mechanism
├── Missing production environment features
└── Higher development cost

Frequently Asked Questions FAQ

Q1: What is the WebSocket connection limit?

A: Depends on server configuration:

Q2: How to handle firewall blocking WebSocket?

A: Socket.io automatic fallback:

  1. Try WebSocket
  2. If failed, use HTTP long polling
  3. Maintain same API interface

Q3: Will mobile WebSocket be disconnected by the system?

A: Yes, needs special handling:

Q4: How to ensure message order?

A: Implement sequence number mechanism:

// Attach sequence number when sending
socket.emit('data', { seq: 123, payload: data });

// Client checks and sorts
const buffer = new Map();
let expectedSeq = 1;

socket.on('data', ({ seq, payload }) => {
  if (seq === expectedSeq) {
    process(payload);
    expectedSeq++;
    // Process subsequent messages in buffer
  } else {
    buffer.set(seq, payload);
  }
});

Q5: How to divide work between WebSocket and REST API?

A: Clear division:

Q6: How to test WebSocket?

A: Use socket.io-client + Jest:

import { io } from 'socket.io-client';

it('should receive price updates', (done) => {
  const client = io('ws://localhost:3000');
  
  client.emit('price:subscribe', ['BTC/USDT']);
  
  client.on('price:update', (data) => {
    expect(data.symbol).toBe('BTC/USDT');
    client.disconnect();
    done();
  });
});

Q7: How to optimize broadcast performance for large volumes?

A: Use Redis Pub/Sub:

// Price service publishes
redisClient.publish('price:BTC/USDT', JSON.stringify(priceData));

// All servers subscribe
redisClient.subscribe('price:BTC/USDT', (message) => {
  const data = JSON.parse(message);
  io.to(`symbol:BTC/USDT:ticker`).emit('price:update', data);
});

Q8: How to monitor WebSocket health?

A: Multi-dimensional monitoring:


Conclusion and Action Recommendations

WebSocket is the technical cornerstone of trading systems, Socket.io is the best choice for production environments. Key success factors:

  1. Reasonable channel design: Layer by domain and permission
  2. Stable reconnection mechanism: Ensure user experience when network unstable
  3. Performance optimization: Compression, throttling, connection pool management
  4. Comprehensive monitoring: Detect and solve problems promptly

Take Action Now


Extended Reading:


Author: Sentinel Team

Last Updated: 2026-03-04

Technical Verification: Based on Sentinel Bot production environment practical experience


Building a real-time trading system? Experience Sentinel Bot's WebSocket-driven monitoring now, or download our WebSocket template to get started quickly.

Free Trial Sentinel Bot | Download WebSocket Template | Technical Consultation


Related Articles

Same Series Extended Reading

Cross-series Recommendations