Skip to main content

Error

Enum Error 

Source
#[non_exhaustive]
pub enum Error { Config(ConfigError), Transport(TransportError), RateLimited { retry_after: Duration, }, Rejected { code: String, message: String, }, Unknown, Unsupported { capability: Cow<'static, str>, }, NotReconciled, Degraded, ShuttingDown, }
Expand description

What can go wrong in a connector call.

The texts printed by Display are the ones on the errors page of the book (docs/src/errors.md), with what they mean and what to do. A test keeps the two in step.

Each variant says what happened and what the caller does next. Error::class groups them. Reading calls (order book, history, portfolio) return only the variants that make sense for a read: Error::Config, Error::Transport, Error::RateLimited, Error::Rejected and Error::Unsupported. The gate variants (Error::NotReconciled, Error::Degraded, Error::ShuttingDown) come from trading commands.

§Examples

use std::time::Duration;
use brokapi_core::{Error, ErrorClass};

/// What a caller does with an error of a reading call.
fn next_step(e: &Error) -> &'static str {
    match e {
        Error::RateLimited { retry_after } if *retry_after < Duration::from_secs(5) => "wait and repeat",
        Error::Transport(_) => "repeat later",
        Error::Unsupported { .. } => "ask the broker another way, or skip",
        _ => "give up and report",
    }
}

let e = Error::RateLimited { retry_after: Duration::from_secs(1) };
assert_eq!(e.class(), ErrorClass::Retryable);
assert_eq!(next_step(&e), "wait and repeat");

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

Config(ConfigError)

The setup is wrong: a bad config value, or an input that cannot work with this broker (for example an InstrumentId whose NativeId is of another broker’s kind).

The broker refusing the credentials (a wrong or expired token, an authentication that failed) is this variant too, at every broker: fix the token, a repeat will not help.

Nothing was sent. The call will fail the same way until the config or the input is fixed.

§

Transport(TransportError)

The network or the broker’s endpoint failed in a way that is not an answer: connect, TLS, timeout of a read, a stream cut, an unreadable reply. (A refused authentication is Error::Config.)

For a reading call, repeat it later. For a trading command the connector returns Error::Unknown instead whenever the command might have reached the broker, so Transport on a command means the connector has no sign that it did (for example the authentication failed). Even then, look at the order before you send a command again, and use a new cid for a new place.

§

RateLimited

A rate limit stopped the call: the local limiter of the connector or the broker’s own answer (HTTP 429 or the equivalent).

Wait retry_after, then repeat. A command refused by the local limiter was not sent. A connector may still have used up the cid (see its docs), so for a place the safe rule is a new cid. The library does not wait and repeat for you.

Fields

§retry_after: Duration

How long to wait before the next try. A hint from the limiter or the broker, not a promise that the next call passes.

§

Rejected

The broker (or the connector, before sending) said no to this request, and nothing was done.

The request is wrong or not allowed: a price outside the band, no money, an unknown order, an order that is already filled, a missing price on a limit order. Change the request. Do not repeat it as it is.

code is a short machine-readable label that the connector sets (for example validation, missing_price, invalid_qty, not_found, already_filled, duplicate_place, http_400). message is the broker’s text or the connector’s explanation, for a human. The set of codes belongs to the connector and is not fixed across brokers, except NOT_FOUND (the same at every broker: use Error::is_not_found) and the codes the shared set of checks relies on (duplicate_place, invalid_qty). Do not parse message.

Fields

§code: String

Short label of the reason, set by the connector. Safe to compare with ==.

§message: String

Explanation for a human, usually the broker’s own text.

§

Unknown

A command (place, cancel, replace, place_stop, cancel_stop) was sent, and no answer says whether the broker did it: a timeout, a connection cut after sending, an HTTP 5xx, an answer that cannot be read.

The order may exist, may be cancelled, or may never have arrived. The library NEVER repeats the command, because a repeated place could create a second order. Do the same:

