ambarish0221/FlashLedger
FlashLedger
A production-grade, low-latency order matching engine with real-time Kafka streaming, a PySpark feature pipeline, LSTM and LightGBM ML models, Groq LLM integration, and a React trading dashboard.
Overview
FlashLedger replicates the core infrastructure of a modern crypto exchange. Orders enter through a REST API, get matched by a price-time priority engine in microseconds, and simultaneously flow through a streaming analytics pipeline that feeds trained machine learning models. A React frontend visualises every layer of the system live.
The primary technical focus is the ML training pipeline: raw trade microstructure data produced by the order book is transformed by PySpark Structured Streaming into engineered features, which train both an LSTM price-direction model and a LightGBM market-regime recommender. Groq LLM is integrated as an additive layer that synthesises model outputs into natural-language commentary and powers an autonomous AI trading agent.
Architecture
Browser (React + Vite)
|
| REST + WebSocket
v
FastAPI (app/)
|-- /order --> Matching Engine --> Order Book (in-memory, heap)
|-- /prediction --> LSTM inference (ml/predict.py)
|-- /insights --> LightGBM recommender + Groq commentary (ml/recommender.py)
|-- /chat --> Groq LLM with live market context
|-- /demo/start --> Rule-based simulation (5 agent types, 5 regimes)
|-- /demo/ai/start --> Groq AI agent (orders generated by Llama 3.3)
|-- /ws --> WebSocket broadcast (orderbook, trades, metrics)
|
| Kafka topic: trades
v
PySpark Structured Streaming (spark/feature_pipeline.py)
|-- 10-second tumbling windows
|-- Aggregates: trade_volume, vwap, order_imbalance, trade_velocity
v
PostgreSQL
|-- trades table
|-- market_features table
|
+--> ml/train.py (LSTM training)
+--> ml/train_recommender.py (LightGBM training on BTC/USD)Stack
Project Structure
FlashLedger/
├── app/
│ ├── main.py FastAPI entry point, CORS, lifespan
│ ├── api/
│ │ ├── routes.py All REST + WebSocket endpoints
│ │ └── ws_manager.py WebSocket broadcast manager
│ ├── engine/
│ │ ├── matching_engine.py Price-time priority matching
│ │ └── order_book.py Heap-based order book
│ ├── db/
│ │ ├── models.py Trade + MarketFeature ORM models
│ │ └── database.py Async PostgreSQL connection
│ ├── kafka/
│ │ └── producer.py Confluent-Kafka producer (graceful degradation)
│ ├── ai/
│ │ └── groq_client.py Groq AsyncGroq client (commentary + chat)
│ └── demo/
│ ├── runner.py Rule-based simulation (market makers, regimes)
│ └── ai_runner.py Groq-powered autonomous trading agent
├── spark/
│ └── feature_pipeline.py PySpark Structured Streaming consumer
├── ml/
│ ├── train.py LSTM training (market_features -> model.pt)
│ ├── predict.py LSTM inference module
│ ├── train_recommender.py LightGBM training (BTC/USD yfinance data)
│ └── recommender.py LightGBM inference + KNN similarity
├── frontend/
│ ├── src/
│ │ ├── App.jsx Main layout, demo state management
│ │ ├── components/
│ │ │ ├── Header.jsx Demo controls, regime badge, AI indicator
│ │ │ ├── OrderBook.jsx Animated bid/ask depth bars
│ │ │ ├── TradeFeed.jsx Live trade stream with side colouring
│ │ │ ├── PriceChart.jsx Recharts price line + volume bars
│ │ │ ├── PredictionWidget.jsx LSTM direction + confidence ring
│ │ │ ├── InsightsWidget.jsx LightGBM recommendation + Groq analysis
│ │ │ ├── OrderForm.jsx Buy/sell order entry form
│ │ │ ├── MetricsPanel.jsx Engine metrics cards
│ │ │ ├── SparkMetrics.jsx Pipeline topology documentation
│ │ │ └── ChatWidget.jsx Floating Groq chat panel
│ │ ├── hooks/
│ │ │ └── useWebSocket.js Auto-reconnect WS hook
│ │ └── api/
│ │ └── client.js Axios client for all endpoints
│ ├── Dockerfile Multi-stage node build + nginx serve
│ └── nginx.conf SPA fallback + API reverse proxy
├── tests/
│ ├── test_order_book.py
│ ├── test_matching_engine.py
│ └── load_test.py
├── docker-compose.yml 6 services: postgres, zookeeper, kafka, app, spark, frontend
├── Dockerfile
├── requirements.txt
└── .env GROQ_API_KEY, DATABASE_URL, KAFKA_BOOTSTRAP_SERVERSML Pipeline
Feature Engineering (PySpark)
The Spark job reads the trades Kafka topic, applies 10-second tumbling windows with a 30-second watermark, and writes four features per window to the market_features PostgreSQL table:
Run the pipeline:
spark-submit \
--packages org.apache.spark:spark-sql-kafka-0-10_2.12:3.5.0,org.postgresql:postgresql:42.7.1 \
spark/feature_pipeline.pyLSTM Price Direction Model
Reads market_features rows, builds 20-step sliding windows, and trains a 2-layer LSTM to predict binary price direction (up / down).
python -m ml.trainOutput: ml/model.pt (contains model weights, scaler params, feature metadata)
LightGBM Market Recommender
Downloads 2 years of BTC/USD hourly OHLCV data via yfinance (17,400+ bars), engineers 6 features matching the live PySpark output, and trains a 3-class classifier:
- Classes: BUY / HOLD / SELL (forward 3-period return, 0.5% threshold)
- Validation accuracy: 44.3% (baseline random = 33.3%)
- HOLD precision: 72% (the model is most reliable when recommending inaction)
python -m ml.train_recommenderOutput: ml/recommender.pkl, ml/rec_scaler.pkl, ml/rec_history.npz (17,485 embedding vectors for KNN similarity search)
Demo Modes
Rule-Based Demo (Primary)
Starts five agent types that simulate realistic exchange microstructure. Automatically cycles through five market regimes.
POST /api/v1/demo/start
POST /api/v1/demo/stop
GET /api/v1/demo/statusAgents: mm_alpha, mm_beta (market makers), trend_1-10 (trend followers), noise_1-4 (noise traders), whale (regime-transition bursts), panic_seller (flash crash only)
Regimes: ranging -> bull / bear / high_vol -> flash_crash -> ranging
Tick interval: 0.4 seconds. Each tick broadcasts fresh orderbook + metrics via WebSocket.
AI Demo (Additional)
Calls Groq Llama 3.3 every 4 seconds with live market context (mid, spread, regime, VWAP delta, order imbalance, trade velocity) and submits the LLM-generated orders to the matching engine.
POST /api/v1/demo/ai/start
POST /api/v1/demo/ai/stop
GET /api/v1/demo/ai/statusRequires GROQ_API_KEY in .env. Can run simultaneously with the rule-based demo.
API Reference
Order Submission
POST /api/v1/order{
"user_id": "trader1",
"side": "buy",
"price": 100.50,
"quantity": 5.0
}Response includes matched trades, remaining quantity, and matching latency in milliseconds.
Order Book
GET /api/v1/orderbook?depth=10Recent Trades
GET /api/v1/trades?limit=100Engine Metrics
GET /api/v1/metricsLSTM Prediction
GET /api/v1/predictionReturns: direction (up/down), confidence, model (lstm or heuristic), window_rows
Market Insights
GET /api/v1/insightsReturns: action (BUY/SELL/HOLD), confidence, regime, probabilities, insights, similar_conditions (KNN), rsi, feature_values, ai_commentary (Groq narrative, optional)
AI Chat
POST /api/v1/chat{ "message": "What does the current order imbalance signal?" }Returns a response from Llama 3.3 with live orderbook and metrics injected as context.
WebSocket
WS /api/v1/wsMessage types: orderbook_update, trade_executed, metrics_update. Send ping to receive pong.
Setup
Prerequisites
- Docker and Docker Compose
- Python 3.11+
- Node.js 20+ (frontend only)
- Groq API key (free tier at console.groq.com)
Environment
Copy .env and fill in your key:
DATABASE_URL=postgresql+asyncpg://flashledger:flashledger@localhost:5432/flashledger
KAFKA_BOOTSTRAP_SERVERS=kafka:9092
GROQ_API_KEY=gsk_...Full Stack with Docker
docker compose up --buildServices started: PostgreSQL, Zookeeper, Kafka, FlashLedger API, PySpark pipeline, React frontend
Frontend: http://localhost:3000 API docs: http://localhost:8000/docs
Local Development
# Backend
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8000
# Frontend
cd frontend
npm install
npm run devTrain the Models
Both commands are independent and can be run in any order. The recommender downloads its own training data; the LSTM requires the Spark pipeline to have produced market_features rows first.
# LightGBM recommender (downloads BTC/USD data automatically, ~2 min)
python -m ml.train_recommender
# LSTM (requires live market_features data from the Spark pipeline)
python -m ml.trainTesting
# Unit tests
pytest tests/ -v
# Load test (requires running server)
python tests/load_test.py --orders 10000 --concurrency 100License
MIT
MVP Features
- ✅ Accept buy and sell orders via REST API
- ✅ Maintain in-memory order book with heap-based priority queues
- ✅ Match orders using price-time priority
- ✅ Execute trades automatically
- ✅ Record trades in PostgreSQL
- ✅ Expose API endpoints for orders and order book
- ✅ Sub-5ms local latency target
System Flow
User submits order → API receives → Engine checks book → Match occurs → Trade executed → Book updated → Trade storedArchitecture
┌─────────────┐ ┌────────────────┐ ┌─────────────┐
│ FastAPI │────▶│ Matching │────▶│ Order Book │
│ /order │ │ Engine │ │ (In-Memory) │
└─────────────┘ └────────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ PostgreSQL │
│ (Trades) │
└─────────────┘Core Concepts
Order Book Structure
- Buy Side: Max heap (highest price first)
- Sell Side: Min heap (lowest price first)
Matching Rules
Orders match when: Buy Price >= Sell Price
Example:
Buy order: Price=100, Qty=10
Sell order: Price=99, Qty=5
Match happens at price=99, quantity=5
Remaining buy: 5 unitsPartial Fills
Buy 10 → Sell 4 available
Trade executes for 4
Remaining buy: 6 (stays in book)Quick Start
With Docker (Recommended)
# Start services
docker-compose up -d
# API available at http://localhost:8000
# Health check: http://localhost:8000/healthLocal Development
# Install dependencies
pip install -r requirements.txt
# Start PostgreSQL (or use Docker)
docker run -d --name postgres \
-e POSTGRES_DB=flashledger \
-e POSTGRES_USER=flashledger \
-e POSTGRES_PASSWORD=flashledger \
-p 5432:5432 \
postgres:15-alpine
# Run the server
uvicorn app.main:app --reload --port 8000API Endpoints
POST /api/v1/order
Submit a new order.
Request:
{
"user_id": "user1",
"side": "buy",
"price": 100,
"quantity": 10
}Response:
{
"order_id": "uuid",
"order_status": "matched",
"trades": [
{
"price": 99,
"quantity": 5,
"trade_id": "uuid"
}
],
"remaining_qty": 5,
"latency_ms": 0.234
}GET /api/v1/orderbook
Get current order book state.
Response:
{
"symbol": "FLASH",
"bids": [
{"price": 99, "quantity": 100, "orders": 3}
],
"asks": [
{"price": 101, "quantity": 50, "orders": 2}
],
"bid_count": 1,
"ask_count": 1
}GET /api/v1/trades
Get recent executed trades.
Response:
[
{
"trade_id": "uuid",
"buy_order_id": "uuid",
"sell_order_id": "uuid",
"buyer_id": "user1",
"seller_id": "user2",
"price": 100,
"quantity": 10,
"timestamp": "2024-01-01T12:00:00"
}
]DELETE /api/v1/order/{order_id}
Cancel an existing order.
GET /api/v1/metrics
Get engine metrics.
Project Structure
flashledger/
├── app/
│ ├── main.py # FastAPI entry point
│ ├── engine/
│ │ ├── order_book.py # Heap-based order book
│ │ └── matching_engine.py # Price-time priority matching
│ ├── api/
│ │ └── routes.py # REST endpoints
│ └── db/
│ ├── models.py # Trade model
│ └── database.py # PostgreSQL connection
├── tests/
│ ├── test_order_book.py
│ ├── test_matching_engine.py
│ └── load_test.py # 10k order benchmark
├── docker-compose.yml
├── Dockerfile
├── requirements.txt
└── README.mdTesting
Unit Tests
pytest tests/ -vLoad Test (10k Orders)
# Start the server first
python tests/load_test.py --orders 10000 --concurrency 100Sample Output:
Orders: 10000
Duration: 2.5 seconds
Orders/second: 4000
Median latency: 2.1 ms
P95 latency: 4.2 ms
✅ PASS: Median latency (2.1ms) < 5ms targetData Flow Example
- User A submits:
BUY 10 @ $100 - Order rests in buy book (no match)
- User B submits:
SELL 5 @ $99 - Match found: Buy $100 >= Sell $99
- Trade executed: 5 units @ $99
- User A's order: 5 remaining in book
- User B's order: fully filled
- Trade persisted to PostgreSQL
MVP Success Criteria
Tech Stack
- Framework: FastAPI (Python 3.11)
- Database: PostgreSQL 15
- ORM: SQLAlchemy 2.0 (async)
- Container: Docker Compose
License
MIT
