A full-stack trading platform built as a microservices-based capstone project. It simulates the core workflow of a centralized exchange: authenticated users can deposit funds, place orders, see live order book and trade updates, and track wallet, portfolio, and order history from persisted backend state.
- A matching engine with price-time-priority order execution
- A microservices architecture with clear service boundaries
- Real-time market data fanout over WebSockets
- Persistent account, order, fill, and wallet ledger data in PostgreSQL/TimescaleDB
- A modern trading-style frontend built with Next.js
- End-to-end local orchestration with Docker Compose
This is not a production exchange. It is a strong engineering-focused simulation designed to showcase distributed backend design, real-time systems, and full-stack integration.
The system is split into six services:
frontend: Next.js app for dashboard, wallet, portfolio, markets, and trade UIapi: Express API gateway for authenticated user actions and read endpointsengine: in-memory matching engine and orderbook managerws: WebSocket fanout service for ticker, depth, and trade streamsdb-worker: async persistence worker consuming engine events and writing to Postgresmm: simple market-maker bot to seed liquidity for demo purposes
Core data flow:
- A user action hits the
apiservice. - The API sends a message to the
enginethrough Redis. - The engine matches or places the order in memory.
- The engine emits:
- direct response messages back to the API
- market-data updates for WebSocket subscribers
- persistence events for the DB worker
- The
db-workerwrites orders, trade fills, wallet ledger entries, and balance changes to Postgres. - The frontend reads current state from the API and subscribes to live market streams through
ws.
- Frontend: Next.js 16, React 19, TypeScript, Tailwind CSS, Radix UI, Lightweight Charts
- Backend: Node.js, Express, TypeScript
- Real-time: WebSockets, Redis Pub/Sub, Redis queues
- Database: PostgreSQL + TimescaleDB
- Auth: Clerk
- Infra: Docker, Docker Compose, pnpm workspaces
- Testing: Vitest
This repo now supports two explicit startup modes:
pnpm dev: local development mode. Onlyredisandtimescaledbrun in Docker. All Node services run on your host with file watching.pnpm compose:backend:up: production-style backend mode. Docker Compose runs the backend microservices on one host.
This matches the intended deployment split:
frontend: deploy separately, for example on Vercel- backend microservices (
api,ws,engine,db-worker,db-cron,mm) plus infrastructure (redis,timescaledb): run on your VPS with Docker Compose
Docker Compose profiles are used to keep this standard and explicit:
- default services: infrastructure only
backendprofile: backend microservicesfrontendprofile: optional containerized frontend for an all-in-one local demo
- Multiple market support
- Price-time-priority matching
- Partial fills
- Order cancellation
- In-memory orderbook restore from persisted open orders on startup
- Real-time ticker, trade, and depth event publishing
- Users
- Balances by asset
- Markets and assets
- Orders with open / partially filled / filled / cancelled states
- Trade fills
- Wallet ledger entries
- Deposits and withdrawals
- Markets page with live-backed market summaries
- Trade page with:
- order entry
- live orderbook depth
- live ticker updates
- chart data
- user order history
- Wallet page with deposit/withdraw actions and transaction history
- Portfolio page with holdings and allocation
- Dashboard page with balance, PnL summary, and recent activity
Real in this project:
- Order matching
- Balance locking/unlocking
- Open order persistence
- Trade persistence
- Portfolio/wallet/order history reads from DB
- Real-time market data streaming
Simulated or simplified:
- Deposits and withdrawals are manual/demo actions, not real banking rails
- The market maker is a demo bot, not a serious strategy
- The engine keeps the live orderbook in memory
- Risk checks and exchange-grade security controls are intentionally simplified
- Docker
- Docker Compose
- Node.js 20+
pnpmviacorepack enable
git clone https://github.com/sheikh162/trading-platform.git
cd trading-platform
cp .env.example .env
cp services/api/.env.example services/api/.env
cp services/persistence/.env.example services/persistence/.env
cp services/engine/.env.example services/engine/.env
cp apps/frontend/.env.example apps/frontend/.env
cp services/market-maker/.env.example services/market-maker/.env
cp services/ws-gateway/.env.example services/ws-gateway/.envFill in your Clerk keys in the relevant .env files before running the full app.
pnpm installRun Redis and TimescaleDB in Docker, and run the application services directly on your machine:
pnpm devWhat pnpm dev does:
- starts
redisandtimescaledbwith Docker Compose - waits for both infra services to become reachable
- applies DB migrations and seeds Timescale objects
- starts
engine,db,api,ws,mm, andfrontendon the host in watch mode
Local URLs:
- Frontend:
http://localhost:3002 - API:
http://localhost:3000 - WebSocket service:
ws://localhost:3001
To stop the Dockerized infra only:
pnpm infra:downIf you need to re-apply the DB seed manually:
pnpm db:seedFor your VPS deployment, keep the frontend separate and start only the backend stack:
pnpm compose:backend:upThat command starts:
redistimescaledbenginedb-seeddb-workerdb-cronapiwsmm
To stop the Compose stack:
pnpm compose:downIf you ever want a single-host demo with the frontend container included:
pnpm compose:full:uppnpm -C db build
pnpm -C engine test --run
pnpm -C api build
pnpm -C frontend lint
pnpm -C frontend buildThe best demo sequence is:
- Sign up / sign in
- Open
/wallet - Deposit demo funds
- Go to
/trade/BTC_USDT - Place a buy or sell order
- Watch live depth and ticker updates
- Revisit:
/wallet/portfolio/dashboard- the trade page order panel
If the market is empty, start the market-maker service so the book has liquidity.
The engine is optimized for fast in-memory order handling. Persistence is handled asynchronously by a dedicated worker so order matching logic stays isolated from slower DB writes.
Redis is used for:
- request/response messaging between API and engine
- pub/sub for real-time market streams
- queue-based event delivery to the DB worker
This keeps service boundaries simple while still demonstrating asynchronous backend design.
Trade and candle data are time-series shaped. TimescaleDB is a good fit for storing fills/trades and generating chart-friendly data efficiently.
- The engine orderbook remains in memory during runtime
- Deposits and withdrawals are simulated
- No advanced risk engine, rate limiting, or admin tooling yet
- No production-grade observability stack
- Frontend deployment configuration for Vercel is still managed separately from the backend Compose stack
- Some service-level READMEs are still catching up to the latest architecture
This project is intended to be a strong resume capstone because it combines:
- distributed systems thinking
- real-time data streaming
- backend state consistency problems
- matching engine logic
- full-stack product implementation
- Dockerized local deployment
Reasonable next steps for this project:
- request validation at API boundaries
- integration tests for deposit -> order -> fill -> cancel flows
- private real-time order status updates over WebSocket
- cleaner service-level docs
- lightweight admin/ops monitoring page
apps/frontend/ Next.js client app
services/api/ Express API gateway
services/engine/ Matching engine and orderbook
services/persistence/ DB worker, migrations, seeding, materialized view refresh logic
services/market-maker/ Demo market-maker bot
services/ws-gateway/ WebSocket fanout service
packages/ Shared config, logger, and message contracts
infra/compose/ Base and production Compose manifests
