A production-grade cryptocurrency trading bot that autonomously connects to Binance, ingests real-time market data, computes technical signals, manages risk, and executes orders — all with full observability, security hardening, and a controlled deployment pipeline from paper trading to live capital.
This is not a prototype or script. It is a multi-layered, event-driven industrial system designed to scale from a single strategy and exchange at MVP to a multi-strategy, multi-exchange platform post-MVP.
The system is built as five independent, event-driven layers. Each layer communicates via a shared message bus (Redis pub/sub) and writes to shared state (Redis + TimescaleDB). No layer depends directly on another — they are decoupled by design.
┌─────────────────────────────────────────────────────────────────┐
│ EXTERNAL DATA SOURCES │
│ Binance REST API │ WebSocket Feed │ Testnet/Mainnet │
└─────────────────────────────┬───────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ LAYER 1 — DATA INGESTION │
│ │
│ AsyncExchangeClient → Normaliser → Validator → Deduper │
│ │ │
│ ├──────────────────────────────────────────────────────►│
│ │ TimescaleDB (OHLCV history) │
│ │ │
│ └──────────────────────────────────────────────────────►│
│ Redis (latest tick cache, 5s TTL) │
└─────────────────────────────┬───────────────────────────────────┘
│ asyncio.Queue (tick stream)
▼
┌─────────────────────────────────────────────────────────────────┐
│ LAYER 2 — STRATEGY ENGINE │
│ │
│ Feature Pipeline → Strategy Registry → Signal │
│ (RSI, MACD, BBands, @strategy decorator Object │
│ EMA, pandas-ta) BaseStrategy ABC (typed) │
│ │
│ Strategies: RSI Mean Reversion (MVP) │
│ Future: ML signals, arbitrage, sentiment, on-chain │
└─────────────────────────────┬───────────────────────────────────┘
│ Signal(symbol, direction,
│ confidence, size_pct, ttl)
▼
┌─────────────────────────────────────────────────────────────────┐
│ LAYER 3 — RISK MANAGEMENT GATE │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────────────┐ │
│ │ Position size│ │ Stop-loss │ │ Daily loss limit │ │
│ │ check (≤5%) │ │ check (−2%) │ │ halt (−5% day) │ │
│ └──────────────┘ └──────────────┘ └────────────────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────────────┐ │
│ │ Rate limiter │ │ Concentration│ │ Circuit breaker │ │
│ │ (orders/min) │ │ limit │ │ (3 consec. rejects) │ │
│ └──────────────┘ └──────────────┘ └────────────────────────┘ │
│ │
│ All state stored in Redis (cross-process) │
│ PASS → Execution Layer FAIL → Log + Alert + Discard │
└─────────────────────────────┬───────────────────────────────────┘
│ Approved Signal
▼
┌─────────────────────────────────────────────────────────────────┐
│ LAYER 4 — ORDER EXECUTION │
│ │
│ Smart Order Router → PAPER ENGINE (PAPER_TRADE=true) │
│ → SHADOW ENGINE (LIVE=false) │
│ → LIVE ENGINE (LIVE=true) │
│ │
│ State machine: pending → open → partial → filled/cancelled │
│ Retry: tenacity exponential backoff (1s, 2s, 4s) │
│ Events: Redis pub/sub → order_placed, order_filled, failed │
│ Audit: append-only audit_log.jsonl (every order) │
└─────────────────────────────┬───────────────────────────────────┘
│ Order lifecycle events
▼
┌─────────────────────────────────────────────────────────────────┐
│ LAYER 5 — INFRASTRUCTURE & OPS │
│ │
│ Prometheus (/metrics) → Grafana (dashboard) │
│ structlog (JSON logs) → ELK / Loki (future) │
│ Telegram alerts → Circuit breaker + daily digest │
│ Docker Compose → VPS deployment │
│ TimescaleDB → Redis │
│ Vault / .env secrets → IP whitelist on exchange │
└─────────────────────────────────────────────────────────────────┘┌─── VPS (Hetzner / DigitalOcean / Vultr Tokyo) ────────────────┐
│ │
│ ┌──────────┐ ┌──────────┐ ┌────────────┐ ┌────────────┐ │
│ │ app │ │ redis │ │ timescaledb│ │ prometheus │ │
│ │ (Python) │ │ :6379 │ │ :5432 │ │ :9091 │ │
│ │ :9090 │ │ │ │ │ │ │ │
│ └────┬─────┘ └────┬─────┘ └─────┬──────┘ └─────┬──────┘ │
│ │ │ │ │ │
│ └─────────────┴──────────────┴───────────────┘ │
│ Docker network │
│ ┌──────────┐ │
│ │ grafana │ port 3000 → operator browser │
│ │ :3000 │ │
│ └──────────┘ │
│ │
│ VPS IP whitelisted on Binance API key │
│ All secrets in .env (never in Git) │
└─────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
Binance Mainnet Telegram Bot
(orders, market data) (alerts + digest)Every strategy must pass each gate sequentially. No skipping.
BACKTEST PAPER TRADE SHADOW LIVE FULL LIVE
───────── ─────────── ─────────── ─────────
6 months 72 hours 7 days Week 1: 5%
historical live data real orders Week 2: 25%
OOS Sharpe > 0.8 no crashes at 0.1% size Week 3: 50%
max DD < 15% all risk limits slippage < 0.2% Week 4: 100%
enforced vs paper
│ │ │ │
▼ ▼ ▼ ▼
Gate: metrics Gate: 72h uptime Gate: slippage Gate: weekly
assert passes zero exceptions delta assertion P&L review| Component | Technology | Version | Purpose |
|---|---|---|---|
| Language | Python | 3.11+ | Primary application language |
| Async runtime | asyncio | stdlib | Concurrent data feeds and execution |
| Type checking | mypy (strict) | latest | Catch bugs at compile time |
| Linting | ruff | latest | Fast code quality enforcement |
| Component | Technology | Version | Purpose |
|---|---|---|---|
| Time-series DB | TimescaleDB | latest-pg15 | OHLCV history, 2yr retention, compression |
| In-memory cache | Redis | 7+ | Latest tick cache (5s TTL), risk state, portfolio |
| Message bus | Redis pub/sub | 7+ | Order lifecycle events, circuit breaker signals |
| DB driver | asyncpg | latest | Native async PostgreSQL — no ORM overhead |
| Data validation | Pydantic v2 | 2.x | Typed models for Tick, OHLCV, Signal |
| ORM | None | — | asyncpg direct SQL for performance |
| Component | Technology | Version | Purpose |
|---|---|---|---|
| Exchange library | ccxt / ccxt.pro | latest | Unified async API for Binance (+ 100 others) |
| Exchange | Binance | — | Primary exchange, testnet + mainnet |
| WebSocket | ccxt.pro watch_* | — | Sub-100ms tick delivery |
| REST | ccxt async | — | OHLCV fetch, order placement, balance |
| Component | Technology | Version | Purpose |
|---|---|---|---|
| Indicators | pandas-ta | latest | RSI, MACD, BBands, EMA computation |
| DataFrames | pandas | 2.x | Feature computation and vectorisation |
| Backtesting | vectorbt | latest | Vectorised strategy simulation |
| Numeric | numpy | 1.x | Returns computation, Sharpe calculation |
| ML (post-MVP) | XGBoost / LightGBM | — | Gradient boosted signal models |
| Deep learning (post-MVP) | PyTorch | — | LSTM on OHLCV sequences |
| Component | Technology | Version | Purpose |
|---|---|---|---|
| Retry logic | tenacity | latest | Exponential backoff on exchange errors |
| Scheduling | APScheduler | 3.x | Daily digest cron, midnight equity reset |
| Config | pydantic-settings | 2.x | Typed env var loading from .env |
| Component | Technology | Version | Purpose |
|---|---|---|---|
| Metrics | prometheus-client | latest | Histograms, counters, gauges |
| Dashboards | Grafana | 10.3+ | Live operational dashboard |
| Logging | structlog | latest | Structured JSON log output |
| HTTP server | aiohttp | 3.x | /metrics and /health endpoints |
| Alerting | python-telegram-bot | 20.x | Critical alerts + daily digest |
| Component | Technology | Version | Purpose |
|---|---|---|---|
| Containers | Docker Compose | latest | Full stack in one command |
| Secrets | .env + python-dotenv | — | Never hardcode credentials |
| Audit log | JSONL file (fcntl locked) | — | Immutable order trail |
| VPS | Hetzner / DigitalOcean | — | Co-located near Binance |
Every component reacts to events on a shared bus. Ticks flow from WebSocket → asyncio.Queue → normaliser → Redis/DB. Orders flow as events through Redis pub/sub. No component polls another — they subscribe and react.
The risk manager is a hard synchronous gate. There is no code path from signal to execution that bypasses it. All risk state lives in Redis so multiple strategy processes share a single consistent view of portfolio exposure.
Strategy plugins implement BaseStrategy.compute(features) → Signal | None. They receive a feature DataFrame and return a signal. They must never read from or write to self between calls. This makes strategies independently testable, hot-swappable, and safe to run in parallel.
Paper fills, shadow fills, and live fills all produce the same log schema with a paper=true/false flag. This means the same analysis scripts work across all modes, and paper vs live comparison requires a single SQL query.
No strategy touches real capital until it has passed four sequential gates: backtest → paper → shadow → live. Each gate has a hard numeric assertion. No human discretion required to know if a strategy passed.
Every critical metric is instrumented from day one: order latency (p50/p95/p99), fill rate, slippage, per-strategy P&L, circuit breaker triggers, tick freshness. The Grafana dashboard answers the four morning questions before you even open the logs.
API keys are trade-only (no withdrawal), IP-whitelisted to the VPS, stored in .env (never Git), validated on every startup. A compromised key is useless from any other IP. An audit log records every order with a cryptographic timestamp.
┌─────────────────────────────────────────────────────────────────┐
│ PANEL 1: Equity Curve PANEL 2: Order Latency│
│ │
│ $10,450 ┤ /───── 500ms ┤ │
│ $10,200 ┤ /─/ 250ms ┤─────────── │
│ $10,000 ┤─────/ 100ms ┤ ─── │
│ └──────────────── time └──────────────│
│ strategy_pnl_usd{total} p50 p95 p99 │
│ │
├─────────────────────────────────────────────────────────────────┤
│ PANEL 3: Risk State PANEL 4: Data Health │
│ │
│ Circuit breaker: [ OK ] btc_usdt: [ 2s ] ✓ │
│ Daily loss: -0.8% of -5% limit eth_usdt: [ 3s ] ✓ │
│ Risk rejections: 3 (last 1h) │
│ CB trips (total): 0 Feed silence alert │
│ threshold: 60s │
└─────────────────────────────────────────────────────────────────┘| Phase | Weeks | Deliverable | Gate |
|---|---|---|---|
| Phase 1 — Foundation | 1–2 | Live BTC/USDT tick data in TimescaleDB + Redis | Tick flowing into DB, Redis cache live |
| Phase 2 — Strategy & Backtest | 3–5 | RSI strategy backtested on 6 months OOS data | Sharpe > 0.8, max DD < 15% |
| Phase 3 — Execution & Ops | 6–8 | Full paper trading loop + Grafana dashboard | 72h uptime, all risk limits enforced |
| Phase 4 — Go Live | 9–12 | Shadow live → full live at 5% capital | Slippage delta < 0.2%, week 1 P&L review |
- Single exchange: Binance (testnet + mainnet)
- Single strategy: RSI mean-reversion with EMA trend filter
- Market and limit order types
- Hard-coded risk params via YAML config
- Docker Compose deployment on single VPS
- Prometheus + Grafana observability
- Telegram alerts (circuit breaker + daily digest)
- Full four-gate deployment pipeline
- Multi-exchange + smart order routing (SOR)
- ML signal models (XGBoost, LightGBM, PyTorch LSTM)
- TWAP / VWAP execution algorithms
- Sentiment analysis (NLP on news/social)
- On-chain data signals (whale flows, exchange reserves)
- Kubernetes + horizontal scaling
- ELK stack / distributed tracing (OpenTelemetry + Jaeger)
- Co-location / latency optimisation
- Additional pairs: ETH/USDT, BNB/USDT
trading-bot/
├── src/
│ ├── ingestion/ # WebSocket feed, exchange client, normaliser, DB writer
│ │ ├── exchange_client.py
│ │ ├── feed.py
│ │ ├── normaliser.py
│ │ ├── validator.py
│ │ ├── deduplicator.py
│ │ └── db_writer.py
│ ├── strategy/ # BaseStrategy ABC, registry, feature pipeline, strategies
│ │ ├── base.py
│ │ ├── registry.py
│ │ ├── feature_pipeline.py
│ │ ├── rsi_strategy.py
│ │ └── passthrough.py
│ ├── execution/ # Order executor, state machine, paper engine, events
│ │ ├── order_executor.py
│ │ ├── order_state.py
│ │ ├── paper_engine.py
│ │ └── events.py
│ ├── risk/ # Risk manager, checks, circuit breaker
│ │ ├── manager.py
│ │ ├── checks.py
│ │ └── circuit_breaker.py
│ ├── backtest/ # Data loader, engine, walk-forward, reporter, metrics
│ │ ├── data_loader.py
│ │ ├── engine.py
│ │ ├── signal_vectoriser.py
│ │ ├── walk_forward.py
│ │ ├── reporter.py
│ │ ├── metrics.py
│ │ └── gate.py
│ ├── infra/ # Metrics server, alerter, watchdog, audit log, startup checks
│ │ ├── metrics_server.py
│ │ ├── alerter.py
│ │ ├── alert_manager.py
│ │ ├── watchdog.py
│ │ ├── audit_log.py
│ │ └── startup_checks.py
│ └── common/ # Shared models, config, cache, metrics definitions
│ ├── models.py # Tick, OHLCV, Signal, OrderResult (Pydantic)
│ ├── config.py # pydantic-settings from .env
│ ├── cache.py # TickCache (Redis helper)
│ └── metrics.py # All Prometheus metric definitions
├── tests/
│ ├── unit/ # No external dependencies — fast, run in CI
│ └── integration/ # Require Docker (DB, Redis) — run pre-deploy
├── infra/
│ ├── docker/ # Dockerfile, .dockerignore
│ ├── prometheus/ # prometheus.yml scrape config
│ └── grafana/
│ └── provisioning/ # Auto-configured datasource + dashboard JSON
├── docs/
│ ├── runbooks/ # api-key-rotation.md, circuit-breaker.md, etc.
│ └── live-reviews/ # Week-by-week performance review notes
├── runs/ # Backtest artifacts (gitignored)
├── logs/ # audit_log.jsonl (gitignored)
├── scripts/ # analyse_shadow_slippage.py, check_shadow_gate.py, etc.
├── config/
│ ├── risk_shadow.yaml # Tight thresholds for shadow live
│ └── risk_live.yaml # Normal thresholds for full live
├── docker-compose.yml
├── pyproject.toml
├── .env.example # Template — committed to Git
├── .env # Real secrets — NEVER committed
└── README.md┌─── Security Layers ─────────────────────────────────────────────┐
│ │
│ Layer 1 — Credential isolation │
│ All API keys, DB passwords in .env only │
│ .env in .gitignore — verified with git log --all -- .env │
│ │
│ Layer 2 — Exchange-level IP restriction │
│ Binance API key whitelisted to VPS IP only │
│ Key has trade-only permissions — withdrawal disabled │
│ Startup check: bot refuses to run if withdrawal enabled │
│ │
│ Layer 3 — Immutable audit trail │
│ Every order attempt logged to append-only JSONL with timestamp │
│ File-locked writes prevent corruption from concurrent access │
│ │
│ Layer 4 — Runtime circuit protection │
│ Circuit breaker halts all trading on anomaly │
│ Daily loss limit provides portfolio-level stop │
│ All risk state in Redis — cross-process, no race conditions │
│ │
└─────────────────────────────────────────────────────────────────┘| Metric | Target | How measured |
|---|---|---|
| Tick delivery latency | < 100ms | tick_cache_age_seconds (Prometheus) |
| Order placement latency p95 | < 500ms | order_latency_ms histogram |
| Paper-vs-live slippage delta | < 0.2% | shadow live gate script |
| Backtested Sharpe (OOS) | > 0.8 | Phase 2 gate assertion |
| Backtested max drawdown (OOS) | < 15% | Phase 2 gate assertion |
| System uptime (paper) | 72h no crash | Phase 3 gate |
| Data freshness | < 10s | Grafana alert threshold |
| Fill rate | > 95% | orders_filled / orders_placed |
The MVP is complete when all of the following are true:
- All 20 tasks and 107 subtasks marked Done in ClickUp
- Four-gate pipeline completed: backtest → paper → shadow → live
- Bot has traded real capital for 7 days at 5% position size
- 7-day live review completed and documented
- All Grafana panels showing live data
- Telegram alerts confirmed working (test alert received)
- Zero critical security violations (IP whitelist, no withdrawal perm, .env clean)
- Runbooks written for: circuit breaker, feed silence, API key rotation, daily loss limit
- Scaling plan documented and reviewed by team
- Post-MVP roadmap items logged for next sprint
Document maintained by the Backergsoft engineering team. Last updated: March 2026. Project board: Trading App in ClickUp