CryptEx

Cryptocurrency Exchange

CryptEx is a centralized crypto exchange backend: a custom spot and perpetual-futures matching engine, plus the REST API and supporting services around it — persistence, WebSocket fan-out, an external mark-price feed and a reverse proxy — built as a Bun/Turborepo TypeScript monorepo. Nothing talks to the trading engine over HTTP: every order, balance change and admin action is a message on a Redis Stream, and every effect the engine produces is a message on a response stream that downstream services each consume independently.

  • Engineered a centralized matching and execution engine for Spot and Perpetual Futures trading, sustaining 1,000+ orders/second with sub-50 ms p95 execution latency across 6 microservices in a Turborepo monorepo.
  • Streamed order book and trade updates to 500+ concurrent WebSocket clients, cutting update lag from 2 s polling to under 100 ms via Redis pub/sub.
  • Achieved zero order loss on restart by persisting engine state through Redis pipelines and 30-second snapshots, restoring the full order book in under 5 seconds and resolving concurrent order-execution race conditions.

What It Does

  • Custom spot and perpetual-futures matching engine handling order creation, liquidation/ADL, funding settlement, and commission & insurance funds.
  • Fully event-driven: every state change flows through Redis Streams (engine.request / engine.response), so persistence and WebSocket fan-out are independent consumers, not synchronous calls.
  • Real-time WebSocket fan-out of order book, balance and position updates to browser clients.
  • External mark-price feed polling Binance plus an hourly funding-rate scheduler.
  • Hourly engine-state snapshots to Cloudflare R2 for recovery.
  • A reverse proxy exposing Backpack Exchange's public market data independently of the core engine.

Architecture

core-backend (REST API) and ws-index-poller (Binance mark-price feed) publish onto the engine.request Redis Stream; core-trading-engine consumes it, performs matching/balances/positions/funding, and publishes results onto engine.response, which database-engine (Postgres persistence) and ws-server (WebSocket broadcast) each consume as their own independent consumer group.

Services

core-backendREST API — auth, admin, orders, balances, market data (port 8080)
core-trading-engineMatching engine — order book, balances, positions, funding, liquidation (port 8081)
database-enginePersists every engine update to Postgres (port 8082)
ws-serverWebSocket fan-out of engine updates to browser clients (port 8083)
ws-index-pollerBinance mark-price feed + hourly funding-rate scheduler (port 8084)
proxy-serverReverse proxy to Backpack Exchange's public REST API (port 8085)
core-frontendPublic-facing web app (Next.js, port 3000)

Tech Stack

Language & Runtime

TypeScript
Bun 1.3
Node.js 20+

Monorepo Tooling

Turborepo

Backend

Express
PostgreSQL
Prisma ORM

Messaging

Redis Streams

Realtime

WebSockets

Frontend

Next.js
shadcn/ui

Infra

Docker Compose
Cloudflare R2

Languages

TypeScript95%
CSS2%
PLpgSQL1%
Dockerfile1%
JavaScript1%

Getting Started

  1. 1Clone the repo
    git clone https://github.com/SajalDBansal/centralized-exchange.git cd centralized-exchange bun install
  2. 2Start everything in Docker (Postgres, Redis, every service)
    docker compose -f infra/docker-compose.dev.yml up -d
  3. 3Run database migrations
    cd packages/database bunx prisma migrate deploy
  4. 4Start the frontends
    bun run dev
GitHub
LinkedIn