A live algorithmic trading platform — designed, built, and operated solo, 24/7.
TypeScript · PostgreSQL · Binance Futures · Running in production since 2026.
01 / Architecture
Architecture
02 / Highlights
Engineering highlights
-
Backtesting engine
Custom engine validated bar-by-bar against research notebooks. Models fees, slippage, and funding — not idealized fills.
-
Idempotent execution
Every external side effect wrapped in idempotency guards with state reconciliation against the exchange. Restarts are boring.
-
Incident response
Failures are documented, root-caused, and regression-guarded. See the incident log below.
-
LLM analysis layer
Claude API integrated into the pipeline for contextual market analysis and alert triage.
03 / Incidents
Incident log
Real systems fail. These are some of the failures, and what they changed.
INC-001 WebSocket event handler was dead code
- Impact
- Order-fill detection silently ran on a 30-second polling fallback instead of sub-second WebSocket events. The reconciliation safety net masked the failure — nothing visibly broke, which is exactly why it lasted.
- Root cause
- The exchange client library transforms raw WebSocket payloads before delivery — renaming and flattening fields. The handler checked a raw-format field that no longer existed, so it never matched and never ran.
- Fix
- Aligned the event interface and field access with the library's actual transformed shape.
- Prevention
- Runtime payload shapes are verified at integration boundaries instead of trusted from docs; a log at the callback boundary now exposes shape drift immediately.
INC-002 False-positive stream-silence alerts
- Impact
- Recurring "stream silent — forcing reconnect" alerts whenever a pending order was resting. No real outage ever occurred.
- Root cause
- The watchdog treated silence on the user-data stream as a dead connection. That stream only emits on account state changes — with a pending order resting, silence is the expected state, not a failure.
- Fix
- Liveness is now derived from a continuously-emitting market stream; the user-data check became a precautionary key refresh plus a forced reconciliation sweep.
- Prevention
- Connectivity is monitored unconditionally, and "no data received" is no longer conflated with "connection is dead."
INC-028 Dual-ID mismatch on stop-loss fills
- Impact
- Stop-loss fills executed correctly on the exchange, but the primary WebSocket handler exited silently without matching them; the reconciliation net closed the records roughly 30 minutes late.
- Root cause
- The exchange uses two identifiers for conditional orders — placement returns an algo ID, while the fill event carries a regular order ID. The handler queried storage by the fill's order ID, which never matched the stored algo ID, and returned without logging anything.
- Fix
- Both identifiers became first-class schema columns, normalized at the library boundary; the handler matches on either ID and backfills the missing one on first fill.
- Prevention
- Unit and integration tests replay the exact mismatch, and unmatched fill events now log a warning — any future ID-matching bug is immediately visible.
04 / Stack
- TypeScript
- Node.js
- PostgreSQL
- Prisma
- React
- Lightweight Charts
- Railway
- Cloudflare
- Webshare Proxies
- Binance Futures API
- Discord API
- Claude API