  1. Do not send the command again.
  2. Ask the broker: OrderExecutor::order_state with the cid, or OrderExecutor::active_orders, or look for the fills in ExecutionSource::executions.
  3. Only when the broker has no such order, place a new one under a NEW cid.

Never turned into Error::Transport or Error::Rejected: those would say “nothing happened”, and here that is not known.

§

Unsupported

This connector or this broker does not have the capability, so the call was not made.

Returned at once, without a network call. capability is a short name of what is missing (for example stop_order_stream). The library does not emulate a missing stream by polling. If you need the data, poll yourself. See also UserDataCaps and MarketDataCaps, which declare what a connector can do.

Fields

§capability: Cow<'static, str>

Short name of the missing capability. Safe to compare with == against a &str. A Cow so that the error survives serialization (for example across a process boundary).

§

NotReconciled

The trading gate is closed: this connector has not run OrderExecutor::reconcile successfully yet.

Trading commands wait for the first reconcile, so that the connector knows which orders are already at the broker before it puts a new one. Call reconcile with your ledger (an empty slice if you have none), then repeat the command. Nothing was sent.

§

Degraded

The trading gate is closed because the connector lost events it could not afford to lose: a Backpressure::Lossless subscription overflowed (an Event::Overflow was sent).

The local state of orders may have a hole. Drain your event channel, then call OrderExecutor::reconcile: a successful reconcile opens the gate again. Nothing was sent.

§

ShuttingDown

The connector is shutting down and takes no new trading commands.

Final for this connector object. Orders already at the exchange are not touched by a shutdown. Start a new connector if you need to trade. Nothing was sent.

Implementations§

Source§

impl Error

Source

pub fn not_found(message: impl Into<String>) -> Self

A Error::Rejected with the code NOT_FOUND: the broker does not know the order, the cid or the instrument. Every connector uses this one for “not found”.

Source

pub fn is_not_found(&self) -> bool

Whether this is the “not found” refusal (Error::Rejected with the code NOT_FOUND).

§Examples
use brokapi_core::Error;

assert!(Error::not_found("x").is_not_found());
assert!(!Error::Unknown.is_not_found());
assert!(!Error::Rejected { code: "validation".into(), message: String::new() }.is_not_found());
Source

pub fn class(&self) -> ErrorClass

The coarse class of this error: may the call be tried again, or not.

The class says what is possible in principle, and it is the class of a read. A generic retry loop must not use it for a trading command: Error::Transport is Retryable here, and a command that failed with it may still have reached the broker. For a command ask retryable_for_command. The library itself never repeats a command, whatever the class.

§Examples
use brokapi_core::{Error, ErrorClass, TransportError};

let e = Error::Transport(TransportError::Message("timeout".into()));
assert_eq!(e.class(), ErrorClass::Retryable);
Source

pub fn retryable_for_command(&self) -> bool

May a trading command that failed with this error be sent again, after the wait the error names?

true only for Error::RateLimited: the broker (or the local limiter) refused before it acted, so the same cancel can be sent again after retry_after. A place needs a new cid, because the connector may have used the old one up. Everything else is false: Error::Transport and Error::Unknown mean the command may have reached the broker, so look at the order first (OrderExecutor::order_state), and the other variants are final until the setup, the gate or the request changes.

Use this, not class, in the retry loop of a command.

§Examples
use std::time::Duration;
use brokapi_core::{Error, TransportError};

assert!(Error::RateLimited { retry_after: Duration::from_secs(1) }.retryable_for_command());
// A read may be repeated after this error, a command may not.
let cut = Error::Transport(TransportError::Message("connection reset".into()));
assert!(!cut.retryable_for_command());
assert!(!Error::Unknown.retryable_for_command());
assert!(!Error::Degraded.retryable_for_command());

Trait Implementations§

Source§

impl Clone for Error

Source§

fn clone(&self) -> Error

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 Error

Source§

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

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

impl<'de> Deserialize<'de> for Error

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Display for Error

Source§

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

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

impl Error for Error

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0:

use the Display impl or to_string()

1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ConfigError> for Error

Source§

fn from(source: ConfigError) -> Self

Converts to this type from the input type.
Source§

impl From<TransportError> for Error

Source§

fn from(source: TransportError) -> Self

Converts to this type from the input type.
Source§

impl Serialize for Error

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

§

impl Freeze for Error

§

impl RefUnwindSafe for Error

§

impl Send for Error

§

impl Sync for Error

§

impl Unpin for Error

§

impl UnsafeUnpin for Error

§

impl UnwindSafe for Error

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> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> 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> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

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

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.