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 cancel_order(
116        time_request: DateTime<Utc>,
117        response_tx: oneshot::Sender<UnindexedOrderResponseCancel>,
118        request: OrderRequestCancel<ExchangeId, InstrumentNameExchange>,
119    ) -> Self {
120        Self::new(
121            time_request,
122            MockExchangeRequestKind::CancelOrder {
123                response_tx,
124                request,
125            },
126        )
127    }
128
129    pub fn open_order(
130        time_request: DateTime<Utc>,
131        response_tx: oneshot::Sender<
132            Order<ExchangeId, InstrumentNameExchange, UnindexedOrderState>,
133        >,
134        request: OrderRequestOpen<ExchangeId, InstrumentNameExchange>,
135    ) -> Self {
136        Self::new(
137            time_request,
138            MockExchangeRequestKind::OpenOrder {
139                response_tx,
140                request,
141            },
142        )
143    }
144}
145
146/// What a [`MockExchangeRequest`] asks the venue for.
147///
148/// Non-exhaustive: requests are built through [`MockExchangeRequest`]'s constructors and matched only
149/// by the venue's own driver, so a new request kind is not a breaking change.
150#[derive(Debug)]
151#[non_exhaustive]
152pub enum MockExchangeRequestKind {
153    FetchAccountSnapshot {
154        response_tx: oneshot::Sender<UnindexedAccountSnapshot>,
155    },
156    FetchBalances {
157        assets: Vec<AssetNameExchange>,
158        response_tx: oneshot::Sender<Vec<AssetBalance<AssetNameExchange>>>,
159    },
160    FetchOrdersOpen {
161        instruments: Vec<InstrumentNameExchange>,
162        response_tx: oneshot::Sender<Vec<Order<ExchangeId, InstrumentNameExchange, Open>>>,
163    },
164    FetchOrdersEnded {
165        orders: Vec<UnindexedOrderKey>,
166        response_tx: oneshot::Sender<Vec<UnindexedInactiveOrder>>,
167    },
168    /// How much more the account can borrow for an order on `instrument` on `side`.
169    FetchBorrowCapacity {
170        instrument: InstrumentNameExchange,
171        side: Side,
172        response_tx: oneshot::Sender<Result<BorrowCapacity, UnindexedApiError>>,
173    },
174    /// Every trade from `start` to `end`, both inclusive.
175    FetchTrades {
176        response_tx: oneshot::Sender<Vec<Trade<AssetNameExchange, InstrumentNameExchange>>>,
177        start: DateTime<Utc>,
178        end: DateTime<Utc>,
179    },
180    CancelOrder {
181        response_tx: oneshot::Sender<UnindexedOrderResponseCancel>,
182        request: OrderRequestCancel<ExchangeId, InstrumentNameExchange>,
183    },
184    OpenOrder {
185        response_tx:
186            oneshot::Sender<Order<ExchangeId, InstrumentNameExchange, UnindexedOrderState>>,
187        /// The order to open, carrying on
188        /// [`RequestOpen::market`](crate::order::request::RequestOpen::market) the market its
189        /// sender observed when it decided to open it.
190        ///
191        /// That snapshot is the venue's only price source for a Market order, which carries no
192        /// limit price of its own. It is not repeated as a field of its own here: two copies of
193        /// the same snapshot on one message could disagree, and nothing could arbitrate.
194        request: OrderRequestOpen<ExchangeId, InstrumentNameExchange>,
195    },
196}