barter_execution/
lib.rs

1#![forbid(unsafe_code)]
2#![warn(
3    unused,
4    clippy::cognitive_complexity,
5    unused_crate_dependencies,
6    unused_extern_crates,
7    clippy::unused_self,
8    clippy::useless_let_if_seq,
9    missing_debug_implementations,
10    rust_2018_idioms,
11    rust_2024_compatibility
12)]
13#![allow(clippy::type_complexity, clippy::too_many_arguments, type_alias_bounds)]
14
15//! # Barter-Execution
16//! Stream private account data from financial venues, and execute (live or mock) orders. Also provides
17//! a feature rich MockExchange and MockExecutionClient to assist with backtesting and paper-trading.
18//!
19//! **It is:**
20//! * **Easy**: ExecutionClient trait provides a unified and simple language for interacting with exchanges.
21//! * **Normalised**: Allow your strategy to communicate with every real or MockExchange using the same interface.
22//! * **Extensible**: Barter-Execution is highly extensible, making it easy to contribute by adding new exchange integrations!
23//!
24//! See `README.md` for more information and examples.
25
26use crate::{
27    balance::AssetBalance,
28    order::{Order, OrderSnapshot, request::OrderResponseCancel},
29    trade::Trade,
30};
31use barter_instrument::{
32    asset::{AssetIndex, QuoteAsset, name::AssetNameExchange},
33    exchange::{ExchangeId, ExchangeIndex},
34    instrument::{InstrumentIndex, name::InstrumentNameExchange},
35};
36use barter_integration::snapshot::Snapshot;
37use chrono::{DateTime, Utc};
38use derive_more::{Constructor, From};
39use order::state::OrderState;
40use serde::{Deserialize, Serialize};
41
42pub mod balance;
43pub mod client;
44pub mod error;
45pub mod exchange;
46pub mod indexer;
47pub mod map;
48pub mod order;
49pub mod trade;
50
51/// Convenient type alias for an [`AccountEvent`] keyed with [`ExchangeId`],
52/// [`AssetNameExchange`], and [`InstrumentNameExchange`].
53pub type UnindexedAccountEvent =
54    AccountEvent<ExchangeId, AssetNameExchange, InstrumentNameExchange>;
55
56/// Convenient type alias for an [`AccountSnapshot`] keyed with [`ExchangeId`],
57/// [`AssetNameExchange`], and [`InstrumentNameExchange`].
58pub type UnindexedAccountSnapshot =
59    AccountSnapshot<ExchangeId, AssetNameExchange, InstrumentNameExchange>;
60
61#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
62pub struct AccountEvent<
63    ExchangeKey = ExchangeIndex,
64    AssetKey = AssetIndex,
65    InstrumentKey = InstrumentIndex,
66> {
67    pub exchange: ExchangeKey,
68    pub kind: AccountEventKind<ExchangeKey, AssetKey, InstrumentKey>,
69}
70
71impl<ExchangeKey, AssetKey, InstrumentKey> AccountEvent<ExchangeKey, AssetKey, InstrumentKey> {
72    pub fn new<K>(exchange: ExchangeKey, kind: K) -> Self
73    where
74        K: Into<AccountEventKind<ExchangeKey, AssetKey, InstrumentKey>>,
75    {
76        Self {
77            exchange,
78            kind: kind.into(),
79        }
80    }
81}
82
83#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, From)]
84pub enum AccountEventKind<ExchangeKey, AssetKey, InstrumentKey> {
85    /// Full [`AccountSnapshot`] - replaces all existing state.
86    Snapshot(AccountSnapshot<ExchangeKey, AssetKey, InstrumentKey>),
87
88    /// Single [`AssetBalance`] snapshot - replaces existing balance state.
89    BalanceSnapshot(Snapshot<AssetBalance<AssetKey>>),
90
91    /// Single [`Order`] snapshot - used to upsert existing order state if it's more recent.
92    ///
93    /// This variant covers general order updates, and open order responses.
94    OrderSnapshot(Snapshot<Order<ExchangeKey, InstrumentKey, OrderState<AssetKey, InstrumentKey>>>),
95
96    /// Response to an [`OrderRequestCancel<ExchangeKey, InstrumentKey>`](order::request::OrderRequestOpen).
97    OrderCancelled(OrderResponseCancel<ExchangeKey, AssetKey, InstrumentKey>),
98
99    /// [`Order<ExchangeKey, InstrumentKey, Open>`] partial or full-fill.
100    Trade(Trade<QuoteAsset, InstrumentKey>),
101}
102
103impl<ExchangeKey, AssetKey, InstrumentKey> AccountEvent<ExchangeKey, AssetKey, InstrumentKey>
104where
105    AssetKey: Eq,
106    InstrumentKey: Eq,
107{
108    pub fn snapshot(self) -> Option<AccountSnapshot<ExchangeKey, AssetKey, InstrumentKey>> {
109        match self.kind {
110            AccountEventKind::Snapshot(snapshot) => Some(snapshot),
111            _ => None,
112        }
113    }
114}
115
116#[derive(
117    Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize, Constructor,
118)]
119pub struct AccountSnapshot<
120    ExchangeKey = ExchangeIndex,
121    AssetKey = AssetIndex,
122    InstrumentKey = InstrumentIndex,
123> {
124    pub exchange: ExchangeKey,
125    pub balances: Vec<AssetBalance<AssetKey>>,
126    pub instruments: Vec<InstrumentAccountSnapshot<ExchangeKey, AssetKey, InstrumentKey>>,
127}
128
129#[derive(
130    Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize, Constructor,
131)]
132pub struct InstrumentAccountSnapshot<
133    ExchangeKey = ExchangeIndex,
134    AssetKey = AssetIndex,
135    InstrumentKey = InstrumentIndex,
136> {
137    pub instrument: InstrumentKey,
138    #[serde(default = "Vec::new")]
139    pub orders: Vec<OrderSnapshot<ExchangeKey, AssetKey, InstrumentKey>>,
140}
141
142impl<ExchangeKey, AssetKey, InstrumentKey> AccountSnapshot<ExchangeKey, AssetKey, InstrumentKey> {
143    pub fn time_most_recent(&self) -> Option<DateTime<Utc>> {
144        let order_times = self.instruments.iter().flat_map(|instrument| {
145            instrument
146                .orders
147                .iter()
148                .filter_map(|order| order.state.time_exchange())
149        });
150        let balance_times = self.balances.iter().map(|balance| balance.time_exchange);
151
152        order_times.chain(balance_times).max()
153    }
154
155    pub fn assets(&self) -> impl Iterator<Item = &AssetKey> {
156        self.balances.iter().map(|balance| &balance.asset)
157    }
158
159    pub fn instruments(&self) -> impl Iterator<Item = &InstrumentKey> {
160        self.instruments.iter().map(|snapshot| &snapshot.instrument)
161    }
162}