# Architecture ``` ┌──────────────┐ SSE /api/market/stream ┌──────────────┐ Browser ──────▶│ Next.js web │──────── rewrite /api ──────▶│ FastAPI api │──▶ Postgres (candles, trades, book, (owner) │ :8471 │ │ :8470 │ runs, audit, risk, paper ledger) └──────────────┘ └──────┬───────┘ │ Redis pub/sub `ktrade:md`, health keys ┌──────────────┐ REST /0/public/* (pairs, OHLC) │ Kraken ───────▶│ ingest worker│────────────────────────────────────┘ REST + WS v2 │ (ktrade worker) WS v2 ticker/book/trade/ohlc → Redis + Postgres └──────────────┘ ``` **Event-time semantics.** Candles are stored by open time with a `closed` flag computed from exchange time; strategies only ever see closed bars; the backtester executes at the next bar's open. WS messages carry the exchange timestamp and the local `received_at`; book validity is tracked per update (CRC32 checksum). **Shared interfaces.** `Strategy.run(df) → target exposure` and `RiskGateway.evaluate(intent, portfolio, market)` are the same objects used by the backtester, the paper simulator (Phase 4) and the live adapter (Phase 5). `CostModel` (fees/spread/slippage/impact/participation/latency) is shared between backtest and paper fills. **Modules** (`apps/api/ktrade`): `kraken/` (rest, ws, checksum, models) · `ingestion/` (pairs, backfill, stream) · `market/` (queries, features) · `strategy/` (SDK, plugins, registry) · `backtest/` (costs, engine, metrics, validation, runner) · `risk/` (gateway) · `execution/` (preflight; paper/live to come) · `api/` (auth, routes) · `workers/` (ingest) · `db/` (pool, migrations, audit) · `cli.py`. **Processes in production** (PM2 on the MacLustr node): `crypto-trade-bot-api` (uvicorn), `crypto-trade-bot-worker`, `crypto-trade-bot-web` (next start). Public route: MacLustr Tunnel (Caddy on BHS64) → web :8471 → `/api` rewrite → :8470. **Scaling path.** Ingestion is per-universe; a second worker can own a disjoint universe (Redis channel is shared). Backtests run in-process via `asyncio.create_task`; a queue (Redis/RQ) is the next step when runs get long.