Trader loses up to 5% of profit due to terminal lags – that's a proven fact. Every millisecond of delay results in losses for high-frequency strategies. We develop terminals that don't lag. Our engineers, with over 5 years of experience, have built 12 projects for prop trading firms and DeFi funds. High-frequency trading requires latency under 100 ms. Contact us – we'll evaluate your project in 2 days and offer a turnkey solution.
Key Terminal Components
Charting System – the heart of the terminal. OHLCV candlestick display, technical indicators, volumes. TradingView Lightweight Charts – standard choice for custom solutions. For full-featured terminals – TradingView Advanced Charts via Data Feed API or fully custom implementation on Canvas/WebGL.
Order Book – real-time bid/ask levels, depth chart (cumulative volume), grouping by tick. Critical: updates happen without re-rendering the entire component – only changed rows.
Order Form – order entry. Supports market, limit, stop-limit, trailing stop. Calculation of size in % of deposit, in base/quote currency, by lots.
Positions/Orders Panel – manage open positions and active orders. Quick close, modify order parameters.
Trade Feed – recent trades feed with large trade highlighting. Portfolio/Balance – account summary: balances, margin ratio, P&L.
Frontend Architecture
// Structure of React terminal application
interface TerminalLayout {
left: {
symbolSearch: SymbolSearchPanel;
watchlist: WatchlistPanel;
};
center: {
chart: ChartPanel;
orderBook: OrderBookPanel;
tradeFeed: TradeFeedPanel;
};
right: {
orderForm: OrderFormPanel;
positions: PositionsPanel;
orders: OrdersPanel;
balance: BalancePanel;
};
bottom: {
orderHistory: OrderHistoryPanel;
alerts: AlertsPanel;
};
}Resizable layout via react-grid-layout or react-mosaic – traders want customizable panel layouts.
Why WebSocket State Is the Bottleneck?
The terminal receives data from multiple WebSocket streams simultaneously. Managing this state is non-trivial. We use Zustand with atomic updates:
import { create } from 'zustand';
interface MarketDataStore {
orderBook: OrderBook | null;
trades: Trade[];
currentPrice: number | null;
updateOrderBook: (diff: OrderBookDiff) => void;
addTrade: (trade: Trade) => void;
}
export const useMarketDataStore = create<MarketDataStore>((set, get) => ({
orderBook: null,
trades: [],
currentPrice: null,
updateOrderBook: (diff) =>
set((state) => {
if (!state.orderBook) return state;
const newBids = new Map(state.orderBook.bids);
const newAsks = new Map(state.orderBook.asks);
for (const [price, qty] of diff.bids) {
if (qty === 0) newBids.delete(price);
else newBids.set(price, qty);
}
for (const [price, qty] of diff.asks) {
if (qty === 0) newAsks.delete(price);
else newAsks.set(price, qty);
}
return {
orderBook: {
bids: newBids,
asks: newAsks,
timestamp: diff.timestamp,
},
};
}),
addTrade: (trade) =>
set((state) => ({
trades: [trade, ...state.trades].slice(0, 1000),
currentPrice: trade.price,
})),
}));
How Does Virtualization Boost Performance 25x?
An order book with 200+ levels, updating 10 times per second, is a heavy DOM load. List virtualization (react-virtual, tanstack/virtual) renders only visible rows: 500 rows in DOM -> 20 visible, yielding a 25x improvement over full rendering.
Web Workers for computations – heavy calculations (order book aggregation, indicator calculation) are moved to a Worker to avoid blocking the UI thread:
// orderbook.worker.ts
self.onmessage = (e: MessageEvent) => {
const { type, data } = e.data;
if (type === 'PROCESS_DIFF') {
const processed = applyDiff(data.currentBook, data.diff);
const aggregated = aggregateByTick(processed, data.tickSize);
self.postMessage({ type: 'BOOK_UPDATED', data: aggregated });
}
};requestAnimationFrame throttling – we update the DOM no more than 60 times per second, buffering incoming updates.
Backend: Gateway Service
The terminal does not connect directly to exchanges – that's an architectural mistake for production systems. An intermediate Gateway service:
- Multiplexes a single exchange WebSocket connection for many clients (reduces load by 10x)
- Caches current order book state
- Authenticates client connections
- Enforces rate limits
from fastapi import FastAPI, WebSocket
from starlette.websockets import WebSocketDisconnect
import asyncio
app = FastAPI()
class MarketDataGateway:
def __init__(self):
self.subscribers: dict[str, list[WebSocket]] = {}
self.book_cache: dict[str, OrderBook] = {}
async def subscribe(self, symbol: str, ws: WebSocket):
if symbol not in self.subscribers:
self.subscribers[symbol] = []
asyncio.create_task(self.connect_to_exchange(symbol))
self.subscribers[symbol].append(ws)
# Send current snapshot to new subscriber
if symbol in self.book_cache:
await ws.send_json(self.book_cache[symbol].to_dict())
async def broadcast(self, symbol: str, data: dict):
dead_connections = []
for ws in self.subscribers.get(symbol, []):
try:
await ws.send_json(data)
except Exception:
dead_connections.append(ws)
for ws in dead_connections:
self.subscribers[symbol].remove(ws) TradingView Integration
TradingView Advanced Charts (paid license) is the standard for professional terminals. Custom DataFeed adapter:
const dataFeed: IdatafeedChartApi = {
onReady: (callback) => {
callback({
supported_resolutions: ['1', '5', '15', '60', '240', 'D', 'W'],
supports_marks: true,
supports_time: true,
});
},
getBars: async (symbolInfo, resolution, periodParams, onHistoryCallback) => {
const candles = await api.getCandles(
symbolInfo.name,
resolution,
periodParams.from,
periodParams.to
);
onHistoryCallback(candles.map(toTradingViewBar), {
noData: candles.length === 0,
});
},
subscribeBars: (symbolInfo, resolution, onRealtimeCallback) => {
wsGateway.on(`candle:${symbolInfo.name}:${resolution}`, onRealtimeCallback);
},
}; Mobile Version
A full-featured terminal on mobile is a different UX challenge. Key patterns:
- Swipe between sections (chart/orderbook/orders) instead of multi-panel layout
- Bottom sheet for order form
- Simplified order book (only 10-20 levels)
- Push notifications for price alerts and order fills
React Native with WebView for TradingView chart or native implementation via react-native-canvas for simple graphs.
Performance and SLA
Performance targets:
| Metric | Goal |
|---|---|
| Latency order book update | < 100 ms from exchange to UI |
| Order submission latency | < 200 ms |
| Chart render FPS | 60 fps |
| Initial load time | < 3 sec |
| WebSocket reconnect | < 2 sec |
Monitoring details
Client-side latency monitoring via performance.now() and sending metrics to analytics is a necessary part of production monitoring. Savings on commissions due to reduced latency can reach 30%.
Evaluation and Work Process
We start with a thorough analysis of your requirements. Then we design the architecture, develop the terminal in iterative sprints, test for performance and reliability, and finally deploy. Post-launch, we provide 3 months of technical support. Typical timeline ranges from 1 month for a basic terminal to over 4 months for a comprehensive solution. Pricing is determined after analysis.
Typical Development Mistakes
- Direct client connection to exchange without Gateway – scaling and security suffer
- Lack of list virtualization – with 200+ order book levels, UI starts lagging
- Re-rendering the entire order book component on each change instead of incremental update
- Ignoring exchange rate limits – leads to API key blocking
What's Included
- Project documentation and architectural description
- Code repository (React frontend, Python gateway, deploy scripts)
- Integration with exchanges from your list
- Training of your team on the code
- 3 months of technical support after release
Order turnkey trading terminal development. Get a consultation – write to us, we'll evaluate your project in 2 days.







