Skip to main content

rustrade_execution/exchange/mock/
request.rs

1use crate::{
2    UnindexedAccountSnapshot,
3    balance::AssetBalance,
4    order::{
5        Order, UnindexedInactiveOrder, UnindexedOrderKey,
6        request::{OrderRequestCancel, OrderRequestOpen, UnindexedOrderResponseCancel},
7        state::{Open, UnindexedOrderState},
8    },
9    trade::Trade,
10};
11use chrono::{DateTime, Utc};
12use rustrade_instrument::{
13    asset::name::AssetNameExchange, exchange::ExchangeId, instrument::name::InstrumentNameExchange,
14};
15use tokio::sync::oneshot;
16
17#[derive(Debug)]
18pub struct MockExchangeRequest {
19    pub time_request: DateTime<Utc>,
20    pub kind: MockExchangeRequestKind,
21}
22
23impl MockExchangeRequest {
24    pub fn new(time_request: DateTime<Utc>, kind: MockExchangeRequestKind) -> Self {
25        Self { time_request, kind }
26    }
27
28    pub fn fetch_account_snapshot(
29        time_request: DateTime<Utc>,
30        response_tx: oneshot::Sender<UnindexedAccountSnapshot>,
31    ) -> Self {
32        Self::new(
33            time_request,
34            MockExchangeRequestKind::FetchAccountSnapshot { response_tx },
35        )
36    }
37
38    pub fn fetch_balances(
39        time_request: DateTime<Utc>,
40        assets: Vec<AssetNameExchange>,
41        response_tx: oneshot::Sender<Vec<AssetBalance<AssetNameExchange>>>,
42    ) -> Self {
43        Self::new(
44            time_request,
45            MockExchangeRequestKind::FetchBalances {
46                response_tx,
47                assets,
48            },
49        )
50    }
51
52    pub fn fetch_orders_open(
53        time_request: DateTime<Utc>,
54        instruments: Vec<InstrumentNameExchange>,
55        response_tx: oneshot::Sender<Vec<Order<ExchangeId, InstrumentNameExchange, Open>>>,
56    ) -> Self {
57        Self::new(
58            time_request,
59            MockExchangeRequestKind::FetchOrdersOpen {
60                response_tx,
61                instruments,
62            },
63        )
64    }
65
66    pub fn fetch_orders_ended(
67        time_request: DateTime<Utc>,
68        orders: Vec<UnindexedOrderKey>,
69        response_tx: oneshot::Sender<Vec<UnindexedInactiveOrder>>,
70    ) -> Self {
71        Self::new(
72            time_request,
73            MockExchangeRequestKind::FetchOrdersEnded {
74                orders,
75                response_tx,
76            },
77        )
78    }
79
80    pub fn fetch_trades(
81        time_request: DateTime<Utc>,
82        response_tx: oneshot::Sender<Vec<Trade<AssetNameExchange, InstrumentNameExchange>>>,
83        start: DateTime<Utc>,
84        end: DateTime<Utc>,
85    ) -> Self {
86        Self::new(
87            time_request,
88            MockExchangeRequestKind::FetchTrades {
89                response_tx,
90                start,
91                end,
92            },
93        )
94    }
95
96    pub fn cancel_order(
97        time_request: DateTime<Utc>,
98        response_tx: oneshot::Sender<UnindexedOrderResponseCancel>,
99        request: OrderRequestCancel<ExchangeId, InstrumentNameExchange>,
100    ) -> Self {
101        Self::new(
102            time_request,
103            MockExchangeRequestKind::CancelOrder {
104                response_tx,
105                request,
106            },
107        )
108    }
109
110    pub fn open_order(
111        time_request: DateTime<Utc>,
112        response_tx: oneshot::Sender<
113            Order<ExchangeId, InstrumentNameExchange, UnindexedOrderState>,
114        >,
115        request: OrderRequestOpen<ExchangeId, InstrumentNameExchange>,
116    ) -> Self {
117        Self::new(
118            time_request,
119            MockExchangeRequestKind::OpenOrder {
120                response_tx,
121                request,
122            },
123        )
124    }
125}
126
127/// What a [`MockExchangeRequest`] asks the venue for.
128///
129/// Non-exhaustive: requests are built through [`MockExchangeRequest`]'s constructors and matched only
130/// by the venue's own driver, so a new request kind is not a breaking change.
131#[derive(Debug)]
132#[non_exhaustive]
133pub enum MockExchangeRequestKind {
134    FetchAccountSnapshot {
135        response_tx: oneshot::Sender<UnindexedAccountSnapshot>,
136    },
137    FetchBalances {
138        assets: Vec<AssetNameExchange>,
139        response_tx: oneshot::Sender<Vec<AssetBalance<AssetNameExchange>>>,
140    },
141    FetchOrdersOpen {
142        instruments: Vec<InstrumentNameExchange>,
143        response_tx: oneshot::Sender<Vec<Order<ExchangeId, InstrumentNameExchange, Open>>>,
144    },
145    FetchOrdersEnded {
146        orders: Vec<UnindexedOrderKey>,
147        response_tx: oneshot::Sender<Vec<UnindexedInactiveOrder>>,
148    },
149    /// Every trade from `start` to `end`, both inclusive.
150    FetchTrades {
151        response_tx: oneshot::Sender<Vec<Trade<AssetNameExchange, InstrumentNameExchange>>>,
152        start: DateTime<Utc>,
153        end: DateTime<Utc>,
154    },
155    CancelOrder {
156        response_tx: oneshot::Sender<UnindexedOrderResponseCancel>,
157        request: OrderRequestCancel<ExchangeId, InstrumentNameExchange>,
158    },
159    OpenOrder {
160        response_tx:
161            oneshot::Sender<Order<ExchangeId, InstrumentNameExchange, UnindexedOrderState>>,
162        /// The order to open, carrying on
163        /// [`RequestOpen::market`](crate::order::request::RequestOpen::market) the market its
164        /// sender observed when it decided to open it.
165        ///
166        /// That snapshot is the venue's only price source for a Market order, which carries no
167        /// limit price of its own. It is not repeated as a field of its own here: two copies of
168        /// the same snapshot on one message could disagree, and nothing could arbitrate.
169        request: OrderRequestOpen<ExchangeId, InstrumentNameExchange>,
170    },
171}