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