Appearance
PendingOrderManager
Handles pending order lifecycle for market and close orders when price data is not immediately available.
High-Level Design
The Problem
Orders use deterministic pricing: every order targets a specific Unix timestamp (Math.floor(Date.now() / 1000)). When the user submits a market or close order, the price for that exact second may not yet exist in PriceCollector. The order cannot execute without it.
The Solution: Reserve-Then-Execute
PendingOrderManager implements a reserve-then-execute pattern that decouples order submission from order execution:
User submits order
│
▼
Price available? ──yes──▶ Execute immediately
│ (handled by OrderExecutionManager)
no
│
▼
Create PENDING order ──▶ Reserve margin upfront ──▶ Register price arrival alert
(MARKET only) (with PriceAlert DO)
│
▼
... time passes (typically < 2 seconds) ...
│
▼
PriceAlert calls onPriceArrival()
│
▼
Execute order with exact timestamp's price
│
▼
EXECUTED or FAILEDKey Concepts
"Eventually Correct" Margin Reservation — Margin is locked at creation time, not execution time. This guarantees the order can execute when the price arrives without re-checking balance. MARKET orders reserve sizeUsd / leverage; CLOSE orders reserve nothing (they release margin).
Implicit Margin Release — getTotalReservedMargin() only sums PENDING orders. When an order transitions to EXECUTED or FAILED, its reserved margin is automatically excluded from the total — no explicit release step needed.
Stale Alert Guard — Each pending order is scoped to an accountId. When the user resets their account, the accountId increments. Callbacks arriving for old accounts are rejected (STALE_ALERT), preventing ghost orders from executing against a fresh account.
No Separate CANCELLED Status — Cancellation marks orders as FAILED with error message "Cancelled by user". This keeps the state machine simple: PENDING → EXECUTED | FAILED.
Edge Cases
- No margin re-check at execution — margin was reserved at creation. Execution failures come from trading logic (e.g., position validation, liquidation check), not insufficient margin.
- Price missing for symbol — if the arrived PriceData doesn't contain the order's symbol, the order is marked FAILED immediately.
- Multiple orders same timestamp —
executePendingOrdersForTimestamploops through all matching orders sequentially. Each executes independently. - CLOSE order type — uses opposite direction of the existing position. Reserves no margin.
See Also
- OrderExecutionManager — creates pending orders and registers alerts
- LimitOrderManager — similar reserve-then-execute pattern for limit orders
- BalanceManager — consumes reserved margin in balance calculations