pub trait ExecutionClientwhere
Self: Clone,{
type Config: Clone;
type AccountStream: Stream<Item = UnindexedAccountEvent> + Send;
const EXCHANGE: ExchangeId;
const SUPPORTED_KINDS: &'static [InstrumentKindDiscriminant];
// Required methods
fn new(config: Self::Config) -> Self;
fn account_snapshot(
&self,
assets: &[AssetNameExchange],
instruments: &[InstrumentNameExchange],
) -> impl Future<Output = Result<UnindexedAccountSnapshot, UnindexedClientError>> + Send;
fn account_stream(
&self,
assets: &[AssetNameExchange],
instruments: &[InstrumentNameExchange],
) -> impl Future<Output = Result<Self::AccountStream, UnindexedClientError>> + Send;
fn cancel_order(
&self,
request: OrderRequestCancel<ExchangeId, &InstrumentNameExchange>,
) -> impl Future<Output = Option<UnindexedOrderResponseCancel>> + Send;
fn open_order(
&self,
request: OrderRequestOpen<ExchangeId, &InstrumentNameExchange>,
) -> impl Future<Output = Option<Order<ExchangeId, InstrumentNameExchange, UnindexedOrderState>>> + Send;
fn fetch_balances(
&self,
assets: &[AssetNameExchange],
) -> impl Future<Output = Result<Vec<AssetBalance<AssetNameExchange>>, UnindexedClientError>> + Send;
fn fetch_open_orders(
&self,
instruments: &[InstrumentNameExchange],
) -> impl Future<Output = Result<Vec<Order<ExchangeId, InstrumentNameExchange, Open>>, UnindexedClientError>> + Send;
fn fetch_trades(
&self,
time_since: DateTime<Utc>,
instruments: &[InstrumentNameExchange],
) -> impl Future<Output = Result<Vec<Trade<AssetNameExchange, InstrumentNameExchange>>, UnindexedClientError>> + Send;
// Provided methods
fn cancel_orders<'a>(
&self,
requests: impl IntoIterator<Item = OrderRequestCancel<ExchangeId, &'a InstrumentNameExchange>>,
) -> impl Stream<Item = Option<UnindexedOrderResponseCancel>> + Send { ... }
fn open_orders<'a>(
&self,
requests: impl IntoIterator<Item = OrderRequestOpen<ExchangeId, &'a InstrumentNameExchange>>,
) -> impl Stream<Item = Option<Order<ExchangeId, InstrumentNameExchange, UnindexedOrderState>>> + Send { ... }
}Required Associated Constants§
const EXCHANGE: ExchangeId
Sourceconst SUPPORTED_KINDS: &'static [InstrumentKindDiscriminant]
const SUPPORTED_KINDS: &'static [InstrumentKindDiscriminant]
The InstrumentKindDiscriminants this client can trade.
A client works off InstrumentNameExchange strings and never inspects an instrument’s
kind, so nothing downstream can infer this from the implementation — routing a Future
through a spot-only venue produces a rejected or, worse, misinterpreted order rather than a
type error. Declaring the set here lets ExecutionBuilder reject an unsupported
instrument set at build time, before any order is sent.
Declare what the venue and this implementation together can actually route, not what the exchange’s product catalogue advertises. A kind the exchange offers but this client builds no request for does not belong in the set.
There is deliberately no default. A new client must state its capabilities rather than inherit a permissive set that would silently admit every kind.
It is a const and not a fn supported_kinds(&self) because ExecutionBuilder validates
the instrument set before Self::new is ever called — there is no instance to ask at the
point the answer is needed, and deferring validation until after construction would mean
standing up a client for a venue the engine is about to reject. A capability set that varies
with Self::Config therefore cannot be expressed here; it would need a separate
pre-construction hook on the config.
Required Associated Types§
type Config: Clone
type AccountStream: Stream<Item = UnindexedAccountEvent> + Send
Required Methods§
fn new(config: Self::Config) -> Self
fn account_snapshot( &self, assets: &[AssetNameExchange], instruments: &[InstrumentNameExchange], ) -> impl Future<Output = Result<UnindexedAccountSnapshot, UnindexedClientError>> + Send
Sourcefn account_stream(
&self,
assets: &[AssetNameExchange],
instruments: &[InstrumentNameExchange],
) -> impl Future<Output = Result<Self::AccountStream, UnindexedClientError>> + Send
fn account_stream( &self, assets: &[AssetNameExchange], instruments: &[InstrumentNameExchange], ) -> impl Future<Output = Result<Self::AccountStream, UnindexedClientError>> + Send
Returns a live stream of account events (fills, order updates, balance changes).
§Startup race window
There is an unavoidable gap between the WebSocket subscribe response and the
first event being delivered: fills arriving in this window (typically milliseconds,
no sub-millisecond guarantee) are silently dropped. account_snapshot reconciles
open-order state, but TRADE fills in this window are not recoverable from the stream
alone. Callers that require fill completeness at startup must call
ExecutionClient::fetch_trades with at least a 1-second lookback after this method returns.
§Backpressure
Implementations use unbounded internal channels. If the consumer cannot keep up, events queue in memory rather than being dropped — per library philosophy, OOM crashes are preferable to silent data loss. Consumers requiring backpressure should implement it at their boundary (e.g., bounded channel with overflow policy).
fn cancel_order( &self, request: OrderRequestCancel<ExchangeId, &InstrumentNameExchange>, ) -> impl Future<Output = Option<UnindexedOrderResponseCancel>> + Send
Sourcefn open_order(
&self,
request: OrderRequestOpen<ExchangeId, &InstrumentNameExchange>,
) -> impl Future<Output = Option<Order<ExchangeId, InstrumentNameExchange, UnindexedOrderState>>> + Send
fn open_order( &self, request: OrderRequestOpen<ExchangeId, &InstrumentNameExchange>, ) -> impl Future<Output = Option<Order<ExchangeId, InstrumentNameExchange, UnindexedOrderState>>> + Send
Place an order on the exchange.
§Return value
Returns OrderState directly rather than Result<Open, OrderError>:
OrderState::Active(Open)- order is resting on the order bookOrderState::Inactive(FullyFilled)- order was immediately filled (includesavg_pricewhen available)OrderState::Inactive(OpenFailed)- order placement failed (API error, connectivity, etc.)
This design allows immediate fills to carry metadata (e.g., avg_price) that
would be lost if we had to infer terminal state from Open::filled_quantity.
Sourcefn fetch_balances(
&self,
assets: &[AssetNameExchange],
) -> impl Future<Output = Result<Vec<AssetBalance<AssetNameExchange>>, UnindexedClientError>> + Send
fn fetch_balances( &self, assets: &[AssetNameExchange], ) -> impl Future<Output = Result<Vec<AssetBalance<AssetNameExchange>>, UnindexedClientError>> + Send
Fetch current balances for the specified assets.
An empty assets slice is the “return all” sentinel: implementations must return
balances for every asset held. When non-empty, only the listed assets are returned.
Sourcefn fetch_open_orders(
&self,
instruments: &[InstrumentNameExchange],
) -> impl Future<Output = Result<Vec<Order<ExchangeId, InstrumentNameExchange, Open>>, UnindexedClientError>> + Send
fn fetch_open_orders( &self, instruments: &[InstrumentNameExchange], ) -> impl Future<Output = Result<Vec<Order<ExchangeId, InstrumentNameExchange, Open>>, UnindexedClientError>> + Send
Fetch currently open orders, optionally filtered by instrument.
An empty instruments slice is the “return all” sentinel: implementations must
return open orders across all instruments. When non-empty, only orders for the
listed instruments are returned.
Sourcefn fetch_trades(
&self,
time_since: DateTime<Utc>,
instruments: &[InstrumentNameExchange],
) -> impl Future<Output = Result<Vec<Trade<AssetNameExchange, InstrumentNameExchange>>, UnindexedClientError>> + Send
fn fetch_trades( &self, time_since: DateTime<Utc>, instruments: &[InstrumentNameExchange], ) -> impl Future<Output = Result<Vec<Trade<AssetNameExchange, InstrumentNameExchange>>, UnindexedClientError>> + Send
Fetch trades (fills) since time_since, optionally filtered by instrument.
An empty instruments slice is the “return all” sentinel: implementations must
return trades across all instruments. When non-empty, only trades for the listed
instruments are returned.
The fee asset (AssetNameExchange) may be quote, base, or third-party (e.g., BNB).
Use fees.fees_quote for quote-equivalent value when available.
Note: MockExecution currently ignores instruments and always returns all trades.
Provided Methods§
fn cancel_orders<'a>( &self, requests: impl IntoIterator<Item = OrderRequestCancel<ExchangeId, &'a InstrumentNameExchange>>, ) -> impl Stream<Item = Option<UnindexedOrderResponseCancel>> + Send
fn open_orders<'a>( &self, requests: impl IntoIterator<Item = OrderRequestOpen<ExchangeId, &'a InstrumentNameExchange>>, ) -> impl Stream<Item = Option<Order<ExchangeId, InstrumentNameExchange, UnindexedOrderState>>> + Send
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".