Skip to main content

Execution paths: WebSocket priority + queue-preserving amendment

Status: Phase 2 shipped (Alembic 0041). Amendment manager: alphaswarm/trading/execution/amendment.py.

Why WebSocket-first​

The Nautilus issue #4000 documents the cost of using REST for amendment: most REST PATCH endpoints actually implement amendment as cancel + recreate. The modified order takes a NEW venue order id and goes to the back of the limit order book queue at the new price. For market-making strategies this is a non-starter -- the queue position IS the alpha.

Phase 2's :class:IDomainBrokerage declares two capability flags:

  • :attr:IDomainBrokerage.supports_websocket_amend -- the venue has a WS endpoint that modifies the order in place
  • :attr:IDomainBrokerage.supports_oco -- the venue accepts an atomic OCO submission

When both are True, the broker is "Phase 2 ready" and the :class:AmendmentManager routes:

ChangeWS amend supportedRouting
Trigger price (stop / MIT / trailing-stop)TrueWS_AMEND
Trigger priceFalseCANCEL_RESUBMIT
Quantity-down on limitTrueWS_AMEND
Quantity-up on limitTrue (if policy allows)WS_AMEND
Quantity-up on limitFalse (default policy)CANCEL_RESUBMIT
Price changeAnyCANCEL_RESUBMIT

Price changes always go cancel + resubmit because the modified order takes the back of the queue at the new price anyway.

Atomic request id counter​

The amendment manager's :class:alphaswarm.trading.execution.amendment.AtomicRequestIdCounter mirrors Rust's AtomicU64 via :class:threading.Lock + :class:itertools.count. Each next_id() returns a monotonically increasing 64-bit-safe int that the manager uses as the WS message id.

Why is this important?

  • WebSocket amend / cancel messages are dispatched asynchronously -- the response comes back over the same connection with the matching request id.
  • If two amendments race (the strategy emits a new amendment before the previous one's response arrives), the manager needs to disambiguate which response belongs to which intent.
  • The counter is gap-free under concurrency, so the matching state table stays correct even when 10+ amendments are inflight.

Fallback semantics​

When the WS amend fails (network drop, venue rejection, policy disallowing the change), the manager:

  1. Logs at WARNING level with the original exception.
  2. Falls through to cancel + resubmit using the broker's :meth:IDomainBrokerage.cancel + :meth:IDomainBrokerage.submit.
  3. Returns an :class:AmendmentResult with routing=CANCEL_RESUBMIT so the caller knows queue position was lost.

This is the "WS primary path with REST fallback" pattern from the Nautilus issue. Callers don't have to know which route was used -- the result tells them.

Code example​

from decimal import Decimal
from alphaswarm.trading.execution import AmendmentManager, AmendmentRequest

mgr = AmendmentManager(
ws_amend=broker.ws_amend, # async callable
cancel_resubmit=broker.cancel_resubmit, # async callable
)

# Reduce a 10-lot limit order to 5 lots without losing queue position
result = await mgr.amend(
AmendmentRequest(
client_order_id=order.client_order_id,
quantity=Decimal("5"),
),
current_order=order,
)
print(result.routing, result.elapsed_ms)

Persistence​

Every amendment ultimately produces one or more :class:ExecutionReport rows in execution_reports. The :class:ExecutionReportDispatcher writes them; the (venue, venue_execution_id) unique index dedupes duplicates from the WS-vs-REST race.

Broker capability matrix​

The three flags above are declared on IDomainBrokerage and default to False. As of this writing, none of the concrete IDomainBrokerage implementations — AlpacaDomainBrokerage, CoinbaseDomainBrokerage, SchwabDomainBrokerage, TastytradeDomainBrokerage, TradovateDomainBrokerage, or PaperDomainBrokerage — override supports_websocket_amend / supports_oco / supports_outside_rth, so every amendment currently falls back to CANCEL_RESUBMIT in practice regardless of venue. There is no IBKR, Tradier, Binance, or Kraken IDomainBrokerage adapter in this repo today (IBKR and Tradier only implement the older BaseAsyncBrokerage/RestBrokerage interfaces; Binance and Kraken aren't integrated at all). The separate, older BrokerCapabilities matrix used by the smart-order-router does carry a real per-venue supports_oco / supports_outside_rth for Alpaca, Schwab, Interactive Brokers, Coinbase, Tastytrade, Tradier, and Tradovate, but it is a distinct system from the Phase 2 amendment path described on this page.

The matrix is read at runtime from the broker's class attributes; specific venues that ship later get added the same way.

Unified Execution with NautilusTrader​

AlphaSwarm leverages NautilusTrader as its primary live execution engine. This provides several advantages:

  • Research-to-Live Parity: Strategies tested in the NautilusEngine can be deployed live with zero code changes.
  • Event-Driven Architecture: Native support for high-frequency streaming data and low-latency order execution.
  • Standardized Reconciliation: NautilusTrader automatically reconciles venue state with internal state on startup and during runtime.
  • Robust Risk Management: Pre-trade risk checks via the LiveRiskEngine.