Skip to main content

rustrade_execution/exchange/mock/
request.rs

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