Subscription.balances
Reads the latest balances that a private subscription keeps up to date from pushed events. Applies only to subscriptions whose channel is private.
balances()Examples
Subscribe to the private stream and print the available and frozen amounts of USDT once the snapshot is ready and on every balance change.
javascript
function main() {
var acct = ctx.subscribe(exchange, {channel: "private"})
while (true) {
var ev = ctx.poll([], 1000)
if (!ev || ev.stream !== acct.id) {
continue
}
var ready = ev.kind === 35 && ev.prefillStatus === 1
if (!ready && ev.channel !== "balance") {
continue
}
var balances = acct.balances()
if (balances === null) {
continue // Account snapshot is not ready yet
}
var usdt = balances.find(function(b) { return b.asset === "USDT" })
Log("USDT free:", usdt ? usdt.free : 0, "frozen:", usdt ? usdt.frozen : 0)
}
}
python
def main():
acct = ctx.subscribe(exchange, {"channel": "private"})
while True:
ev = ctx.poll([], 1000)
if ev is None or ev.stream != acct.id:
continue
ready = ev.kind == 35 and ev.prefillStatus == 1
if not ready and ev.channel != "balance":
continue
balances = acct.balances()
if balances is None:
continue # Account snapshot is not ready yet
usdt = next((b for b in balances if b.asset == "USDT"), None)
Log("USDT free:", usdt.free if usdt else 0, "frozen:", usdt.frozen if usdt else 0)
rust
use sdk::ctx::EventExt;
fn main() {
let acct = ctx::subscribe(exchange, ctx::SubOpts::private()).unwrap();
loop {
match ctx::poll(&[], Some(1000)) {
ctx::Polled::Event(ev) if ev.stream() == acct.id() => {
if ev.channel() != "private" && ev.channel() != "balance" {
continue;
}
if let Ok(Some(rows)) = acct.balances() {
if let Some(u) = rows.iter().find(|b| b.asset == "USDT") {
Log!("USDT free:", u.free, "frozen:", u.frozen);
}
}
}
ctx::Polled::Stopped => break,
_ => {}
}
}
}Returns
| Type | Description |
array / null value | An array of balances sorted by asset name. Each element holds the current full balance of one asset. Returns a null value while the account snapshot is not ready yet. |
See Also
Remarks
Fields of each array element:
| Field | Type | Description |
|---|---|---|
| asset | string | Asset name, the same as the asset name returned by exchange.GetAssets |
| free | number | Available amount |
| frozen | number | Frozen amount |
| equity、upnl、margin | number | Equity, unrealized PnL and margin in use. These fields are left out when the exchange does not push them |
| time | number | Exchange update time in milliseconds. This field is left out when the exchange does not provide it |
Assets whose available amount and frozen amount are both 0 are not included in the array.
A null return value means the state is unknown. It does not mean there is no balance. After subscribing, data is available only after this event stream delivers the initialization status event with channel set to private and prefillStatus set to 1. A null value is also returned when the most recent snapshot failed, until the next snapshot is ready.
The docker updates this state from the pushed balance events (kind is 18), so you need to keep calling ctx.poll to receive events. Exchanges push balances in different ways. On some exchanges, the connector requests the REST API again after a balance change and then pushes the result. Other exchanges only provide snapshots. See each exchange's page for details. exchange.GetAssets and exchange.GetAccount always request the REST API and do not depend on pushed data.
Calling this method on a subscription that is not private, or on one that has been unsubscribed, throws an exception.
In Rust the signature is sub.balances() -> Result<Option<Vec<ctx::BalanceRow>>, String>, where Ok(None) means the snapshot is not ready yet. The fields of BalanceRow are asset, free, frozen, equity, upnl, margin and time, and the last four are Option. In Python the call is sub.balances(). It returns a list of dictionaries with the same fields, which can also be read as attributes, and it returns None while the snapshot is not ready yet.