1#![forbid(unsafe_code)]
2#![deny(
3 clippy::unwrap_used,
4 clippy::expect_used,
5 clippy::cast_possible_truncation,
6 clippy::cast_sign_loss
7)]
8#![warn(
9 unused,
10 clippy::cognitive_complexity,
11 unused_crate_dependencies,
12 unused_extern_crates,
13 clippy::unused_self,
14 clippy::useless_let_if_seq,
15 missing_debug_implementations,
16 rust_2018_idioms
17)]
18#![allow(clippy::type_complexity, clippy::too_many_arguments, type_alias_bounds)]
19
20#[cfg(test)]
33use tracing_subscriber as _;
34#[cfg(test)]
35use wiremock as _;
36
37use crate::{
38 balance::AssetBalance,
39 order::{Order, OrderSnapshot, request::OrderResponseCancel},
40 position::Position,
41 trade::Trade,
42};
43use chrono::{DateTime, Utc};
44use derive_more::{Constructor, From};
45use order::state::OrderState;
46use rustrade_instrument::{
47 asset::{AssetIndex, name::AssetNameExchange},
48 exchange::{ExchangeId, ExchangeIndex},
49 instrument::{InstrumentIndex, name::InstrumentNameExchange},
50};
51use rustrade_integration::collection::snapshot::Snapshot;
52use serde::{Deserialize, Serialize};
53
54pub mod balance;
55pub mod client;
56pub mod error;
57pub mod exchange;
58pub mod fee;
59pub use fee::{FeeModel, FeeModelConfig, PerContractFeeModel, PercentageFeeModel, ZeroFeeModel};
60pub mod fill;
61pub use fill::{BidAskFillModel, FillModel, LastPriceFillModel, MidpointFillModel, SimFillConfig};
62pub mod indexer;
63pub mod map;
64pub mod order;
65pub mod position;
66pub mod trade;
67
68pub type UnindexedAccountEvent =
71 AccountEvent<ExchangeId, AssetNameExchange, InstrumentNameExchange>;
72
73pub type UnindexedAccountSnapshot =
76 AccountSnapshot<ExchangeId, AssetNameExchange, InstrumentNameExchange>;
77
78#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
79pub struct AccountEvent<
80 ExchangeKey = ExchangeIndex,
81 AssetKey = AssetIndex,
82 InstrumentKey = InstrumentIndex,
83> {
84 pub exchange: ExchangeKey,
85 pub kind: AccountEventKind<ExchangeKey, AssetKey, InstrumentKey>,
86}
87
88impl<ExchangeKey, AssetKey, InstrumentKey> AccountEvent<ExchangeKey, AssetKey, InstrumentKey> {
89 pub fn new<K>(exchange: ExchangeKey, kind: K) -> Self
90 where
91 K: Into<AccountEventKind<ExchangeKey, AssetKey, InstrumentKey>>,
92 {
93 Self {
94 exchange,
95 kind: kind.into(),
96 }
97 }
98}
99
100#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, From)]
101#[non_exhaustive]
102pub enum AccountEventKind<ExchangeKey, AssetKey, InstrumentKey> {
103 Snapshot(AccountSnapshot<ExchangeKey, AssetKey, InstrumentKey>),
105
106 BalanceSnapshot(Snapshot<AssetBalance<AssetKey>>),
108
109 OrderSnapshot(Snapshot<Order<ExchangeKey, InstrumentKey, OrderState<AssetKey, InstrumentKey>>>),
113
114 OrderCancelled(OrderResponseCancel<ExchangeKey, AssetKey, InstrumentKey>),
116
117 Trade(Trade<AssetKey, InstrumentKey>),
123
124 StreamError(String),
130}
131
132impl<ExchangeKey, AssetKey, InstrumentKey> AccountEvent<ExchangeKey, AssetKey, InstrumentKey>
133where
134 AssetKey: Eq,
135 InstrumentKey: Eq,
136{
137 pub fn snapshot(self) -> Option<AccountSnapshot<ExchangeKey, AssetKey, InstrumentKey>> {
138 match self.kind {
139 AccountEventKind::Snapshot(snapshot) => Some(snapshot),
140 _ => None,
141 }
142 }
143}
144
145#[derive(
146 Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize, Constructor,
147)]
148pub struct AccountSnapshot<
149 ExchangeKey = ExchangeIndex,
150 AssetKey = AssetIndex,
151 InstrumentKey = InstrumentIndex,
152> {
153 pub exchange: ExchangeKey,
154 pub balances: Vec<AssetBalance<AssetKey>>,
155 pub instruments: Vec<InstrumentAccountSnapshot<ExchangeKey, AssetKey, InstrumentKey>>,
156}
157
158#[derive(
159 Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize, Constructor,
160)]
161pub struct InstrumentAccountSnapshot<
162 ExchangeKey = ExchangeIndex,
163 AssetKey = AssetIndex,
164 InstrumentKey = InstrumentIndex,
165> {
166 pub instrument: InstrumentKey,
167 #[serde(default = "Vec::new")]
168 pub orders: Vec<OrderSnapshot<ExchangeKey, AssetKey, InstrumentKey>>,
169 #[serde(default, skip_serializing_if = "Option::is_none")]
172 pub position: Option<Position>,
173}
174
175impl<ExchangeKey, AssetKey, InstrumentKey> AccountSnapshot<ExchangeKey, AssetKey, InstrumentKey> {
176 pub fn time_most_recent(&self) -> Option<DateTime<Utc>> {
177 let order_times = self.instruments.iter().flat_map(|instrument| {
178 instrument
179 .orders
180 .iter()
181 .filter_map(|order| order.state.time_exchange())
182 });
183 let balance_times = self.balances.iter().map(|balance| balance.time_exchange);
184
185 order_times.chain(balance_times).max()
186 }
187
188 pub fn assets(&self) -> impl Iterator<Item = &AssetKey> {
189 self.balances.iter().map(|balance| &balance.asset)
190 }
191
192 pub fn instruments(&self) -> impl Iterator<Item = &InstrumentKey> {
193 self.instruments.iter().map(|snapshot| &snapshot.instrument)
194 }
195}