Forex Daemon
A streaming, self-supervising FX trading daemon
What it is
A long-running Python daemon that runs automated foreign-exchange strategies against the OANDA API. It scans for setups on a fixed candle cycle, sizes and places trades under strict risk rules, and manages open positions in real time. Not publicly hosted — it runs as a background service on a private machine — but it’s the most operationally involved project here.
Architecture
The daemon holds persistent WebSocket connections rather than polling on a cron: one shared pricing stream and a per-account transaction stream. A handful of cooperating threads — a scheduler, a price/transaction event manager, and a state flusher — share a single lock-guarded state object. The whole core is written with the Python standard library only (no pandas/numpy/requests); even the indicators are computed by hand.
Engineering highlights
- Streaming-first design — reacting to live ticks (rather than scheduled polling) lets it manage positions at sub-second latency: when a trade reaches its first risk target, a manager thread automatically closes part of the position and moves the stop to breakeven.
- Layered risk gates — each independently configurable and measured: a drawdown circuit breaker, a consecutive-loss cooldown, ATR-based position sizing to a fixed risk fraction, and trend/momentum filters that can veto a signal.
- Multi-account orchestration — one daemon manages several accounts at once, sharing the data pipeline but keeping separate configs and risk state per account.
- Resilience by construction — graceful
SIGTERMshutdown that flushes state, infinite stream reconnect loops, and a supervisor that respawns the manager thread if it dies. OANDA is treated as the source of truth, so a restart simply re-reads open trades and resumes. - Custom observability — a hand-rolled Prometheus exporter (no client library) serves live account/trade gauges plus file-backed counters the daemon writes every few minutes, all visualized in a Grafana dashboard.
- Tested and validated — 200+ pytest cases cover the indicators, sizing, scheduling, streams, and end-to-end daemon behavior, and a walk-forward backtesting framework checks strategies against held-out data to guard against overfitting.
Process supervision
Runs under systemd on Linux (with a companion metrics service and a weekly “retro” analysis timer) and launchd on macOS for development — auto-starting on boot and restarting on failure.
What I learned
Anything touching real money raises the bar on reliability: idempotency, safe restarts, and observability stopped being nice-to-haves and became requirements. Moving from cron-scheduled scripts to a streaming daemon was the turning point — it made real-time position management possible and the whole system far easier to reason about.