Skip to main content

brokapi_core/
lib.rs

1//! The public surface of brokapi: domain types, capability traits, events and errors.
2//!
3//! This is the core crate of the workspace. It has no network code and does not depend on any
4//! broker. A broker connector (`brokapi-bcs`, `brokapi-tbank`, `brokapi-finam`) implements the traits
5//! of this crate, and your program is written against them, so the same code runs on every broker.
6//! Documentation of the whole library, with guides: <https://brokapi.ru/docs/>.
7//!
8//! # What is here
9//!
10//! | Part | Items |
11//! |---|---|
12//! | Traits | [`OrderBookSource`], [`MarketDataSource`], [`InstrumentSource`] (market data), [`OrderExecutor`], [`ExecutionSource`], [`PortfolioSource`], [`StopOrderExecutor`] (your account) |
13//! | Events | [`Envelope`] around an [`Event`], delivered into a `tokio::sync::mpsc` channel you give to the connector |
14//! | Errors | [`Error`] with [`ErrorClass`], one enum for all brokers |
15//! | Capabilities | [`MarketDataCaps`], [`UserDataCaps`]: what a connector can do, as data |
16//! | Types | [`InstrumentId`], [`OrderBook`], [`PlaceOrderRequest`], [`OrderSnapshot`], [`Execution`], [`Portfolio`], [`Price`], [`Qty`], [`UnixNanos`] and the rest of [`types`] |
17//! | Order ids | [`ClientOrderId`] and the [`CidCodec`] that maps it to a broker's form |
18//!
19//! # Rules to know before you trade
20//!
21//! - You make the [`ClientOrderId`] of every order and keep a ledger of them.
22//! - Trading commands are refused until [`OrderExecutor::reconcile`] succeeds once
23//!   ([`Error::NotReconciled`]).
24//! - A command with no answer is [`Error::Unknown`]. The library never repeats a command, and neither
25//!   should you before you have looked at the order.
26//! - Read your event channel steadily. A subscription that must not lose events overflows loudly
27//!   ([`Event::Overflow`]) and trading stops ([`Error::Degraded`]) until you reconcile.
28//! - Shutdown never cancels orders at the exchange.
29//!
30//! # Examples
31//!
32//! Read an order book and handle the error by its class. The connector here is the BCS one on an
33//! in-process imitation of the broker, so the example runs without a network.
34//!
35//! ```
36//! use brokapi_bcs::limits::default_limits;
37//! use brokapi_bcs::{MarketDataConfig, MarketDataConnector};
38//! use brokapi_core::{
39//!     ErrorClass, InstrumentId, InstrumentKey, NativeId, OrderBook, OrderBookSource, ShutdownMode,
40//! };
41//! use brokapi_runtime::BrokerLimiter;
42//! # use brokapi_bcs_protocol::config::BcsConfig;
43//!
44//! # #[tokio::main(flavor = "current_thread")]
45//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
46//! # let server = brokapi_mocks::bcs::MockServer::start(Default::default()).await;
47//! # let cfg = BcsConfig::for_mock("mock-refresh-token", &server.http_base);
48//! // The connector writes stream events into this channel. A plain read does not need it.
49//! let (events_tx, _events) = tokio::sync::mpsc::channel(256);
50//! let limiter = BrokerLimiter::new(&default_limits());
51//! let md = MarketDataConnector::start(MarketDataConfig::new(cfg, "bcs-md"), limiter, events_tx).await?;
52//!
53//! let sber = InstrumentId::new(
54//!     InstrumentKey::new("SBER", "TQBR"),
55//!     NativeId::TickerClass { ticker: "SBER".into(), class_code: "TQBR".into() },
56//! );
57//! match md.order_book(&sber, 5).await {
58//!     Ok(OrderBook::Snapshot { bids, asks, .. }) => {
59//!         println!("best bid {:?}, best ask {:?}", bids.first(), asks.first());
60//!     }
61//!     Ok(_) => unreachable!("a read answers a snapshot"),
62//!     Err(e) if e.class() == ErrorClass::Retryable => println!("try again later: {e}"),
63//!     Err(e) => println!("will not work as it is: {e}"),
64//! }
65//!
66//! md.shutdown(ShutdownMode::Immediate).await;
67//! # Ok(())
68//! # }
69//! ```
70
71#![warn(missing_docs)]
72
73pub mod cid;
74pub mod error;
75pub mod traits;
76pub mod types;
77
78pub use cid::{Charset, CidCaps, CidCodec, CidError, HexUuidCodec, NativeCid};
79pub use error::{ConfigError, Error, ErrorClass, NOT_FOUND, TransportError};
80pub use traits::{
81    Connector, ExecutionSource, InstrumentSource, MarketDataSource, OrderBookSource, OrderExecutor,
82    PortfolioSource, StopOrderExecutor,
83};
84pub use types::*;
85
86/// The exact decimal number inside [`Price`], [`Qty`] and [`Money`] (from the `rust_decimal` crate).
87pub use rust_decimal::Decimal;
88/// Makes a [`Decimal`] from a literal: `dec!(250.15)`. Needs `Decimal` in scope
89/// (`use brokapi_core::{Decimal, dec};`).
90pub use rust_decimal_macros::dec;