Order updates#
Polling get_order_status works, but fills arrive late and cost requests. subscribe_order_updates opens a private WebSocket and pushes events to you as they happen.
Subscribe#
You give the SDK a tokio::sync::broadcast::Sender. It spawns a background task that holds the connection, reconnects with exponential backoff, and sends each OrderUpdateEvent on your channel. You get back a JoinHandle to stop it.
use tokio::sync::broadcast;
let (tx, mut rx) = broadcast::channel::<OrderUpdateEvent>(1024);
let handle = trader.subscribe_order_updates(tx).await?;
while let Ok(ev) = rx.recv().await {
println!("{} {} {:?} filled {}/{} ({:.0}%)",
ev.exchange, ev.symbol, ev.status, ev.filled_quantity, ev.quantity, ev.fill_percentage());
if ev.is_filled() { break; }
}
handle.abort(); // graceful shutdown of the background task
Because it is a broadcast channel, you can call tx.subscribe() to give several consumers their own receiver. A slow receiver can lag and miss events (RecvError::Lagged), so size the buffer for your burst rate and handle that error.
OrderUpdateEvent#
| Field | Type | Meaning |
|---|---|---|
exchange |
String |
Adapter name. |
order_id |
String |
|
client_order_id |
Option<String> |
|
symbol |
String |
|
status |
OrderStatus |
New, PartiallyFilled, Filled, Cancelled, Rejected, Expired, Pending. |
side, order_type |
||
price |
f64 |
Order price. |
quantity |
f64 |
Order quantity. |
filled_quantity |
f64 |
Cumulative filled. |
avg_fill_price |
Option<f64> |
|
fee, fee_currency |
Option<f64>, Option<String> |
|
exchange_timestamp |
i64 |
Milliseconds, set by the exchange. |
received_at |
i64 |
Milliseconds, set locally on receipt. |
raw |
Option<serde_json::Value> |
Raw exchange payload. |
Helpers: latency_ms() (received_at - exchange_timestamp), is_filled(), remaining_quantity(), fill_percentage().
Support#
The default implementation returns an error. Adapters that implement it declare ws_orders in their capabilities. See the exchange matrix for which ones do today.
if trader.capabilities().is_supported("ws_orders") {
let handle = trader.subscribe_order_updates(tx).await?;
}
Patterns#
- Track your own orders. Keep a map from
order_idto your strategy state and update it from events. UseOrderStatus::is_final()to know when to drop an entry. - Reconcile after reconnects. Events during a disconnect are not replayed. After a long outage, check open orders with
get_order_status. - Latency.
latency_ms()includes clock skew between your machine and the exchange. Compare it againstget_server_timeif you need precision.