Saltar al contenido principal

Paper & live trading

Doc map: alphaswarm_docs/index.md · Session state machine: alphaswarm_docs/flows.md#4-paper-trading-session.

AlphaSwarm's paper trading engine is a Lean-inspired async runtime that shares 100% of its strategy code with the backtester. Orders from the same IStrategy object flow through the same ledger tables regardless of whether the session is a backtest, a paper replay, or a live session.

Architecture

Lifecycle

  1. alphaswarm paper run --config <file> (or POST /paper/start) builds a PaperTradingSession via alphaswarm/trading/runner.py.
  2. _connect subscribes the feed to the strategy's universe.
  3. For each bar (up to max_bars or forever):
    • Check the kill switch (POST /portfolio/kill_switch).
    • Append to an in-memory history window.
    • Call strategy.on_bar(bar, context) — identical to the backtest.
    • For each returned OrderRequest:
      • Run the pre-trade risk check (RiskManager.check_pretrade).
      • Submit via brokerage.submit_order_async (or the sync bridge).
      • Persist the OrderRecord and ledger entry.
    • Drain order updates (simulated path) and emit fills.
  4. Every state_flush_every_bars bars, a snapshot of the session state is flushed to the paper_trading_runs.state JSONB column.
  5. On shutdown (kill switch, stop signal, max_bars, or feed EOF), the engine drains, writes the final row, and emits done to the progress bus.

Broker adapters

Each adapter lives in alphaswarm/trading/brokerages/ and implements both IBrokerage (sync, for backtest parity) and IAsyncBrokerage.

Alpaca ([alpaca] extra)

brokerage:
class: AlpacaBrokerage
kwargs: {paper: true} # flip to false for live

Requires ALPHASWARM_ALPACA_API_KEY and ALPHASWARM_ALPACA_SECRET_KEY. The adapter maintains a background TradingStream that re-emits order updates through the session's _order_event_queue.

Interactive Brokers ([ibkr] extra)

brokerage:
class: InteractiveBrokersBrokerage
kwargs: {exchange: SMART, currency: USD}

Requires a running TWS or IB Gateway. Defaults: ALPHASWARM_IBKR_HOST=127.0.0.1, ALPHASWARM_IBKR_PORT=7497 (paper), ALPHASWARM_IBKR_CLIENT_ID=1. The feed uses client_id + 100 so it doesn't collide with the trading client.

Tradier (generic REST template)

brokerage:
class: TradierBrokerage

Requires ALPHASWARM_TRADIER_TOKEN and ALPHASWARM_TRADIER_ACCOUNT_ID. Demonstrates how to subclass RestBrokerage — five small overrides give you a full paper/live venue: _order_payload, _parse_order(s), _parse_positions, _parse_account, _order_detail_path/_orders_path/_positions_path/_account_path.

Credential flow

alphaswarm.config.Settings reads every broker secret from the ALPHASWARM_* environment (via .env). Adapters pick those up automatically at construction time, so YAML recipes rarely need to inline secrets.

Order of precedence:

  1. Explicit kwargs in the YAML recipe (highest)
  2. Explicit kwargs= passed to build_from_config
  3. ALPHASWARM_* environment variables
  4. Package defaults (sandbox URLs, paper=True, etc.)

Kill-switch integration

The paper session wraps every iteration in a check against alphaswarm.risk.kill_switch.is_engaged. Toggling the switch via POST /portfolio/kill_switch (or the UI's Portfolio page) causes the session to:

  1. Stop accepting new bars from the feed.
  2. Cancel every open order via brokerage.cancel_order_async.
  3. Flush final state + close brokerage/feed connections.
  4. Emit done to the task progress channel.

Set session.stop_on_kill_switch: false in the recipe to disable this behaviour (not recommended).

Remote / Kubernetes runs

The paper-trader Docker image (--target paper) runs alphaswarm paper run as a single-replica k8s Deployment. See alphaswarm_platform/deploy/k8s/base/paper-trader.yaml.

To run on a remote host over SSH:

ALPHASWARM_ALPACA_API_KEY=... ALPHASWARM_ALPACA_SECRET_KEY=... \
alphaswarm paper run --config configs/paper/alpaca_mean_rev.yaml --celery

The --celery flag enqueues the job onto the shared worker pool; the shell can exit and the session keeps running. Use alphaswarm paper stop <task_id> to drain it gracefully from anywhere.

Metadata Gate — Strict Mode Rollout

Paper sessions now run with strict metadata validation only. Startup aborts when session.model_urn or session.pipeline_urn is missing, invalid, or unresolvable, or when model status is not Production/Staging.

When adding a new paper config:

  1. Declare both model_urn and pipeline_urn in the YAML.
  2. Seed matching aspects before startup checks run.
  3. Built-in baseline configs are seeded by Alembic revision 0049_paper_metadata_seed_aspects; additional configs should ship a follow-up migration (either using alphaswarm.trading.baseline_aspects.seed_paper_baseline_aspects() or direct write_aspect(...) calls in non-migration application code).

Baseline URNs seeded by revision 0049_paper_metadata_seed_aspects:

  • urn:alphaswarm:mlmodel:prod:alpaca_mean_reversion_v1
  • urn:alphaswarm:pipeline:prod:alpaca_mean_reversion_loop
  • urn:alphaswarm:mlmodel:prod:ibkr_mean_reversion_v1
  • urn:alphaswarm:pipeline:prod:ibkr_mean_reversion_loop
  • urn:alphaswarm:mlmodel:prod:avellaneda_stoikov_v1
  • urn:alphaswarm:pipeline:prod:avellaneda_stoikov_quotes_loop
  • urn:alphaswarm:mlmodel:prod:lucic_tse_options_v1
  • urn:alphaswarm:pipeline:prod:lucic_tse_options_loop
  • urn:alphaswarm:mlmodel:prod:tradier_rest_baseline_v1
  • urn:alphaswarm:pipeline:prod:tradier_rest_loop

Observability hooks

All broker calls and the main session loop are instrumented with OpenTelemetry spans (see observability.md):

Span nameEmitted by
paper.session.runPaperTradingSession.run
paper.session.barEach bar processed
paper.session.submit_orderOrder submission gate
broker.submit_orderEvery concrete broker adapter
broker.cancel_orderEvery concrete broker adapter
broker.query_positionsEvery concrete broker adapter
broker.query_accountEvery concrete broker adapter

Each span carries a broker.venue attribute (alpaca, ibkr, tradier, or sim).