Build an authenticated account monitor that keeps exact funding and trading balances separate, tracks reservations and open orders, and uses revisions to reject stale balance updates.
Read the balance snapshot
use polyester::proto::ledger::read::v1::GetBalancesRequest;
let balances = client.balances.list(GetBalancesRequest::default()).await?;
for balance in &balances.balances {
println!(
"{} available={} reserved={} trading_revision={} funding_revision={}",
balance.asset_id,
polyester::codecs::scalars::format_ledger_u128(&balance.available, 18)?,
polyester::codecs::scalars::format_ledger_u128(&balance.reserved, 18)?,
balance.trading_revision,
balance.funding_revision,
);
}The balance components are raw ledger u128 strings at ledger scale 18. The formatter is for
display only; retain the raw strings in the tracker.
funding is deposit/withdraw custody state. trading, reserved, and available are execution
state. Their revisions are independent; compare trading_revision only with trading-state updates
and funding_revision only with funding-state updates.
Reconcile open orders
use polyester::models::ListOpenOrdersOpts;
let open = client
.orders
.list_open_with(ListOpenOrdersOpts {
include_attached_risk: true,
include_attached_risk_state: true,
..Default::default()
})
.await?;
for order in &open.orders {
println!(
"{} {} {} {} {:?} {:?} {:?}",
order.order_id,
order.client_order_id,
order.symbol_id,
order.status,
order.orig_qty,
order.cum_qty,
order.leaves_qty,
);
}Reserved balance and open-order leaves should move together eventually, but they are served by different read models and can lag briefly. Do not flag a mismatch until a bounded reconciliation window and a fresh read have both completed.
Subscribe for low-latency order changes
let mut subscription = client
.orders
.subscribe(client.default_account_id.as_deref())
.await?;
if let Some(order) = subscription.recv_result().await? {
let scale = client
.catalogs
.base_quantity_scale_for_symbol_id(order.symbol_id)
.ok_or_else(|| polyester::Error::validation("stream symbol quantity scale is unavailable"))?;
let cum = match &order.cum_qty {
Some(qty) => Some(qty.format(Some(scale))?),
None => None,
};
let leaves = match &order.leaves_qty {
Some(qty) => Some(qty.format(Some(scale))?),
None => None,
};
println!("{} {} {:?} {:?}", order.order_id, order.status, cum, leaves);
}
if let Some(err) = subscription.err() {
eprintln!("{err}");
}The private stream accelerates the UI; it does not replace snapshots. On reconnect or queue
overflow, discard local assumptions and reconcile balances plus open orders again. Stream
quantities can omit scale, so resolve it from the hydrated catalog by symbol_id and fail closed
if unavailable; never invent a stream scale.
Resolve fills before computing inventory
use std::time::Duration;
let details = client
.orders
.wait_for_order_trades_complete(
None,
Some("order-id-from-create"),
Duration::from_secs(15),
)
.await?;
if let Some(order) = details.order {
println!("{:?} {}", order.cum_qty, details.trades.len());
}The order projection can show cumulative quantity before every related trade row is queryable. Use the completed trade projection for fee-source-aware received inventory and realized execution reporting.
Poll as a safety net
Poll slowly enough to respect rate limits, add jitter across replicas, and set one overall tokio::time::timeout per cycle. A useful cycle is balances โ open orders โ recent history.
Publish the new dashboard state atomically only after all required reads succeed; otherwise retain
the previous state and mark it stale.
Account-state API map
| Method | Important inputs | Use |
|---|---|---|
balances.list | GetBalancesRequest | Funding/trading snapshot and revisions |
balances.get_balance_history | request options | Auditable balance movement |
orders.list_open_with | subaccount, pagination, attached-risk flags | Current reservation intent |
orders.list_history_with | symbol, pagination | Terminal and recent order states |
orders.get / get_with | order ID or client order ID | One order plus related fills |
orders.subscribe | account ID | Low-latency private lifecycle updates |
orders.wait_for_order_trades_complete | order identity, overall duration | Complete fill projection |
trades.list | request filters | User execution ledger |
Tested source
Example 02 in polyester-examples-rust performs
authenticated balance and order reads. Every target compiles and passes Clippy against the exact v0.1.0a22 SDK commit.