Errors#
What methods return#
Every ExchangeTrader method returns anyhow::Result<T>. Network failures, signature problems, exchange error codes and "not implemented" cases all arrive as an anyhow::Error with a message. Print it with {e:#} to see the whole context chain.
match trader.get_balance().await {
Ok(b) => println!("{}", b.available_balance),
Err(e) => eprintln!("balance failed: {e:#}"),
}
Rejected orders#
Order methods return Result<OrderResult>. A request the exchange refuses may come back as Ok with success == false and a message in error, not as Err. Check both:
match trader.place_market_order("BTCUSDT", OrderSide::Buy, 0.001).await {
Ok(r) if r.success => println!("filled {}", r.order_id()),
Ok(r) => eprintln!("rejected: {:?}", r.error),
Err(e) => eprintln!("request failed: {e:#}"),
}
Err means the call itself failed, for example a network error or a malformed response. Ok with success == false means the exchange answered and said no.
"Not implemented"#
Optional trait methods that an adapter does not override return an error shaped like get_ticker not implemented for <exchange>. Check capabilities before calling optional methods on adapters you have not used.
ExchangeError#
tradersdk_core::ExchangeError (re-exported in the prelude) is a typed error enum:
| Variant | Meaning |
|---|---|
Network(reqwest::Error) |
Network error during an API call. |
Authentication(String) |
Authentication failed. |
InvalidResponse(String) |
The response could not be understood. |
RateLimited { retry_after_ms } |
Rate limit exceeded. |
OrderRejected(String) |
Order rejected by the exchange. |
InsufficientFunds(String) |
Not enough balance. |
SymbolNotFound(String) |
Unknown symbol. |
InvalidOrder(String) |
Invalid order parameters. |
PositionNotFound(String) |
No such position. |
WebSocket(String) |
WebSocket error. |
ExchangeSpecific { exchange, code, message } |
An exchange-specific error code. |
Other(String) |
Anything else. |
It has constructors (ExchangeError::auth("..."), rate_limited(ms), ...) and helpers:
is_retryable()is true forNetwork,RateLimitedandWebSocket.is_rate_limited()andretry_after()(milliseconds).
Adapters do not return
ExchangeErroryet. The bundled adapters returnanyhowerrors built from messages, soerr.downcast_ref::<ExchangeError>()will usually find nothing. UseExchangeErrorin your own code and in new adapters, and match on error messages for the built-in ones until the adapters adopt the typed variants.
Retrying#
The tradersdk-utils crate has retry, rate-limiting and circuit-breaking helpers. See Utilities. Do not blindly retry order placement: a request that timed out may still have reached the exchange. Check the order status before sending it again.