A high-performance perpetual futures trading engine built with TypeScript, Bun, Redis Streams, and PostgreSQL.
Introduction ·
Architecture ·
User Interface ·
Features ·
Tech Stack ·
API Endpoints ·
Order Matching & Execution ·
AMM Simulator ·
Local Development ·
License
PERP is a low-latency, event-driven perpetual futures trading engine designed for high-frequency derivatives trading. Built with TypeScript and Bun in a monorepo architecture, it features an in-memory order book utilizing B-Trees and Doubly-Linked Lists, real-time WebSocket streaming, dynamic risk management (leverage validation, mark price calculation, dynamic funding rates, auto-liquidation), and an asynchronous persistence layer powered by Redis Streams and PostgreSQL.
- GitHub Repository - PERP-UI
- ⚡ Ultra-fast Order Matching - In-memory matching engine for sub-millisecond execution.
- 🏦 In-memory Order Book & Balances - B-Trees for sorted price-level tracking and Doubly-Linked Lists for FIFO resting order execution.
- 🔥 Real-time WebSockets - Instant broadcasts for orderbook depth, trade execution fills, and tickers.
- 🛡️ Risk & Liquidation Engine - Dynamic margin checks, mark price tracking, leverage validation, funding rate calculations, and automated liquidations.
- 🔄 Fault-tolerant Architecture - Redis Streams message broker with offset replay for zero-loss crash recovery.
- 📦 Decoupled Persistence - Asynchronous background DB Poller worker batch persisting orders, fills, trades, and candles to PostgreSQL without blocking engine performance.
- 🔌 Efficient API Layer - Express.js REST API Gateway with JWT authentication, Zod validation, and direct read paths for historical queries.
- TypeScript - Core language for type safety and execution performance.
- Bun - Fast JavaScript/TypeScript runtime and package manager.
- Turborepo - High-performance build system for monorepos.
- Redis Streams - Message queue and pub/sub event bus.
- PostgreSQL - Persistent storage for trade history, orders, candles, and balances.
- Prisma ORM - Database interaction and client generation.
- Express.js - Web framework for REST API endpoints.
- WebSockets - Real-time market data streaming.
- Zod - Schema validation.
-
Primary REST API Gateway (
apps/backend)- Handles REST API requests (Auth, Orders, Balance, Positions).
- Routes write/execution requests to Redis Streams with unique correlation IDs and awaits responses.
- Queries PostgreSQL directly for historical queries (candles, trades, orders) to unburden matching engine CPU.
-
Redis Streams Message Bus
REQUEST_STREAM: Message queue for inbound order creations, cancellations, deposits, and withdrawals.MARK_PRICE_STREAM: Oracle price updates from external feeds.RESPONSE_STREAM: Event stream for matching engine outputs, trade fills, liquidations, and depth updates.
-
Matching & Risk Engine (
apps/engine)- Maintains in-memory order books and user balances.
- Executes trades using price-time priority.
- Manages position leverage, mark price recalculations, and auto-liquidations.
-
WebSocket Layer (
apps/web-socket-server)- Consumes market events from Redis Streams.
- Streams live orderbook depth (
depth.<market>), market trades (trade.<market>), and tickers to clients in real time.
-
Database Poller (
apps/db-poller)- Background worker consuming execution events from Redis Streams.
- Batch inserts and updates orders, fills, positions, and candlestick data into PostgreSQL asynchronously.
-
Price Feed Oracle (
apps/price-feed)- Connects to external price sockets (e.g. Binance) and streams live mark prices into Redis Streams.
POST /api/v1/sign-up-> Register a new trader accountPOST /api/v1/sign-in-> Authenticate trader and receive JWT token
POST /api/v1/onramp-> Deposit collateral balance (e.g., USDC)POST /api/v1/withdraw-> Withdraw collateral balanceGET /api/v1/balance-> Get user available and locked balances
POST /api/v1/order-> Create/Execute a new LONG or SHORT order (limit/market)DELETE /api/v1/order-> Cancel an active limit orderGET /api/v1/orders/:marketId-> Get user historical orders for a marketGET /api/v1/orders/open/:marketId-> Get open user orders for a marketGET /api/v1/position/open-> Get all open leveraged positionsGET /api/v1/position/open/:marketId-> Get open position for a specific marketGET /api/v1/fills-> Get trade execution fills
GET /api/v1/depth/:marketId-> Get live orderbook depth (bids & asks)GET /api/v1/trades/:marketId-> Get recent executed market tradesGET /api/v1/candles/:marketId-> Get historical OHLC candlestick data
// Core Engine Structure
interface Engine {
orderbooks: Map<string, Orderbook>;
balances: Map<string, UserBalance>;
positions: Map<string, Map<string, Position>>;
}
// In-Memory Orderbook (B-Tree + Doubly Linked List)
interface Orderbook {
bids: BTree<number, LinkedList<Order>>; // Sorted descending by price
asks: BTree<number, LinkedList<Order>>; // Sorted ascending by price
market: string;
}
// Order Definition
interface Order {
orderId: string;
userId: string;
market: string;
side: "LONG" | "SHORT";
type: "limit" | "market";
price: number;
qty: number;
filledQty: number;
margin: number;
status: "open" | "partiallyFilled" | "Filled" | "Close" | "Cancel";
timestamp: number;
}
// User Balances & Position State
interface UserBalance {
userId: string;
availableBalance: number;
lockedBalance: number;
}
interface Position {
positionId: string;
userId: string;
market: string;
side: "LONG" | "SHORT";
qty: number;
entryPrice: number;
margin: number;
leverage: number;
liquidationPrice: number;
}- Orders are processed asynchronously using Bun runtime and Redis Streams.
- API Gateway pushes requests (
CreateOrder,CancelOrder) toREQUEST_STREAM. - The engine pops new requests from Redis Streams and evaluates the in-memory order book.
- If a match is found, trade execution occurs using price-time priority.
- Trade fills, market updates, and user positions are published to
RESPONSE_STREAM. - WebSocket server streams updates to clients while DB Poller batch persists state to PostgreSQL.
A built-in market maker script is included to simulate two-sided quoting and liquidity pressure:
node market-maker.jsWhat it does:
- Registers market maker test accounts (
mm_trader_1andmm_trader_2). - Funds accounts with test USDC balance via
/onramp. - Continuously posts active two-sided limit orders across
SOLandETHmarkets.
git clone https://github.com/Dev050x/PERP.git
cd PERP
bun install
bun devPERP is open-source under the MIT License.

