SPB Git forge
1commits 1branches 0releases
189.0 KBsize
maindefault branch
3 h agolast push
Python 54.7% TypeScript 42.5% SQL 1.9%
2.6 KB

# Architecture

text
                 ┌──────────────┐   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.