1use crate::{
2 AccountEvent, AccountEventKind, AccountSnapshot, InstrumentAccountSnapshot,
3 InstrumentBalanceUpdate, IsolatedInstrumentState, UnindexedAccountEvent,
4 UnindexedAccountSnapshot,
5 balance::{AssetBalance, AssetBalanceUpdate},
6 error::{
7 ApiError, ClientError, KeyError, OrderError, UnindexedApiError, UnindexedClientError,
8 UnindexedOrderError,
9 },
10 map::ExecutionInstrumentMap,
11 order::{
12 Order, OrderEvent, OrderKey, OrderSnapshot, UnindexedOrderKey, UnindexedOrderSnapshot,
13 request::OrderResponseCancel,
14 state::{InactiveOrderState, OrderState, UnindexedOrderState},
15 },
16 trade::{AssetFees, Trade},
17};
18use derive_more::Constructor;
19use rustrade_instrument::{
20 asset::{AssetIndex, name::AssetNameExchange},
21 exchange::{ExchangeId, ExchangeIndex},
22 index::error::IndexError,
23 instrument::{InstrumentIndex, name::InstrumentNameExchange},
24};
25use rustrade_integration::{
26 collection::snapshot::Snapshot,
27 stream::ext::indexed::{IndexedStream, Indexer},
28};
29use std::sync::Arc;
30
31pub type IndexedAccountStream<St> = IndexedStream<St, AccountEventIndexer>;
32
33#[derive(Debug, Clone, Constructor)]
34pub struct AccountEventIndexer {
35 pub map: Arc<ExecutionInstrumentMap>,
36}
37
38impl Indexer for AccountEventIndexer {
39 type Unindexed = UnindexedAccountEvent;
40 type Indexed = AccountEvent;
41
42 fn index(&self, item: Self::Unindexed) -> Result<Self::Indexed, IndexError> {
43 self.account_event(item)
44 }
45}
46
47impl AccountEventIndexer {
48 pub fn account_event(&self, event: UnindexedAccountEvent) -> Result<AccountEvent, IndexError> {
49 let UnindexedAccountEvent { exchange, kind } = event;
50
51 let exchange = self.map.find_exchange_index(exchange)?;
52
53 let kind = match kind {
54 AccountEventKind::Snapshot(snapshot) => {
55 AccountEventKind::Snapshot(self.snapshot(snapshot)?)
56 }
57 AccountEventKind::BalanceSnapshot(snapshot) => {
58 AccountEventKind::BalanceSnapshot(self.asset_balance(snapshot.0).map(Snapshot)?)
59 }
60 AccountEventKind::BalanceStreamUpdate(snapshot) => {
61 AccountEventKind::BalanceStreamUpdate(
62 self.asset_balance_update(snapshot.0).map(Snapshot)?,
63 )
64 }
65 AccountEventKind::InstrumentBalanceUpdate(update) => {
66 AccountEventKind::InstrumentBalanceUpdate(self.instrument_balance_update(update)?)
67 }
68 AccountEventKind::OrderSnapshot(snapshot) => {
69 AccountEventKind::OrderSnapshot(self.order_snapshot(snapshot.0).map(Snapshot)?)
70 }
71 AccountEventKind::OrderCancelled(response) => {
72 AccountEventKind::OrderCancelled(self.order_response_cancel(response)?)
73 }
74 AccountEventKind::Trade(trade) => AccountEventKind::Trade(self.trade(trade)?),
75 AccountEventKind::StreamError(msg) => AccountEventKind::StreamError(msg),
76 };
77
78 Ok(AccountEvent { exchange, kind })
79 }
80
81 pub fn snapshot(
82 &self,
83 snapshot: UnindexedAccountSnapshot,
84 ) -> Result<AccountSnapshot, IndexError> {
85 let UnindexedAccountSnapshot {
86 exchange,
87 balances,
88 instruments,
89 } = snapshot;
90
91 let exchange = self.map.find_exchange_index(exchange)?;
92
93 let balances = balances
94 .into_iter()
95 .map(|balance| self.asset_balance(balance))
96 .collect::<Result<Vec<_>, _>>()?;
97
98 let instruments = instruments
99 .into_iter()
100 .map(|snapshot| {
101 let InstrumentAccountSnapshot {
102 instrument,
103 orders,
104 position,
105 isolated,
106 } = snapshot;
107
108 let instrument = self.map.find_instrument_index(&instrument)?;
109
110 let orders = orders
111 .into_iter()
112 .map(|order| self.order_snapshot(order))
113 .collect::<Result<Vec<_>, _>>()?;
114
115 let isolated = isolated
119 .map(|state| self.isolated_instrument_state(state))
120 .transpose()?;
121
122 Ok(InstrumentAccountSnapshot {
123 instrument,
124 orders,
125 position,
126 isolated,
127 })
128 })
129 .collect::<Result<Vec<_>, _>>()?;
130
131 Ok(AccountSnapshot {
132 exchange,
133 balances,
134 instruments,
135 })
136 }
137
138 pub fn asset_balance(
139 &self,
140 balance: AssetBalance<AssetNameExchange>,
141 ) -> Result<AssetBalance<AssetIndex>, IndexError> {
142 let AssetBalance {
143 asset,
144 balance,
145 time_exchange,
146 } = balance;
147 let asset = self.map.find_asset_index(&asset)?;
148
149 Ok(AssetBalance {
150 asset,
151 balance,
152 time_exchange,
153 })
154 }
155
156 pub fn asset_balance_update(
157 &self,
158 update: AssetBalanceUpdate<AssetNameExchange>,
159 ) -> Result<AssetBalanceUpdate<AssetIndex>, IndexError> {
160 let AssetBalanceUpdate {
161 asset,
162 update,
163 time_exchange,
164 } = update;
165 let asset = self.map.find_asset_index(&asset)?;
166
167 Ok(AssetBalanceUpdate {
168 asset,
169 update,
170 time_exchange,
171 })
172 }
173
174 pub fn isolated_instrument_state(
180 &self,
181 state: IsolatedInstrumentState<AssetNameExchange>,
182 ) -> Result<IsolatedInstrumentState<AssetIndex>, IndexError> {
183 let IsolatedInstrumentState { base, quote, risk } = state;
184
185 Ok(IsolatedInstrumentState {
186 base: self.asset_balance(base)?,
187 quote: self.asset_balance(quote)?,
188 risk,
189 })
190 }
191
192 pub fn instrument_balance_update(
197 &self,
198 update: InstrumentBalanceUpdate<AssetNameExchange, InstrumentNameExchange>,
199 ) -> Result<InstrumentBalanceUpdate, IndexError> {
200 let InstrumentBalanceUpdate {
201 instrument,
202 base,
203 quote,
204 } = update;
205
206 Ok(InstrumentBalanceUpdate {
207 instrument: self.map.find_instrument_index(&instrument)?,
208 base: self.asset_balance_update(base)?,
209 quote: self.asset_balance_update(quote)?,
210 })
211 }
212
213 pub fn order_snapshot(
214 &self,
215 order: UnindexedOrderSnapshot,
216 ) -> Result<OrderSnapshot, IndexError> {
217 let Order {
218 key,
219 side,
220 price,
221 quantity,
222 kind,
223 time_in_force,
224 state,
225 } = order;
226
227 let key = self.order_key(key)?;
228 let state = self.order_state(state)?;
229
230 Ok(Order {
231 key,
232 side,
233 price,
234 quantity,
235 kind,
236 time_in_force,
237 state,
238 })
239 }
240
241 pub fn order_response_cancel(
242 &self,
243 response: OrderResponseCancel<ExchangeId, AssetNameExchange, InstrumentNameExchange>,
244 ) -> Result<OrderResponseCancel, IndexError> {
245 let OrderResponseCancel { key, state } = response;
246
247 Ok(OrderResponseCancel {
248 key: self.order_key(key)?,
249 state: match state {
250 Ok(cancelled) => Ok(cancelled),
251 Err(error) => Err(self.order_error(error)?),
252 },
253 })
254 }
255
256 pub fn order_key(&self, key: UnindexedOrderKey) -> Result<OrderKey, IndexError> {
257 let UnindexedOrderKey {
258 exchange,
259 instrument,
260 strategy,
261 cid,
262 } = key;
263
264 Ok(OrderKey {
265 exchange: self.map.find_exchange_index(exchange)?,
266 instrument: self.map.find_instrument_index(&instrument)?,
267 strategy,
268 cid,
269 })
270 }
271
272 pub fn order_state(&self, state: UnindexedOrderState) -> Result<OrderState, IndexError> {
276 Ok(match state {
277 UnindexedOrderState::Active(active) => OrderState::Active(active),
278 UnindexedOrderState::Inactive(inactive) => match inactive {
279 InactiveOrderState::OpenFailed(failed) => match failed {
280 OrderError::Rejected(rejected) => {
281 OrderState::inactive(OrderError::Rejected(self.api_error(rejected)?))
282 }
283 OrderError::Connectivity(error) => {
284 OrderState::inactive(OrderError::Connectivity(error))
285 }
286 OrderError::UnsupportedOrderType(msg) => {
287 OrderState::inactive(OrderError::UnsupportedOrderType(msg))
288 }
289 },
290 InactiveOrderState::Cancelled(cancelled) => OrderState::inactive(cancelled),
291 InactiveOrderState::FullyFilled(filled) => OrderState::fully_filled(filled),
292 InactiveOrderState::Expired(expired) => OrderState::expired(expired),
293 },
294 })
295 }
296
297 pub fn api_error(&self, error: UnindexedApiError) -> Result<ApiError, IndexError> {
298 Ok(match error {
299 UnindexedApiError::RateLimit => ApiError::RateLimit,
300 UnindexedApiError::Unauthenticated(msg) => ApiError::Unauthenticated(msg),
301 UnindexedApiError::AssetInvalid(asset, value) => {
302 ApiError::AssetInvalid(self.map.find_asset_index(&asset)?, value)
303 }
304 UnindexedApiError::InstrumentInvalid(instrument, value) => {
305 ApiError::InstrumentInvalid(self.map.find_instrument_index(&instrument)?, value)
306 }
307 UnindexedApiError::BalanceInsufficient(asset, value) => {
308 ApiError::BalanceInsufficient(self.map.find_asset_index(&asset)?, value)
309 }
310 UnindexedApiError::OrderRejected(reason) => ApiError::OrderRejected(reason),
311 UnindexedApiError::OrderAlreadyCancelled => ApiError::OrderAlreadyCancelled,
312 UnindexedApiError::OrderAlreadyFullyFilled => ApiError::OrderAlreadyFullyFilled,
313 })
314 }
315
316 pub fn order_request<Kind>(
317 &self,
318 order: &OrderEvent<Kind, ExchangeIndex, InstrumentIndex>,
319 ) -> Result<OrderEvent<Kind, ExchangeId, &InstrumentNameExchange>, KeyError>
320 where
321 Kind: Clone,
322 {
323 let OrderEvent {
324 key:
325 OrderKey {
326 exchange,
327 instrument,
328 strategy,
329 cid,
330 },
331 state,
332 } = order;
333
334 let exchange = self.map.find_exchange_id(*exchange)?;
335 let instrument = self.map.find_instrument_name_exchange(*instrument)?;
336
337 Ok(OrderEvent {
338 key: OrderKey {
339 exchange,
340 instrument,
341 strategy: strategy.clone(),
342 cid: cid.clone(),
343 },
344 state: state.clone(),
345 })
346 }
347
348 pub fn order_error(&self, error: UnindexedOrderError) -> Result<OrderError, IndexError> {
349 Ok(match error {
350 UnindexedOrderError::Connectivity(error) => OrderError::Connectivity(error),
351 UnindexedOrderError::Rejected(error) => OrderError::Rejected(self.api_error(error)?),
352 UnindexedOrderError::UnsupportedOrderType(msg) => OrderError::UnsupportedOrderType(msg),
353 })
354 }
355
356 pub fn client_error(&self, error: UnindexedClientError) -> Result<ClientError, IndexError> {
357 Ok(match error {
358 UnindexedClientError::Connectivity(error) => ClientError::Connectivity(error),
359 UnindexedClientError::Api(error) => ClientError::Api(self.api_error(error)?),
360 UnindexedClientError::TaskFailed(value) => ClientError::TaskFailed(value),
361 UnindexedClientError::Internal(value) => ClientError::Internal(value),
362 UnindexedClientError::Truncated { limit } => ClientError::Truncated { limit },
363 UnindexedClientError::TruncatedSnapshot { limit } => {
364 ClientError::TruncatedSnapshot { limit }
365 }
366 })
367 }
368
369 pub fn trade(
381 &self,
382 trade: Trade<AssetNameExchange, InstrumentNameExchange>,
383 ) -> Result<Trade<AssetIndex, InstrumentIndex>, IndexError> {
384 let Trade {
385 id,
386 order_id,
387 instrument,
388 strategy,
389 time_exchange,
390 side,
391 price: trade_price,
392 quantity,
393 fees,
394 } = trade;
395
396 let instrument_index = self.map.find_instrument_index(&instrument)?;
397 let fee_asset_index = self.map.find_asset_index(&fees.asset)?;
398
399 let fees_quote = self
401 .map
402 .instruments
403 .get_index(instrument_index.index())
404 .and_then(|instr| {
405 if fee_asset_index == instr.underlying.quote {
406 Some(fees.fees)
408 } else if fee_asset_index == instr.underlying.base {
409 Some(fees.fees * trade_price)
411 } else {
412 None
414 }
415 });
416
417 Ok(Trade {
418 id,
419 order_id,
420 instrument: instrument_index,
421 strategy,
422 time_exchange,
423 side,
424 price: trade_price,
425 quantity,
426 fees: AssetFees {
427 asset: fee_asset_index,
428 fees: fees.fees,
429 fees_quote,
430 },
431 })
432 }
433}