Bequant
Institutional crypto exchange with proprietary matching engine. Trading terminal handling 10K market events per minute.
Outcomes
Context
Bequant is an institutional crypto exchange — not a retail Robinhood clone, but a venue for market-makers and prop-trading desks with their own quant infrastructure. The matching engine is in-house. The trading terminal needs to feel like Bloomberg, not like Binance.
The product had three uncomfortable problems when I joined the frontend team: the order book rendered at 4-5 FPS under load, the portfolio screen made 14 separate REST calls on every page load, and the same KYC document upload was reimplemented 3 times across product surfaces.
What I built
- Rewrote the order book and trades feed using WebSocket diffs + virtualization. Sustained 10 000 market events per minute without dropping frames. Throttling on the React reducer, not on the socket — preserved the actual data, just batched the UI updates.
- Designed a GraphQL aggregation layer on top of the existing REST services. The portfolio screen went from 14 REST round-trips to 1 GraphQL query. Backend load on that route dropped 45% measured over 30 days.
- Introduced multi-tier Redis caching: rate-limits at the edge, market data at the API gateway, user sessions in the service layer. Sustained 50K active users at peak without backend degradation.
- Migrated CI from a homegrown shell-pipeline to GitLab CI with parallel test execution. 800+ unit tests and a Cypress E2E suite now run in 9 minutes instead of 3 hours.
- Set up Prometheus + Grafana metrics and PagerDuty alerts for SLO violations. MTTR for production incidents went from 45 to 8 minutes — most of that win was just knowing which service was broken inside the first 2 minutes.
- Hardened security: implemented OAuth 2.0, 2FA, JWT-replay protection, CSRF tokens on state-changing endpoints, and client-side AES-GCM encryption for KYC document uploads before they hit S3.
Technical decisions
Order book diffing: the engine pushes deltas, not snapshots. UI maintains the canonical order book in a normalized Redux slice and applies diffs in a single dispatch per animation frame. Re-renders go through React.memo with a custom equality check on price/size pairs.
GraphQL choice was pragmatic: the existing REST services stayed, the GraphQL layer was a thin BFF (backend-for-frontend) on Apollo. No migration tax, immediate win.
Cypress for E2E even though the team was leaning Playwright at the time — Cypress's time-travel debugger and built-in network stubbing saved us countless hours on flaky tests against the matching engine.
Client-side KYC encryption: keys derived from the user's password via PBKDF2, never sent to the server. If S3 leaks, the documents are still unreadable. Trade-off: user can't recover documents on password reset — explicit copy in UI handles that.
From the code
query Portfolio($userId: ID!) {
user(id: $userId) {
id
balances {
currency
free
locked
btcEquivalent
}
openOrders {
id
symbol
side
price
size
filled
createdAt
}
recentTrades(limit: 20) {
id
symbol
side
price
size
fee
executedAt
}
pnl(timeframe: D1) {
realized
unrealized
percentChange
}
}
}
# 1 round-trip replaces 14 REST calls.
type OrderBookDiff = {
bids: [price: string, size: string][]; // size="0" means delete
asks: [price: string, size: string][];
sequence: number;
};
const applyDiff = (state: OrderBookState, diff: OrderBookDiff) => {
if (diff.sequence !== state.sequence + 1) {
// Out-of-order or gap: resync via REST snapshot.
return { ...state, needsResync: true };
}
for (const [price, size] of diff.bids) {
if (size === "0") delete state.bids[price];
else state.bids[price] = size;
}
for (const [price, size] of diff.asks) {
if (size === "0") delete state.asks[price];
else state.asks[price] = size;
}
state.sequence = diff.sequence;
};
Result
Trading terminal handles institutional-grade load. Backend cost dropped meaningfully after the GraphQL consolidation. CI release cycle went from a 3-hour ritual to a 25-minute boring background task.
Mentored 3 junior engineers; two of them grew into mids within a year.