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
alphaswarm paper run --config <file>(orPOST /paper/start) builds aPaperTradingSessionviaalphaswarm/trading/runner.py._connectsubscribes the feed to the strategy's universe.- For each bar (up to
max_barsor 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
OrderRecordand ledger entry.
- Run the pre-trade risk check (
- Drain order updates (simulated path) and emit fills.
- Check the kill switch (
- Every
state_flush_every_barsbars, a snapshot of the session state is flushed to thepaper_trading_runs.stateJSONB column. - On shutdown (kill switch, stop signal,
max_bars, or feed EOF), the engine drains, writes the final row, and emitsdoneto 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:
- Explicit
kwargsin the YAML recipe (highest) - Explicit
kwargs=passed tobuild_from_config ALPHASWARM_*environment variables- 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:
- Stop accepting new bars from the feed.
- Cancel every open order via
brokerage.cancel_order_async. - Flush final state + close brokerage/feed connections.
- Emit
doneto 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:
- Declare both
model_urnandpipeline_urnin the YAML. - Seed matching aspects before startup checks run.
- Built-in baseline configs are seeded by Alembic revision
0049_paper_metadata_seed_aspects; additional configs should ship a follow-up migration (either usingalphaswarm.trading.baseline_aspects.seed_paper_baseline_aspects()or directwrite_aspect(...)calls in non-migration application code).
Baseline URNs seeded by revision 0049_paper_metadata_seed_aspects:
urn:alphaswarm:mlmodel:prod:alpaca_mean_reversion_v1urn:alphaswarm:pipeline:prod:alpaca_mean_reversion_loopurn:alphaswarm:mlmodel:prod:ibkr_mean_reversion_v1urn:alphaswarm:pipeline:prod:ibkr_mean_reversion_loopurn:alphaswarm:mlmodel:prod:avellaneda_stoikov_v1urn:alphaswarm:pipeline:prod:avellaneda_stoikov_quotes_loopurn:alphaswarm:mlmodel:prod:lucic_tse_options_v1urn:alphaswarm:pipeline:prod:lucic_tse_options_loopurn:alphaswarm:mlmodel:prod:tradier_rest_baseline_v1urn: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 name | Emitted by |
|---|---|
paper.session.run | PaperTradingSession.run |
paper.session.bar | Each bar processed |
paper.session.submit_order | Order submission gate |
broker.submit_order | Every concrete broker adapter |
broker.cancel_order | Every concrete broker adapter |
broker.query_positions | Every concrete broker adapter |
broker.query_account | Every concrete broker adapter |
Each span carries a broker.venue attribute (alpaca, ibkr,
tradier, or sim).