Real-Time Trading Terminal with Charts and Order Book

Real-Time Trading Terminal with Charts and Order Book When a trading stream delivers 2000+ order book updates per second, the browser starts to lag, data becomes inconsistent, and the trader loses money. We solve these problems at the architecture level: proper stack selection, differential updat

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1452
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1310
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    1005
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1270
  • image_logo-advance_0.webp
    B2B Advance company logo design
    719
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1012

Real-Time Trading Terminal with Charts and Order Book

When a trading stream delivers 2000+ order book updates per second, the browser starts to lag, data becomes inconsistent, and the trader loses money. We solve these problems at the architecture level: proper stack selection, differential updates, and rendering optimization. With 8+ years of experience in blockchain development and 15+ implemented trading interfaces, our platforms process up to 10,000 orders per second with less than 5 ms latency. We use proven solutions: WebSocket for streams, Redis for caching, and ClickHouse for history. This ensures not a single tick is lost and the interface remains responsive.

Recently we completed a project for a crypto exchange where the data stream reached 3000 updates per second. Our solution processed it without a single missed tick, and the interface latency did not exceed 2 ms. For another exchange, we optimized the architecture so that infrastructure costs decreased by 40% through efficient use of WebSocket gateways and Redis.

Technologies Used in Professional Terminals

Frontend: React 18 + TypeScript, Zustand for state management, TradingView Lightweight Charts, react-virtual for list virtualization. Backend: FastAPI (Python) or Fastify (Node.js) as WebSocket gateway, Redis for caching and pub/sub. Storage: ClickHouse or TimescaleDB for historical OHLCV data.

Data flow: Binance WS → Exchange Connector → Redis PubSub → WS Gateway → Browser. The gateway multiplexes data for all clients, allowing hundreds of connections with minimal latency.

Order Book Implementation: Avoiding Desync

The order book is built using differential updates. First, a snapshot is loaded via REST, then changes come via WebSocket. The key issue is maintaining sequence: each diff contains U (first update id) and u (last update id). If a snapshot is missed, data becomes desynchronized. We buffer diffs and check lastUpdateId:

Order Book Manager Code
class OrderBookManager { private bids: Map<number, number> = new Map(); private asks: Map<number, number> = new Map(); private lastUpdateId: number = 0; private buffer: OrderBookDiff[] = []; async initialize(symbol: string) { const ws = this.connectToStream(`${symbol.toLowerCase()}@depth`); const snapshot = await fetchOrderBookSnapshot(symbol, 1000); this.lastUpdateId = snapshot.lastUpdateId; this.bids = new Map(snapshot.bids.map(([p, q]) => [+p, +q])); this.asks = new Map(snapshot.asks.map(([p, q]) => [+p, +q])); for (const diff of this.buffer) { if (diff.U <= this.lastUpdateId + 1 && diff.u >= this.lastUpdateId + 1) { this.applyDiff(diff); } } this.buffer = []; } applyDiff(diff: OrderBookDiff) { if (diff.U !== this.lastUpdateId + 1) { console.error('Gap detected, reinitializing...'); this.initialize(this.symbol); return; } for (const [price, qty] of diff.b) { if (+qty === 0) this.bids.delete(+price); else this.bids.set(+price, +qty); } for (const [price, qty] of diff.a) { if (+qty === 0) this.asks.delete(+price); else this.asks.set(+price, +qty); } this.lastUpdateId = diff.u; this.notifySubscribers(); } getTopLevels(depth: number = 20) { const sortedBids = [...this.bids.entries()] .sort(([a], [b]) => b - a) .slice(0, depth); const sortedAsks = [...this.asks.entries()] .sort(([a], [b]) => a - b) .slice(0, depth); return { bids: sortedBids, asks: sortedAsks }; } } 

Steps to implement the order book:

  1. Fetch the initial snapshot via REST.
  2. Connect to WebSocket stream.
  3. Buffer incoming diffs.
  4. Apply diffs after snapshot, checking sequence.
  5. Render only visible levels using virtualization.

For display, we use virtualization via @tanstack/react-virtual to render only visible rows. This allows handling 500+ levels without performance loss. Our differential update approach is 3 times faster than full reload every 100 ms, and buffering guarantees consistency even during temporary network disruptions.

