Skip to content

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.

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.

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.

  1. You submit a run from the UI → POST /api/backtests writes a BacktestRun row (status QUEUED) and enqueues an arq job.
  2. The worker picks up the job, resolves the strategy from the registry, and runs it on a NautilusTrader BacktestEngine fed only by the local catalog.
  3. The worker writes artifacts (equity curve, fills, positions, per-kind JSON) to ./artifacts/<run> and the summary metrics to the BacktestRun row; progress is published to Redis as it goes.
  4. 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.

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).

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.

  • 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/).