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 serial_test as _;
34#[cfg(test)]
35use tracing_subscriber as _;
36#[cfg(test)]
37use wiremock as _;
38
39use crate::{
40 balance::AssetBalance,
41 order::{Order, OrderSnapshot, request::OrderResponseCancel},
42 position::Position,
43 trade::Trade,
44};
45use chrono::{DateTime, Utc};
46use derive_more::{Constructor, From};
47use order::state::OrderState;
48use rustrade_instrument::{
49 asset::{AssetIndex, name::AssetNameExchange},
50 exchange::{ExchangeId, ExchangeIndex},
51 instrument::{InstrumentIndex, name::InstrumentNameExchange},
52};
53use rustrade_integration::collection::snapshot::Snapshot;
54use serde::{Deserialize, Serialize};
55
56pub mod balance;
57pub mod client;
58pub mod error;
59pub mod exchange;
60pub mod fee;
61pub use fee::{FeeModel, FeeModelConfig, PerContractFeeModel, PercentageFeeModel, ZeroFeeModel};
62pub mod fill;
63pub use fill::{BidAskFillModel, FillModel, LastPriceFillModel, MidpointFillModel, SimFillConfig};
64pub mod indexer;
65pub mod map;
66pub mod order;
67pub mod position;
68pub mod trade;
69
70pub type UnindexedAccountEvent =
73 AccountEvent<ExchangeId, AssetNameExchange, InstrumentNameExchange>;
74
75pub type UnindexedAccountSnapshot =
78 AccountSnapshot<ExchangeId, AssetNameExchange, InstrumentNameExchange>;
79
80#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
81pub struct AccountEvent<
82 ExchangeKey = ExchangeIndex,
83 AssetKey = AssetIndex,
84 InstrumentKey = InstrumentIndex,
85> {
86 pub exchange: ExchangeKey,
87 pub kind: AccountEventKind<ExchangeKey, AssetKey, InstrumentKey>,
88}
89
90impl<ExchangeKey, AssetKey, InstrumentKey> AccountEvent<ExchangeKey, AssetKey, InstrumentKey> {
91 pub fn new<K>(exchange: ExchangeKey, kind: K) -> Self
92 where
93 K: Into<AccountEventKind<ExchangeKey, AssetKey, InstrumentKey>>,
94 {
95 Self {
96 exchange,
97 kind: kind.into(),
98 }
99 }
100}
101
102#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, From)]
103#[non_exhaustive]
104pub enum AccountEventKind<ExchangeKey, AssetKey, InstrumentKey> {
105 Snapshot(AccountSnapshot<ExchangeKey, AssetKey, InstrumentKey>),
107
108 BalanceSnapshot(Snapshot<AssetBalance<AssetKey>>),
110
111 OrderSnapshot(Snapshot<Order<ExchangeKey, InstrumentKey, OrderState<AssetKey, InstrumentKey>>>),
115
116 OrderCancelled(OrderResponseCancel<ExchangeKey, AssetKey, InstrumentKey>),
118
119 Trade(Trade<AssetKey, InstrumentKey>),
125
126 StreamError(String),
132}
133
134impl<ExchangeKey, AssetKey, InstrumentKey> AccountEvent<ExchangeKey, AssetKey, InstrumentKey>
135where
136 AssetKey: Eq,
137 InstrumentKey: Eq,
138{
139 pub fn snapshot(self) -> Option<AccountSnapshot<ExchangeKey, AssetKey, InstrumentKey>> {
140 match self.kind {
141 AccountEventKind::Snapshot(snapshot) => Some(snapshot),
142 _ => None,
143 }
144 }
145}
146
147#[derive(
148 Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize, Constructor,
149)]
150pub struct AccountSnapshot<
151 ExchangeKey = ExchangeIndex,
152 AssetKey = AssetIndex,
153 InstrumentKey = InstrumentIndex,
154> {
155 pub exchange: ExchangeKey,
156 pub balances: Vec<AssetBalance<AssetKey>>,
157 pub instruments: Vec<InstrumentAccountSnapshot<ExchangeKey, AssetKey, InstrumentKey>>,
158}
159
160#[derive(
161 Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize, Constructor,
162)]
163pub struct InstrumentAccountSnapshot<
164 ExchangeKey = ExchangeIndex,
165 AssetKey = AssetIndex,
166 InstrumentKey = InstrumentIndex,
167> {
168 pub instrument: InstrumentKey,
169 #[serde(default = "Vec::new")]
170 pub orders: Vec<OrderSnapshot<ExchangeKey, AssetKey, InstrumentKey>>,
171 #[serde(default, skip_serializing_if = "Option::is_none")]
174 pub position: Option<Position>,
175}
176
177impl<ExchangeKey, AssetKey, InstrumentKey> AccountSnapshot<ExchangeKey, AssetKey, InstrumentKey> {
178 pub fn time_most_recent(&self) -> Option<DateTime<Utc>> {
179 let order_times = self.instruments.iter().flat_map(|instrument| {
180 instrument
181 .orders
182 .iter()
183 .filter_map(|order| order.state.time_exchange())
184 });
185 let balance_times = self.balances.iter().map(|balance| balance.time_exchange);
186
187 order_times.chain(balance_times).max()
188 }
189
190 pub fn assets(&self) -> impl Iterator<Item = &AssetKey> {
191 self.balances.iter().map(|balance| &balance.asset)
192 }
193
194 pub fn instruments(&self) -> impl Iterator<Item = &InstrumentKey> {
195 self.instruments.iter().map(|snapshot| &snapshot.instrument)
196 }
197}