Skip to content

Paper trading

Paper trading runs a strategy (or a multi-strategy book) against simulated execution — no real money — so you can watch a validated edge behave in real time before risking capital. The same registered strategy code runs here as in a backtest and live. Two venues:

  • Crypto sandbox (zero-setup default) — a fully local simulator (Nautilus’s sandbox execution client) that fills your orders against a live Kraken market-data feed (US-available, no key). Nothing leaves the machine; no money at risk.
  • IB paper — Interactive Brokers’ native paper account (a DU… id), through the Dockerized IB Gateway.

Starting a session from the app (no terminal)

Section titled “Starting a session from the app (no terminal)”

The Paper tab’s guided start card walks you through it:

  1. Choose a venueCrypto sandbox (nothing to configure) or IB paper (shows an IB account preview).
  2. Get IB ready (IB only) — a readiness strip shows the gateway state; a Start gateway / Restart (re-login) button runs docker compose for you (no terminal). The first start downloads the image (~2 min) and IB may ask for a 2FA tap on your phone.
  3. Configure — a Single strategy / Book toggle. Single: strategy, symbol (searchable picker), timeframe, parameters. Book: Add strategy for as many sleeves (strategy + symbol) as you want — they run as one node on one account. Plus starting cash (sandbox), an optional auto-stop at HH:MM ET, and a label. Strategies that declare a required cadence (the 1-minute intraday family) grey out other timeframes in the picker, and the API refuses a mismatch — intraday legs also get a per-bar fidelity comparison automatically.
  4. Start. The API spawns and supervises the runner; the card flips to the live status cards, controls, and event feed. Stop session flattens and stops gracefully. If a start fails, the log tail is shown in the UI.

The start form also has an opt-in circuit breaker — auto-halt the session on a drawdown-% or session-loss-$ breach — and the feed surfaces a recovery notice if a restart re-adopts open orders/positions.

A ready strategy’s Start paper button on the research ladder deep-links here, pre-filled.

IB paper/live trade through the Dockerized gateway. In backend/.env set the container env (see configuration):

  • TWS_USERID / TWS_PASSWORD — your IBKR login (enable 2FA).
  • ATS_IB_ACCOUNT_ID — your paper account id (starts with DU).

Start the gateway from the Paper tab’s button, the header chip, or a shell:

Terminal window
docker compose -f infra/docker-compose.yml --profile ib up -d --wait

No paper account yet? “Paper Account Notice: the specified user does not have a Paper Trading user” means you must create one in IB Client Portal (Settings → Account Settings → Paper Trading Account), then put the DU… id in ATS_IB_ACCOUNT_ID and restart the gateway.

The command-line runners (power-user / automation)

Section titled “The command-line runners (power-user / automation)”

The CLI runners are the automation path (cron, headless, scripting):

Terminal window
cd backend
# IB paper — foreground; Ctrl-C flattens and stops
uv run python -m ats.paper --strategy ibs_reversion --instrument QQQ.NASDAQ \
--bar-spec 1-DAY-LAST --params '{"buy_threshold": 0.15, "exit_threshold": 0.7}'
# Crypto sandbox — crypto trades 24/7 (no market-hours gating)
uv run python -m ats.crypto_paper --strategy tsmom --instrument BTCUSD \
--bar-spec 1-DAY-LAST --params '{"trade_size": 1}' --starting-cash 100000

For unattended sessions use scripts/run-paper.sh (relaunches after crashes, respects intentional stops). Add --until 16:05 for a clean market-close auto-stop, and cron it — see scheduling.

IB symbology vs catalog symbology: trading uses IB ids (QQQ.NASDAQ), distinct from catalog ids (QQQ.XNAS) on purpose, so a session states exactly which IB contract it trades. IB and crypto paper sessions run concurrently — one session per venue, each on its own telemetry/control namespace (IB on paper, crypto on paper-crypto), so the two legs never collide.

Running a book (multiple strategies, one account)

Section titled “Running a book (multiple strategies, one account)”

Pass --sleeves-json to run several strategies in one node — one feed, one heartbeat, one kill switch, one RiskEngine, all on the same account — and --label to name it:

Terminal window
uv run python -m ats.paper --label "QQQ book" \
--sleeves-json '[{"strategy_key":"ibs_reversion","instrument":"QQQ.NASDAQ","params":{"buy_threshold":0.1}},
{"strategy_key":"turn_of_month","instrument":"HYG.NASDAQ"}]'

Each event/fill is attributed to its sleeve. A live/paper book can only contain order-placing registry strategies — the vectorized research engines (cross-sectional, pairs) have no live order path. See multi-instrument engines.

While a session runs you have, from the UI or queued through Redis (each acknowledged in the feed and audited):

  • Pause — RiskEngine HALTED: new orders denied, positions held, indicators warm.
  • Resume — back to ACTIVE.
  • Flatten — REDUCING: cancel open orders, close all positions (closing orders only).
  • Kill — flatten, then shut the session process down once the account is actually flat (or after a 30-second grace window — a kill never hangs; reconciliation catches any remainder next start).

While a session runs, the Paper tab is a working dashboard:

  • Status card (the hero) — session state, the control buttons, and the money strip: equity, available capital, unrealized/realized P&L, and net exposure, always visible without a click. Below it, the session info (strategy/sleeves, timeframe with a next-bar hint, account, connectivity, and the auto-halt/circuit-breaker state).
  • Portfolio strip — the combined campaign portfolio across both paper venues (book + BTC).
  • Equity chart + positions (left) — the session’s live equity curve (persisted snapshots seed it, so it survives a refresh) over the per-position P&L table.
  • Event stream (right) — the run-scoped feed (orders, fills, connectivity) in Eastern time, streamed over WebSocket and persisted.
  • Performance | Fidelity tabs — durable fill history (trades, win rate, realized P&L, fees) per strategy/instrument with an Export CSV link, and the live-vs-backtest fidelity scorecard.

Idle, the page shows the start form beside the account at rest — a read-only IB account probe (reqAccountSummary / reqPositions, never an order) with equity, cash, buying power, exposure, and holdings, which explains why there’s no data (gateway down / logged out) rather than showing nothing. The tabs add Events so the 7-day persisted log stays reachable for post-mortems. The header’s gateway health chip shows separate Paper/Live state (OK / re-login needed / off) with copy-paste restart commands; a worker monitor probes each gateway ~every 15 min.

The Home tab’s “All accounts” card sums equity and session P&L across every running session — IB paper, crypto sandbox, and live — from their telemetry heartbeats.

Every run — either venue — is recorded as a session (opened/closed from the telemetry heartbeat) by the worker’s session relay. History persists whether or not Telegram is configured; the Telegram alerts are optional on top. The Sessions tab lists them newest-first (label, kind, strategy/instrument or book, started/ended in ET, status, fills, round trips, realized P&L, fees); open a row for the per-sleeve breakdown and round-trips, and delete one or bulk-clear a kind. (Deleting a session also removes its fills from the Research “Paper” rung — the confirm says so.)

Your data is yours: every session row has a download icon for its trade-log CSV, and the detail dialog offers both Trade log CSV and Equity CSV (full-resolution snapshots, not the downsampled chart series). The Performance panel’s Export CSV covers the aggregated per-strategy/instrument rows.

Paper runs behind the same machinery as live: the pre-trade risk engine (per-order notional

  • submit-rate caps), startup reconciliation, and gateway resilience — so what you exercise on paper is what protects you live.