#[non_exhaustive]pub struct Balance {
pub total: Decimal,
pub free: Decimal,
pub margin: Option<MarginDetails>,
pub accrued: Option<Decimal>,
}Expand description
Per-asset balance: gross holdings, the freely-tradable portion, optional margin debt and optional accrued carry.
Construct via Balance::new (cash) or Balance::new_margin (per-asset debt), then
Balance::with_accrued where the venue reports an accrual. The struct is
#[non_exhaustive], so code outside this crate builds it only through those, and later fields
are additive. total is gross holdings and free the freely-tradable portion; the remainder
(total - free, exposed by Balance::used) is reserved against resting orders. Producers
keep free <= total.
margin: None denotes a cash / no-debt context, not “unknown debt” — see Balance::margin
and Balance::net_asset.
Ord/PartialOrd are derived and compare lexicographically over
(total, free, margin, accrued) (None sorts before Some); they exist for use as collection
keys and generic bounds, not as a financial ranking. Use Balance::net_asset for value
comparisons that account for debt.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.total: DecimalGross holdings of the asset (free + locked). Unaffected by any borrowing — debt is
carried separately in Balance::margin.
Exception: a venue whose margin is account-level (Alpaca, IBKR) reports only the account’s
cash here, which is negative while the account borrows, with margin left None. See
the client’s account_snapshot.
A carrying cost (funding, margin interest, a borrow fee) reaches total only once the venue
posts it to the account, hourly at some venues and monthly at others. Until then total
leaves it out. A venue that reports the pending amount puts it in Balance::accrued, or,
for interest on a loan, in MarginDetails::interest. Each client’s rustdoc says what its
venue posts and when.
free: DecimalPortion of total available to trade (not reserved against resting orders).
margin: Option<MarginDetails>Per-asset margin debt, present only for venues that report it (see MarginDetails).
None means a cash / no-debt context — not “unknown debt”. The REST account snapshot
always populates this for a margin account, and the WS partial update (BalanceUpdate)
structurally cannot clear it, so None reliably denotes “no margin facility for this
asset”. See Balance::net_asset.
accrued: Option<Decimal>Carry accrued to date and not yet posted to total: interest earned or charged, and
whatever else the venue accrues the same way. Signed: positive is an amount the account
will receive, negative one it will pay.
The cash the account holds once the accrual posts is total + accrued. The venue resets
the accrual as it posts it, so the two never count the same amount twice. None means the
venue does not report one, not that nothing has accrued.
This differs from MarginDetails::interest, which is interest owed on a loan of the
asset and is paid out of a later repayment, not added to cash.
It is only as fresh as the last
BalanceSnapshot for the asset: a
BalanceUpdate carries none, and Balance::apply_stream_update keeps the prior value.
Implementations§
Source§impl Balance
impl Balance
Sourcepub const fn new(total: Decimal, free: Decimal) -> Self
pub const fn new(total: Decimal, free: Decimal) -> Self
Construct a cash Balance with no margin debt (margin: None).
Sourcepub const fn new_margin(
total: Decimal,
free: Decimal,
borrowed: Decimal,
interest: Decimal,
) -> Self
pub const fn new_margin( total: Decimal, free: Decimal, borrowed: Decimal, interest: Decimal, ) -> Self
Construct a margin Balance carrying per-asset borrowed/interest debt.
Sourcepub const fn with_accrued(self, accrued: Decimal) -> Self
pub const fn with_accrued(self, accrued: Decimal) -> Self
Set Balance::accrued, the carry accrued and not yet posted to total.
Sourcepub fn net_asset(&self) -> Decimal
pub fn net_asset(&self) -> Decimal
Net asset value: gross holdings less everything owed on the asset’s loan.
Returns total when Balance::margin is None and total - borrowed - interest when
Some, as Binance defines its margin accounts’ netAsset. The result can be
negative: a short position is a negative net holding in the borrowed (base) asset.
None is a cash / no-debt context, where net asset is simply the gross holding, except on
a venue whose margin is account-level (Alpaca, IBKR): there total is already the
account’s cash, negative while it borrows (see Balance::total), and the result is that
figure, with no loan or interest itemised.
Accrued MarginDetails::interest is owed as the principal is, so it is deducted once
the venue reports it accrued, not when it is repaid. Repaying the loan out of the asset’s
holdings leaves the result unchanged, since total falls by what the debt does. For the
principal alone, read MarginDetails::borrowed.
Balance::accrued is not counted: it is carry the venue posts to total later, not a
debt of the loan.
§Freshness
The returned value reflects debt only as fresh as the last
BalanceSnapshot or
MarginDebt for this asset. WS partial updates keep
free/locked live but never carry debt, so on a venue that streams no debt changes a
position borrowed since the last snapshot reads as zero-debt (net_asset == total)
until the next snapshot. Interest is likewise held at its last reported total: it falls in
steps as snapshots or debt events report it, not continuously as the venue accrues it.
Each venue client says whether it streams debt changes.
Sourcepub fn apply_stream_update(
prior: Option<Balance>,
update: &BalanceUpdate,
) -> Balance
pub fn apply_stream_update( prior: Option<Balance>, update: &BalanceUpdate, ) -> Balance
Merge a WS partial BalanceUpdate onto an optional prior Balance, preserving debt.
Applies the stream’s live free/locked (recomputing total = free + locked) while
carrying forward any MarginDetails and Balance::accrued from prior — a partial
update carries neither, so this is the single-sourced “debt and accruals fresh as of last
snapshot, free/locked live over the stream” merge. On a cold start (prior = None) the
result has margin: None and accrued: None.
This is the same no-clobber merge the engine applies internally for asset-keyed balances. It
is exposed so consumers applying per-instrument
InstrumentBalanceUpdate frames — which the engine does
not store — can reuse it rather than re-implement the contract.
Trait Implementations§
impl Copy for Balance
Source§impl<'de> Deserialize<'de> for Balance
impl<'de> Deserialize<'de> for Balance
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for Balance
Source§impl Ord for Balance
impl Ord for Balance
1.21.0 (const: unstable) · Source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
1.21.0 (const: unstable) · Source§fn min(self, other: Self) -> Selfwhere
Self: Sized,
fn min(self, other: Self) -> Selfwhere
Self: Sized,
Source§impl PartialOrd for Balance
impl PartialOrd for Balance
impl StructuralPartialEq for Balance
Auto Trait Implementations§
impl Freeze for Balance
impl RefUnwindSafe for Balance
impl Send for Balance
impl Sync for Balance
impl Unpin for Balance
impl UnsafeUnpin for Balance
impl UnwindSafe for Balance
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Comparable<K> for Q
impl<Q, K> Comparable<K> for Q
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreimpl<T> JsonSchemaMaybe for T
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.