System design

Architecture

AURA is split into a live trading service and a walk-forward parameter optimizer, sharing a codebase but never sharing an event loop or a database write path. Below is the per-cycle lifecycle followed by the system's key invariants.

  1. 01

    Data ingestion

    A coverage-aware provider chain (historical archive → multiple tail feeds → CoinGecko fallback) merges into a per-symbol Parquet cache. Freshness short-circuits and provider-lookback padding stabilize backtests without hammering live APIs.

  2. 02

    Signal generation

    Universe is regenerated daily under a momentum / SMA / drawdown screen. A composite scoring function ranks candidates; robust voting across multiple historical offsets favours stable rank over single-snapshot noise. A two-cycle regime hysteresis suppresses bull / sideways / bear flips at the boundary.

  3. 03

    Execution engine

    A fully synchronous, single-threaded loop builds intents from the rebalance plan, hashes each intent into a deterministic clientOrderId for idempotent retries, and routes them through CCXT to Binance Spot. Sell-clamp logic retries on transient balance-fetch failures rather than aborting the sell.

  4. 04

    Risk management

    Three concentric gates — a kill-switch on rolling drawdown, per-position stop-loss / take-profit, and a portfolio-level cost-benefit check — must clear before any capital moves. The sync guard prevents phantom kill-switch trips when a transient broker error returns an empty position set.

  5. 05

    Logging & persistence

    Every cycle writes events, intents, orders, and snapshots to an embedded SQLite. Permanent diagnostic logs ([BOOT], [RISK_TICK], [SL_CHECK], [SYNC_GUARD], [ENTRY_RECOVER]) surface any silent regression in journalctl alone. Stop-loss reachability is preserved across restarts via entry-price recovery from snapshots.

Invariants

Four properties we never compromise on.

Determinism
Same inputs → same plan. No threading, no event loops, no async surprises.
Idempotency
clientOrderId hashing means a retry after an ambiguous failure cannot double-fill.
Crash safety
Boot reconciliation refreshes any broker-acknowledged order whose fill callback was lost.
Hot reload
Risk thresholds and selector weights can be tuned between cycles without a service restart.

A more detailed internal reference, including module-level wiring and incident history, lives in ARCHITECTURE.md at the repository root.