Architecture
ClearEdge is a small set of cooperating processes on one machine. Nothing listens on a public interface by default, and the request-driven web layer is deliberately separated from the trading engine.
The processes
Section titled “The processes” Browser (React UI, Vite :5173) │ /api proxy FastAPI API (:8000) ─────────── Postgres (users, runs, audit log, session fills, approvals, │ enqueue jobs │ saved charts, generated strategies, copilot threads) Redis (arq queue + pub/sub) ── Worker ─────┘ │ │ runs NautilusTrader (a BacktestEngine, or a live TradingNode) │ ▼ │ ParquetDataCatalog (./data/catalog — the system of record for bars) └─ telemetry / control ── ats.paper / ats.live runners ── IB Gateway (Docker)| Process | What it is | Responsibility |
|---|---|---|
| API | FastAPI + Uvicorn (ats.api.main:app) |
Auth, CRUD, enqueuing jobs, serving results. Never runs the trading engine. |
| Worker | an arq worker (ats.workers.settings) |
Runs every heavy job: backtests, the gauntlet stages, optimizations, ingestion. This is where NautilusTrader’s BacktestEngine executes. |
| Postgres | application state | Users, run metadata + metrics, the append-only audit log, session fills, go-live approvals, saved charts, generated strategies, copilot threads. Not the engine’s own state. |
| Redis | queue + pub/sub | The arq job queue, plus progress/telemetry/health keys the API reads to stream updates. |
| Catalog | a ParquetDataCatalog on local disk |
The single source of truth for market bars. Backtests read only from here. |
| IB Gateway | Interactive Brokers’ gateway, in Docker | The broker connection for paper and live trading. The ats.paper / ats.live runners connect to it. |
The frontend is a Vite + React 19 single-page app that talks to the API over /api. In development
it runs on :5173 and proxies to the API on :8000; in a packaged deployment it is built to static
assets.
Why API and worker are separate
Section titled “Why API and worker are separate”The trading engine is synchronous, CPU-bound, and stateful; the web layer must stay responsive and must never block on (or crash because of) an engine run. So the API only ever enqueues work onto Redis and reads results back from Postgres/Redis. The worker pulls jobs, runs NautilusTrader, writes artifacts to disk and metrics to Postgres, and publishes progress to Redis. The two communicate only through Postgres and Redis — never in-process.
get_settings() (the configuration singleton) is read at startup by both processes, which is why
changing a key takes effect only after a restart — see the
configuration reference.
Data flow of a backtest
Section titled “Data flow of a backtest”- You submit a run from the UI →
POST /api/backtestswrites aBacktestRunrow (statusQUEUED) and enqueues an arq job. - The worker picks up the job, resolves the strategy from the registry, and runs it on a
NautilusTrader
BacktestEnginefed only by the local catalog. - The worker writes artifacts (equity curve, fills, positions, per-kind JSON) to
./artifacts/<run>and the summary metrics to theBacktestRunrow; progress is published to Redis as it goes. - The UI polls the run (and a Redis progress key) and renders the result when status is
DONE.
Because the engine reads closed bars from a fixed catalog and orders fill on the next bar, runs are reproducible and free of look-ahead.
Strategies are code
Section titled “Strategies are code”Built-in strategies live in backend/ats/strategies/ and are registered at import time — see the
strategy contract. Strategies submitted from the web are not executed
as arbitrary code, with one deliberate exception: AI-generated strategies from the
Studio, which run only behind a validation + isolation sandbox (see the
security model).
Live/paper execution
Section titled “Live/paper execution”The same registered strategy code runs in a live TradingNode as in a backtest. The ats.paper and
ats.live runners are separate processes that connect to the IB Gateway, enforce a pre-trade
risk engine, stream telemetry to Redis, and persist fills and a session record
to Postgres. Live trading is gated behind an explicit, audited approve-to-live step.
Tech stack
Section titled “Tech stack”- Backend: Python 3.12 (managed by uv), FastAPI, Pydantic v2 + pydantic-settings, SQLAlchemy 2.0 (async) + Alembic, arq + Redis, NautilusTrader (with the IB adapter), pandas, Optuna, Databento.
- Frontend: Vite, React 19, TypeScript, MUI, TanStack Query, klinecharts.
- Infra: Docker Compose for Postgres, Redis, and the IB Gateway (
infra/).
See also
Section titled “See also”- Concepts & glossary
- Deployment
- Database & migrations
- Architecture decisions (ADR-001)