Skip to content

Live trading

Live trading places real orders on a real Interactive Brokers account (a U… id). The same strategy code that you backtested and paper-traded runs unchanged. Because this is real money, it sits behind multiple deliberate gates and a tighter risk profile.

Live trading is for a personal build you operate yourself. The sold/research edition ships with ATS_ENABLE_LIVE_TRADING=false — research and paper only.

  1. Edition flagATS_ENABLE_LIVE_TRADING must be true, or the Live tab doesn’t even appear.
  2. A separate live gateway — the live IB Gateway runs on its own port (ATS_IB_LIVE_PORT, default 4001) with the live account id (ATS_IB_LIVE_ACCOUNT_ID, a U… id — the guard rejects a DU-prefixed paper id here).
  3. An audited approve-to-live step — a strategy cannot trade live until you explicitly approve it, and that approval is recorded (GoLiveApproval) in the append-only audit log. The research ladder makes this an explicit step, not a default.

A Studio-generated strategy is no exception — it must clear the gauntlet and the approval like any other.

Nautilus’s RiskEngine runs inside the trading node and denies any order that breaches:

  • max notional per orderATS_LIVE_RISK_MAX_NOTIONAL_PER_ORDER (default 5000, deliberately tighter than paper’s 25000).
  • max order-submit rateATS_LIVE_RISK_MAX_ORDER_SUBMIT_RATE (default 2/00:00:01).

Denied orders never reach the broker. Raise these in backend/.env only once proven.

  • Kill switch — an operator control halts a running session immediately.
  • Reconciliation — on connect, the node reconciles its orders/positions against the broker’s truth, so a restart can’t double-trade or lose track.
  • Gateway resilience — a monitor watches gateway health and alerts on a healthy→broken transition; IBC handles the gateway’s nightly/weekly restarts.
  • Audit log — every order intent and security-relevant action is recorded, append-only.

The same strategy code, gated. Run one gateway at a time — paper and live share your IB username, and IB allows a single session.

  1. Validate on paper until you trust the behavior; confirm the Research ladder’s paper rung passes.
  2. Record your sign-off (audited; the live runner refuses to start without it):
    Terminal window
    cd backend
    uv run python -m ats.cli approve-live --strategy ibs_reversion \
    --instrument QQQ.NASDAQ --note "2w paper, 14 trades, matched backtest"
    (revoke-live removes it. See the admin CLI.)
  3. Configure — set ATS_IB_LIVE_ACCOUNT_ID (your U… id); review the ATS_LIVE_RISK_* caps; make sure 2FA is on.
  4. Swap gateways and run (start small, during market hours, watching the Live tab and the IB portal):
    Terminal window
    docker compose -f infra/docker-compose.yml --profile ib stop ib-gateway-paper
    docker compose -f infra/docker-compose.yml --profile ib-live up -d --wait
    cd backend && uv run python -m ats.live --strategy ibs_reversion \
    --instrument QQQ.NASDAQ --bar-spec 1-DAY-LAST --params '{"buy_threshold": 0.15}'
    The runner prints the session summary (account, params, risk caps, who approved) and requires you to type the live account id before anything connects (--i-understand <account-id> for supervised scripts). The Live tab mirrors the Paper tab — same kill switch, a separate Redis namespace, and a REAL MONEY badge.

Guards: the paper runner refuses ids that aren’t DU; the live runner refuses anything that isn’t a U… account and requires the typed confirmation. A live book (--sleeves-json) is allowed, but every sleeve must have its own approve-live sign-off (the gate loops over all of them).

Live runs as its own process (ats.live), or from the Live tab’s start panel (same shape as paper, pointed at the live gateway). Sessions, telemetry, controls, and history work identically to paper.

  • ARM64/Apple Silicon gateway image support is experimental; if the container misbehaves, enable Rosetta in Docker Desktop or run IB Gateway natively.
  • See the headless gateway GUI: with VNC_SERVER_PASSWORD set in backend/.env, uvx --from vncdotool vncdo -s 127.0.0.1::5900 -p "$VNC_PASS" capture shot.png (VNC is localhost-only).