Skip to main content

BinanceSpot

Struct BinanceSpot 

Source
pub struct BinanceSpot { /* private fields */ }
Expand description

BinanceSpot execution client using the official binance-sdk.

  • REST API: account snapshot, balance/order/trade queries (startup/cold paths)
  • WebSocket API: order placement, order cancellation, user data stream (hot paths)

§Rate limits

REST and the WebSocket API share one per-IP request-weight limit per minute. Its value comes from each WebSocket API response, and is Binance’s documented 6000 until the first one. Once a response reports at least 90% of it used, REST queries wait for the next minute, so the rest is left for orders and cancels, which never wait for it. A query, including a fetch_open_orders after a reconnect, can therefore take up to about a minute longer. A reconnect’s fill recovery does not wait for it either, since a pause could outlast the recovery’s 30 s and delay its fills to a retry. After Binance answers with a rate-limit error, REST calls wait out a cooldown, and an order or cancel that would have to open a new WebSocket API session fails with ApiError::RateLimit instead, unsent.

§Fills of other clients’ orders

The account stream, fill recovery and fetch_trades report every fill on the account, whoever placed the order, and Binance does not say who did. A consumer that also trades the account outside the engine filters those fills itself, for example by Trade::client_order_id. See the module docs.

Trait Implementations§

Source§

impl Clone for BinanceSpot

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for BinanceSpot

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl ExecutionClient for BinanceSpot

Source§

fn new(config: Self::Config) -> Self

§Panics

Panics if the binance-sdk REST or WebSocket configuration builder fails (e.g. empty or malformed API key/secret).

Source§

async fn account_stream( &self, _assets: &[AssetNameExchange], instruments: &[InstrumentNameExchange], ) -> Result<Self::AccountStream, UnindexedClientError>

Returns a live stream of account events (fills, order updates, balance changes).

§Startup Race Window

There is a brief window between the initial WS subscribe response and the internal event listener being registered inside the spawned connection manager. TRADE fills arriving in this gap are silently dropped. Callers that require fill completeness at startup MUST call ExecutionClient::fetch_trades with a 1–2 second lookback unconditionally after account_stream returns, before processing any events. Do not use the first event’s arrival as a readiness signal — the first event may be a recovered fill sent before live WS events start. The dedup cache absorbs any duplicates from the overlapping time window.

§A recovery that does not finish

Recovery after a reconnect is bounded by a 30 s timeout, and an instrument’s query can fail. Each instrument’s gap, from the disconnect to just after the recovery began, is kept until its fills are forwarded. A gap not read is retried after 1, 2, 4, 8 and 16 minutes, whether the stream stays connected or reconnects in between. A retry reads only the gap, not fills the stream delivered live after it; the few seconds at its end that overlap live delivery are deduplicated. Each failed read is logged at warn with the instrument and the gap. After five failed retries the gap is given up, logged at error, and its fills are not delivered. The stream says so with an AccountEventKind::FillRecoveryGaveUp naming the instrument and the gap: read its fills with ExecutionClient::fetch_trades.

A recovered gap counts as read even when a fill in it could not be converted, which is logged, or its order’s cumulative could not be looked up (see below).

§A recovered fill advances the order too

A fill that arrives live over the WebSocket carries the order’s cumulative filled quantity in Trade::order_filled_quantity (executionReport’s z), so it advances the order by itself. A fill recovered after a disconnect comes from REST myTrades, which reports executions only, so recovery rebuilds the same figure by reading each recovered order’s executions from its first: one extra request per order (another per further 1,000 executions), up to four orders at a time per instrument.

Those lookups have their own time budget inside the recovery timeout, so they can never cost a fill. A fill whose order was not looked up in time, or whose lookup failed, goes out with order_filled_quantity: None, logged at warn. It then advances the position but not the order, which keeps whatever filled_quantity it held before the gap until the order’s state is learned some other way.

§Orders that ended while disconnected

A reconnect also reports how each order the client holds as live on one of instruments ended, where it did, as an AccountEventKind::OrderSnapshot of its inactive state: filled, cancelled with what filled before, expired, or rejected. Like fill recovery, it covers only the instruments the stream was opened with. Binance’s order history filters on when an order was created, so such an order is found by asking about it, not by time.

  • Which orders. The client holds an order as live from the response to placing it, from a listing of open orders (account_snapshot, fetch_open_orders), and from its live reports on any of its account streams, until it sees the order end. It holds up to 4,096 orders and forgets the oldest past that, logged at warn. An order placed outside this client and never listed or reported to it is not covered.
  • Cost. One openOrders request per instrument with an order held (weight 6), then one GET /api/v3/order (weight 4) for each held order the listing no longer shows.
  • Fills first. An instrument is checked only once its fill gap is recovered or given up, so an order’s recovered fills arrive before how it ended. A fill that brings an order to its full quantity ends it, and that order is not reported again.
  • Keys. Each snapshot carries StrategyId::unknown, since Binance records no strategy. The engine matches it to the order it tracks by client order id.
  • Failures. Each order’s lookup is settled as it ends, and each instrument as soon as its check ends. One whose listing or any lookup fails, or whose check is still running when a pass reaches 30 s, is retried on the fill gaps’ schedule (1, 2, 4, 8 and 16 minutes), asking only about the orders still held, then given up, logged at error. Its orders are asked about again at the next reconnect. An order Binance does not know (-2013) stops being held, logged at warn; one it still reports live, or in a state this version cannot read, stays held.

