1use std::{cell::RefCell, rc::Rc};
19
20#[cfg(feature = "defi")]
21use nautilus_common::messages::defi::{
22 RequestPoolSnapshot, SubscribeBlocks, SubscribePool, SubscribePoolFeeCollects,
23 SubscribePoolFlashEvents, SubscribePoolLiquidityUpdates, SubscribePoolSwaps, UnsubscribeBlocks,
24 UnsubscribePool, UnsubscribePoolFeeCollects, UnsubscribePoolFlashEvents,
25 UnsubscribePoolLiquidityUpdates, UnsubscribePoolSwaps,
26};
27use nautilus_common::{
28 cache::Cache,
29 clients::DataClient,
30 messages::data::{
31 RequestBars, RequestBookSnapshot, RequestCustomData, RequestForwardPrices,
32 RequestInstrument, RequestInstruments, RequestQuotes, RequestTrades, SubscribeBars,
33 SubscribeBookDeltas, SubscribeBookDepth10, SubscribeCustomData, SubscribeIndexPrices,
34 SubscribeInstrument, SubscribeInstrumentClose, SubscribeInstrumentStatus,
35 SubscribeInstruments, SubscribeMarkPrices, SubscribeQuotes, SubscribeTrades,
36 UnsubscribeBars, UnsubscribeBookDeltas, UnsubscribeBookDepth10, UnsubscribeCustomData,
37 UnsubscribeIndexPrices, UnsubscribeInstrument, UnsubscribeInstrumentClose,
38 UnsubscribeInstrumentStatus, UnsubscribeInstruments, UnsubscribeMarkPrices,
39 UnsubscribeQuotes, UnsubscribeTrades,
40 },
41};
42use nautilus_model::identifiers::{ClientId, Venue};
43
44#[derive(Debug)]
51pub struct BacktestDataClient {
52 pub client_id: ClientId,
53 pub venue: Venue,
54 _cache: Rc<RefCell<Cache>>,
55}
56
57impl BacktestDataClient {
58 #[must_use]
60 pub const fn new(client_id: ClientId, venue: Venue, cache: Rc<RefCell<Cache>>) -> Self {
61 Self {
62 client_id,
63 venue,
64 _cache: cache,
65 }
66 }
67}
68
69#[async_trait::async_trait(?Send)]
70impl DataClient for BacktestDataClient {
71 fn client_id(&self) -> ClientId {
72 self.client_id
73 }
74
75 fn venue(&self) -> Option<Venue> {
76 Some(self.venue)
77 }
78
79 fn start(&mut self) -> anyhow::Result<()> {
80 Ok(())
81 }
82
83 fn stop(&mut self) -> anyhow::Result<()> {
84 Ok(())
85 }
86
87 fn reset(&mut self) -> anyhow::Result<()> {
88 Ok(())
89 }
90
91 fn dispose(&mut self) -> anyhow::Result<()> {
92 Ok(())
93 }
94
95 fn is_connected(&self) -> bool {
96 true
97 }
98
99 fn is_disconnected(&self) -> bool {
100 false
101 }
102
103 fn subscribe(&mut self, _cmd: SubscribeCustomData) -> anyhow::Result<()> {
104 Ok(())
105 }
106
107 fn subscribe_instruments(&mut self, _cmd: SubscribeInstruments) -> anyhow::Result<()> {
108 Ok(())
109 }
110
111 fn subscribe_instrument(&mut self, _cmd: SubscribeInstrument) -> anyhow::Result<()> {
112 Ok(())
113 }
114
115 fn subscribe_book_deltas(&mut self, _cmd: SubscribeBookDeltas) -> anyhow::Result<()> {
116 Ok(())
117 }
118
119 fn subscribe_book_depth10(&mut self, _cmd: SubscribeBookDepth10) -> anyhow::Result<()> {
120 Ok(())
121 }
122
123 fn subscribe_quotes(&mut self, _cmd: SubscribeQuotes) -> anyhow::Result<()> {
124 Ok(())
125 }
126
127 fn subscribe_trades(&mut self, _cmd: SubscribeTrades) -> anyhow::Result<()> {
128 Ok(())
129 }
130
131 fn subscribe_bars(&mut self, _cmd: SubscribeBars) -> anyhow::Result<()> {
132 Ok(())
133 }
134
135 fn subscribe_mark_prices(&mut self, _cmd: SubscribeMarkPrices) -> anyhow::Result<()> {
136 Ok(())
137 }
138
139 fn subscribe_index_prices(&mut self, _cmd: SubscribeIndexPrices) -> anyhow::Result<()> {
140 Ok(())
141 }
142
143 fn subscribe_instrument_status(
144 &mut self,
145 _cmd: SubscribeInstrumentStatus,
146 ) -> anyhow::Result<()> {
147 Ok(())
148 }
149
150 fn subscribe_instrument_close(&mut self, _cmd: SubscribeInstrumentClose) -> anyhow::Result<()> {
151 Ok(())
152 }
153
154 #[cfg(feature = "defi")]
157 fn subscribe_blocks(&mut self, _cmd: SubscribeBlocks) -> anyhow::Result<()> {
158 Ok(())
159 }
160
161 #[cfg(feature = "defi")]
162 fn subscribe_pool(&mut self, _cmd: SubscribePool) -> anyhow::Result<()> {
163 Ok(())
164 }
165
166 #[cfg(feature = "defi")]
167 fn subscribe_pool_swaps(&mut self, _cmd: SubscribePoolSwaps) -> anyhow::Result<()> {
168 Ok(())
169 }
170
171 #[cfg(feature = "defi")]
172 fn subscribe_pool_liquidity_updates(
173 &mut self,
174 _cmd: SubscribePoolLiquidityUpdates,
175 ) -> anyhow::Result<()> {
176 Ok(())
177 }
178
179 #[cfg(feature = "defi")]
180 fn subscribe_pool_fee_collects(
181 &mut self,
182 _cmd: SubscribePoolFeeCollects,
183 ) -> anyhow::Result<()> {
184 Ok(())
185 }
186
187 #[cfg(feature = "defi")]
188 fn subscribe_pool_flash_events(
189 &mut self,
190 _cmd: SubscribePoolFlashEvents,
191 ) -> anyhow::Result<()> {
192 Ok(())
193 }
194
195 fn unsubscribe(&mut self, _cmd: &UnsubscribeCustomData) -> anyhow::Result<()> {
196 Ok(())
197 }
198
199 fn unsubscribe_instruments(&mut self, _cmd: &UnsubscribeInstruments) -> anyhow::Result<()> {
200 Ok(())
201 }
202
203 fn unsubscribe_instrument(&mut self, _cmd: &UnsubscribeInstrument) -> anyhow::Result<()> {
204 Ok(())
205 }
206
207 fn unsubscribe_book_deltas(&mut self, _cmd: &UnsubscribeBookDeltas) -> anyhow::Result<()> {
208 Ok(())
209 }
210
211 fn unsubscribe_book_depth10(&mut self, _cmd: &UnsubscribeBookDepth10) -> anyhow::Result<()> {
212 Ok(())
213 }
214
215 fn unsubscribe_quotes(&mut self, _cmd: &UnsubscribeQuotes) -> anyhow::Result<()> {
216 Ok(())
217 }
218
219 fn unsubscribe_trades(&mut self, _cmd: &UnsubscribeTrades) -> anyhow::Result<()> {
220 Ok(())
221 }
222
223 fn unsubscribe_bars(&mut self, _cmd: &UnsubscribeBars) -> anyhow::Result<()> {
224 Ok(())
225 }
226
227 fn unsubscribe_mark_prices(&mut self, _cmd: &UnsubscribeMarkPrices) -> anyhow::Result<()> {
228 Ok(())
229 }
230
231 fn unsubscribe_index_prices(&mut self, _cmd: &UnsubscribeIndexPrices) -> anyhow::Result<()> {
232 Ok(())
233 }
234
235 fn unsubscribe_instrument_status(
236 &mut self,
237 _cmd: &UnsubscribeInstrumentStatus,
238 ) -> anyhow::Result<()> {
239 Ok(())
240 }
241
242 fn unsubscribe_instrument_close(
243 &mut self,
244 _cmd: &UnsubscribeInstrumentClose,
245 ) -> anyhow::Result<()> {
246 Ok(())
247 }
248
249 #[cfg(feature = "defi")]
250 fn unsubscribe_blocks(&mut self, _cmd: &UnsubscribeBlocks) -> anyhow::Result<()> {
251 Ok(())
252 }
253
254 #[cfg(feature = "defi")]
255 fn unsubscribe_pool(&mut self, _cmd: &UnsubscribePool) -> anyhow::Result<()> {
256 Ok(())
257 }
258
259 #[cfg(feature = "defi")]
260 fn unsubscribe_pool_swaps(&mut self, _cmd: &UnsubscribePoolSwaps) -> anyhow::Result<()> {
261 Ok(())
262 }
263
264 #[cfg(feature = "defi")]
265 fn unsubscribe_pool_liquidity_updates(
266 &mut self,
267 _cmd: &UnsubscribePoolLiquidityUpdates,
268 ) -> anyhow::Result<()> {
269 Ok(())
270 }
271
272 #[cfg(feature = "defi")]
273 fn unsubscribe_pool_fee_collects(
274 &mut self,
275 _cmd: &UnsubscribePoolFeeCollects,
276 ) -> anyhow::Result<()> {
277 Ok(())
278 }
279
280 #[cfg(feature = "defi")]
281 fn unsubscribe_pool_flash_events(
282 &mut self,
283 _cmd: &UnsubscribePoolFlashEvents,
284 ) -> anyhow::Result<()> {
285 Ok(())
286 }
287
288 fn request_data(&self, _request: RequestCustomData) -> anyhow::Result<()> {
289 Ok(())
291 }
292
293 fn request_instruments(&self, _request: RequestInstruments) -> anyhow::Result<()> {
294 Ok(())
296 }
297
298 fn request_instrument(&self, _request: RequestInstrument) -> anyhow::Result<()> {
299 Ok(())
301 }
302
303 fn request_book_snapshot(&self, _request: RequestBookSnapshot) -> anyhow::Result<()> {
304 Ok(())
306 }
307
308 fn request_quotes(&self, _request: RequestQuotes) -> anyhow::Result<()> {
309 Ok(())
311 }
312
313 fn request_trades(&self, _request: RequestTrades) -> anyhow::Result<()> {
314 Ok(())
316 }
317
318 fn request_bars(&self, _request: RequestBars) -> anyhow::Result<()> {
319 Ok(())
321 }
322
323 fn request_forward_prices(&self, _request: RequestForwardPrices) -> anyhow::Result<()> {
324 anyhow::bail!("backtest data client cannot fetch forward prices")
327 }
328
329 #[cfg(feature = "defi")]
330 fn request_pool_snapshot(&self, _request: RequestPoolSnapshot) -> anyhow::Result<()> {
331 Ok(())
332 }
333}
334
335#[cfg(test)]
336mod tests {
337 use nautilus_core::{UUID4, UnixNanos};
338 use rstest::rstest;
339 use ustr::Ustr;
340
341 use super::*;
342
343 #[rstest]
344 fn test_request_forward_prices_returns_err_for_engine_fallback() {
345 let client_id = ClientId::new("BACKTEST");
346 let venue = Venue::new("BACKTEST");
347 let cache = Rc::new(RefCell::new(Cache::default()));
348 let client = BacktestDataClient::new(client_id, venue, cache);
349
350 let request = RequestForwardPrices::new(
351 venue,
352 Ustr::from("BTC"),
353 None,
354 Some(client_id),
355 UUID4::new(),
356 UnixNanos::default(),
357 None,
358 );
359
360 let result = client.request_forward_prices(request);
361 assert!(result.is_err());
362 let msg = result.unwrap_err().to_string();
363 assert!(msg.contains("backtest data client"));
364 }
365}