Charts: TradingView Lightweight Charts vs Alternatives

For candlestick charts we use Lightweight Charts. This library is 2 times faster than Chart.js for candle rendering and provides built-in support for financial data. Comparison:

Library Performance Customization Financial Data
TradingView LWC High (up to 60 FPS) High Built-in support for candles
Chart.js Medium (20-30 FPS) Medium Requires customization
D3.js High (complexity) Maximum Low (custom components)

Example setup:

Trading Chart Component Code
import { createChart, CandlestickSeries } from 'lightweight-charts'; function TradingChart({ symbol }: { symbol: string }) { const chartContainerRef = useRef<HTMLDivElement>(null); const seriesRef = useRef<CandlestickSeries>(); useEffect(() => { const chart = createChart(chartContainerRef.current!, { width: chartContainerRef.current!.clientWidth, height: 400, layout: { background: { color: '#1a1a2e' }, textColor: '#d1d4dc', }, grid: { vertLines: { color: '#2d2d4e' }, horzLines: { color: '#2d2d4e' }, }, crosshair: { mode: 1 }, timeScale: { borderColor: '#485c7b', timeVisible: true }, }); const candleSeries = chart.addCandlestickSeries({ upColor: '#26a69a', downColor: '#ef5350', borderUpColor: '#26a69a', borderDownColor: '#ef5350', }); seriesRef.current = candleSeries; loadHistoricalData(symbol, '1h').then((candles) => { candleSeries.setData(candles); chart.timeScale().fitContent(); }); const unsubscribe = wsGateway.subscribe(`candle:${symbol}:1h`, (candle) => { candleSeries.update(candle); }); return () => { unsubscribe(); chart.remove(); }; }, [symbol]); return <div ref={chartContainerRef} className="chart-container" />; } 

Lightweight Charts is 3 times faster than Chart.js on large datasets (10,000+ candles).

Why Proper Reconnect Matters

On connection loss, automatic reconnection with exponential backoff (1 s → 30 s) minimizes downtime. We use a custom hook that handles reconnect and subscription resubmission:

WebSocket Hook Code
export function useWebSocket(url: string) { const wsRef = useRef<WebSocket | null>(null); const reconnectTimerRef = useRef<NodeJS.Timeout>(); const reconnectCountRef = useRef(0); const connect = useCallback(() => { wsRef.current = new WebSocket(url); wsRef.current.onclose = (e) => { if (!e.wasClean) { const delay = Math.min(1000 * 2 ** reconnectCountRef.current++, 30000); reconnectTimerRef.current = setTimeout(connect, delay); } else { reconnectCountRef.current = 0; } }; wsRef.current.onerror = () => wsRef.current?.close(); }, [url]); useEffect(() => { connect(); return () => { clearTimeout(reconnectTimerRef.current); wsRef.current?.close(); }; }, [connect]); return wsRef; } 

In practice, reconnect takes less than 2 seconds, which is critical for high-frequency trading. Learn more about the WebSocket API on MDN.

How We Optimize Performance

Critical points: throttling updates, memoizing components, rendering depth chart via Canvas. We use requestAnimationFrame for rendering to avoid blocking the thread. For example, with 50+ order book updates per second, a buffer accumulates diffs, and rendering occurs no more than once per frame. This keeps FPS at 60 even under peak loads. Our optimizations reduce CPU load by 40% compared to a naive implementation. Consequently, operational costs on server infrastructure decrease by 30%, saving up to $2,000 per month for a medium-scale exchange.

Development Process and What's Included

Stage Duration Result
Requirements analysis 1-2 days Technical specification
Architecture 2-3 days Documentation
Implementation 2-4 weeks Working code
Testing 1 week Load report
Deployment 2-3 days Ready solution

The turnkey development includes: commented frontend and backend source code, exchange integration (Binance, Bybit, OKX, etc.), WebSocket gateway setup, deployment and operations documentation, 2-hour team training, and 3 months of free support after launch.

We also provide consulting on stack and architecture selection. Contact us to discuss your project. Order turnkey web platform development and get a ready solution with low latency.