The same lookup is public as OrderStatusClient::fetch_ended_orders.

Source§

async fn fetch_open_orders( &self, instruments: &[InstrumentNameExchange], ) -> Result<Vec<Order<ExchangeId, InstrumentNameExchange, Open>>, UnindexedClientError>

An empty instruments slice is the ExecutionClient “return all” sentinel: a single no-symbol GET /api/v3/openOrders call returns open orders across every instrument (each order’s instrument is recovered from its own symbol field). A non-empty slice fetches the listed instruments concurrently, per-symbol.

Source§

async fn fetch_trades( &self, start: DateTime<Utc>, end: DateTime<Utc>, instruments: &[InstrumentNameExchange], ) -> Result<TradesRead<AssetNameExchange, InstrumentNameExchange>, UnindexedClientError>

Documented deviation from the ExecutionClient::fetch_trades “return all” contract: Binance’s myTrades endpoint requires a symbol — there is no no-symbol “all trades” query (unlike open orders). An empty instruments slice therefore has nothing to query and reads nothing; callers wanting all trades must enumerate instruments explicitly.

Each instrument is paged by trade id to the span’s end within the call, with no page cap, so the read is always complete (resume: None).

Source§

const EXCHANGE: ExchangeId = ExchangeId::BinanceSpot

Source§

const SUPPORTED_KINDS: &'static [InstrumentKindDiscriminant]

The InstrumentKindDiscriminants this client can trade. Read more
Source§

type Config = BinanceSpotConfig

Source§

type AccountStream = Pin<Box<dyn Stream<Item = AccountEvent<ExchangeId, AssetNameExchange, InstrumentNameExchange>> + Send>>

Source§

async fn account_snapshot( &self, assets: &[AssetNameExchange], instruments: &[InstrumentNameExchange], ) -> Result<UnindexedAccountSnapshot, UnindexedClientError>

Reads the account’s balances, and its open orders and positions for instruments, from the venue. Read more
Source§

async fn cancel_order( &self, request: OrderRequestCancel<ExchangeId, &InstrumentNameExchange>, ) -> UnindexedOrderResponseCancel

Cancel an order at the venue. Read more
Source§

async fn open_order( &self, request: OrderRequestOpen<ExchangeId, &InstrumentNameExchange>, ) -> Order<ExchangeId, InstrumentNameExchange, UnindexedOrderState>

Place an order on the exchange. Read more
Source§

async fn fetch_balances( &self, assets: &[AssetNameExchange], ) -> Result<Vec<AssetBalance<AssetNameExchange>>, UnindexedClientError>

Fetch current balances for the specified assets. Read more
Source§

fn validate_config( config: &Self::Config, instruments: &[ClientInstrument<'_>], ) -> Result<(), String>

Checks config against the instruments this client is about to be built to trade, before Self::new is called. Err names what is wrong. Read more
Source§

fn cancel_orders<'a>( &self, requests: impl IntoIterator<Item = OrderRequestCancel<ExchangeId, &'a InstrumentNameExchange>>, ) -> impl Stream<Item = UnindexedOrderResponseCancel> + Send

Source§

fn open_orders<'a>( &self, requests: impl IntoIterator<Item = OrderRequestOpen<ExchangeId, &'a InstrumentNameExchange>>, ) -> impl Stream<Item = Order<ExchangeId, InstrumentNameExchange, UnindexedOrderState>> + Send

Source§

impl OrderStatusClient for BinanceSpot

Looks each order up with GET /api/v3/order by symbol and client order id, weight 4 each, up to eight at a time. Binance’s FILLED is reported with its average price, CANCELED with what filled before it, EXPIRED and EXPIRED_IN_MATCH (self-trade prevention) as expired, and REJECTED as OpenFailed. An order Binance does not know under the key’s symbol (-2013, or -1121 for a symbol that does not exist) is omitted. A row whose status this version does not know is omitted too, with a warning, as is a PENDING_CANCEL one, which Binance does not use.

The account stream runs the same lookup itself after a reconnect; see account_stream.

Source§

async fn fetch_ended_orders( &self, orders: &[UnindexedOrderKey], ) -> Result<Vec<UnindexedInactiveOrder>, UnindexedClientError>

How each of orders ended, for those that have. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Conv for T

Source§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> FmtForward for T

Source§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
Source§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
Source§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
Source§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
Source§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
Source§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
Source§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
Source§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
Source§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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 more
Source§

impl<T> JsonSchemaMaybe for T

Source§

impl<T> Pipe for T
where T: ?Sized,

Source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
Source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
Source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows 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
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows 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
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
Source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Tap for T

Source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
Source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
Source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
Source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
Source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
Source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
Source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
Source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
Source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
Source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .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
where Self: BorrowMut<B>, B: ?Sized,

Calls .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
where Self: AsRef<R>, R: ?Sized,

Calls .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
where Self: AsMut<R>, R: ?Sized,

Calls .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
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> TryConv for T

Source§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more