Skip to main content

nautilus_common/messages/data/
response.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use std::{any::Any, sync::Arc};
17
18use nautilus_core::{Params, UUID4, UnixNanos};
19use nautilus_model::{
20    data::{
21        Bar, BarType, DataType, FundingRateUpdate, HasTsInit, OrderBookDelta, OrderBookDepth,
22        QuoteTick, TradeTick,
23    },
24    identifiers::{ClientId, InstrumentId, OptionSeriesId, Venue},
25    instruments::InstrumentAny,
26    orderbook::OrderBook,
27    types::Price,
28};
29use serde::{Deserialize, Serialize};
30
31use super::Payload;
32
33/// Trims `data` to the inclusive `[start, end]` window on `ts_init`.
34///
35/// When `start` is set, drops leading entries with `ts_init < start`; when `end`
36/// is set, drops trailing entries with `ts_init > end`. Empty payloads and
37/// absent bounds short-circuit. When the bounds do not overlap the payload
38/// (e.g. `start` after the last entry, or `end` before the first), `data` is
39/// cleared.
40pub(crate) fn trim_data_to_bounds<T: HasTsInit>(
41    data: &mut Vec<T>,
42    start: Option<UnixNanos>,
43    end: Option<UnixNanos>,
44) {
45    let data_len = data.len();
46    if data_len == 0 {
47        return;
48    }
49
50    let first_index = if let Some(start) = start {
51        let Some(i) = data
52            .iter()
53            .position(|item| item.ts_init().as_u64() >= start.as_u64())
54        else {
55            data.clear();
56            return;
57        };
58        i
59    } else {
60        0
61    };
62
63    let last_index = if let Some(end) = end {
64        let Some(i) = data
65            .iter()
66            .rposition(|item| item.ts_init().as_u64() <= end.as_u64())
67        else {
68            data.clear();
69            return;
70        };
71        i
72    } else {
73        data_len - 1
74    };
75
76    if first_index <= last_index {
77        data.drain(..first_index);
78        data.truncate(last_index - first_index + 1);
79    } else {
80        data.clear();
81    }
82}
83
84#[derive(Clone, Debug)]
85pub struct CustomDataResponse {
86    pub correlation_id: UUID4,
87    pub client_id: ClientId,
88    pub venue: Option<Venue>,
89    pub data_type: DataType,
90    pub data: Payload,
91    pub start: Option<UnixNanos>,
92    pub end: Option<UnixNanos>,
93    pub ts_init: UnixNanos,
94    pub params: Option<Params>,
95}
96
97impl CustomDataResponse {
98    /// Creates a new [`CustomDataResponse`] instance.
99    #[expect(clippy::too_many_arguments)]
100    pub fn new<T: Any + Send + Sync>(
101        correlation_id: UUID4,
102        client_id: ClientId,
103        venue: Option<Venue>,
104        data_type: DataType,
105        data: T,
106        start: Option<UnixNanos>,
107        end: Option<UnixNanos>,
108        ts_init: UnixNanos,
109        params: Option<Params>,
110    ) -> Self {
111        Self {
112            correlation_id,
113            client_id,
114            venue,
115            data_type,
116            data: Arc::new(data),
117            start,
118            end,
119            ts_init,
120            params,
121        }
122    }
123
124    /// Converts the response to a dyn Any trait object for messaging.
125    pub fn as_any(&self) -> &dyn Any {
126        self
127    }
128}
129
130#[derive(Clone, Debug, Serialize, Deserialize)]
131pub struct InstrumentResponse {
132    pub correlation_id: UUID4,
133    pub client_id: ClientId,
134    pub instrument_id: InstrumentId,
135    pub data: InstrumentAny,
136    pub start: Option<UnixNanos>,
137    pub end: Option<UnixNanos>,
138    pub ts_init: UnixNanos,
139    pub params: Option<Params>,
140}
141
142impl InstrumentResponse {
143    /// Converts to a dyn Any trait object for messaging.
144    pub fn as_any(&self) -> &dyn Any {
145        self
146    }
147
148    /// Creates a new [`InstrumentResponse`] instance.
149    #[expect(clippy::too_many_arguments)]
150    pub fn new(
151        correlation_id: UUID4,
152        client_id: ClientId,
153        instrument_id: InstrumentId,
154        data: InstrumentAny,
155        start: Option<UnixNanos>,
156        end: Option<UnixNanos>,
157        ts_init: UnixNanos,
158        params: Option<Params>,
159    ) -> Self {
160        Self {
161            correlation_id,
162            client_id,
163            instrument_id,
164            data,
165            start,
166            end,
167            ts_init,
168            params,
169        }
170    }
171}
172
173#[derive(Clone, Debug, Serialize, Deserialize)]
174pub struct InstrumentsResponse {
175    pub correlation_id: UUID4,
176    pub client_id: ClientId,
177    pub venue: Venue,
178    pub data: Vec<InstrumentAny>,
179    pub start: Option<UnixNanos>,
180    pub end: Option<UnixNanos>,
181    pub ts_init: UnixNanos,
182    pub params: Option<Params>,
183}
184
185impl InstrumentsResponse {
186    /// Converts to a dyn Any trait object for messaging.
187    pub fn as_any(&self) -> &dyn Any {
188        self
189    }
190
191    /// Creates a new [`InstrumentsResponse`] instance.
192    #[expect(clippy::too_many_arguments)]
193    pub fn new(
194        correlation_id: UUID4,
195        client_id: ClientId,
196        venue: Venue,
197        data: Vec<InstrumentAny>,
198        start: Option<UnixNanos>,
199        end: Option<UnixNanos>,
200        ts_init: UnixNanos,
201        params: Option<Params>,
202    ) -> Self {
203        Self {
204            correlation_id,
205            client_id,
206            venue,
207            data,
208            start,
209            end,
210            ts_init,
211            params,
212        }
213    }
214}
215
216#[derive(Clone, Debug)]
217pub struct BookResponse {
218    pub correlation_id: UUID4,
219    pub client_id: ClientId,
220    pub instrument_id: InstrumentId,
221    pub data: OrderBook,
222    pub start: Option<UnixNanos>,
223    pub end: Option<UnixNanos>,
224    pub ts_init: UnixNanos,
225    pub params: Option<Params>,
226}
227
228impl BookResponse {
229    /// Converts to a dyn Any trait object for messaging.
230    pub fn as_any(&self) -> &dyn Any {
231        self
232    }
233
234    /// Creates a new [`BookResponse`] instance.
235    #[expect(clippy::too_many_arguments)]
236    pub fn new(
237        correlation_id: UUID4,
238        client_id: ClientId,
239        instrument_id: InstrumentId,
240        data: OrderBook,
241        start: Option<UnixNanos>,
242        end: Option<UnixNanos>,
243        ts_init: UnixNanos,
244        params: Option<Params>,
245    ) -> Self {
246        Self {
247            correlation_id,
248            client_id,
249            instrument_id,
250            data,
251            start,
252            end,
253            ts_init,
254            params,
255        }
256    }
257}
258
259#[derive(Clone, Debug, Serialize, Deserialize)]
260pub struct BookDeltasResponse {
261    pub correlation_id: UUID4,
262    pub client_id: ClientId,
263    pub instrument_id: InstrumentId,
264    pub data: Vec<OrderBookDelta>,
265    pub start: Option<UnixNanos>,
266    pub end: Option<UnixNanos>,
267    pub ts_init: UnixNanos,
268    pub params: Option<Params>,
269}
270
271impl BookDeltasResponse {
272    /// Converts to a dyn Any trait object for messaging.
273    pub fn as_any(&self) -> &dyn Any {
274        self
275    }
276
277    /// Creates a new [`BookDeltasResponse`] instance.
278    #[expect(clippy::too_many_arguments)]
279    pub fn new(
280        correlation_id: UUID4,
281        client_id: ClientId,
282        instrument_id: InstrumentId,
283        data: Vec<OrderBookDelta>,
284        start: Option<UnixNanos>,
285        end: Option<UnixNanos>,
286        ts_init: UnixNanos,
287        params: Option<Params>,
288    ) -> Self {
289        Self {
290            correlation_id,
291            client_id,
292            instrument_id,
293            data,
294            start,
295            end,
296            ts_init,
297            params,
298        }
299    }
300}
301
302#[derive(Clone, Debug, Serialize, Deserialize)]
303pub struct BookDepthResponse {
304    pub correlation_id: UUID4,
305    pub client_id: ClientId,
306    pub instrument_id: InstrumentId,
307    pub data: Vec<OrderBookDepth>,
308    pub start: Option<UnixNanos>,
309    pub end: Option<UnixNanos>,
310    pub ts_init: UnixNanos,
311    pub params: Option<Params>,
312}
313
314impl BookDepthResponse {
315    /// Converts to a dyn Any trait object for messaging.
316    pub fn as_any(&self) -> &dyn Any {
317        self
318    }
319
320    /// Creates a new [`BookDepthResponse`] instance.
321    #[expect(clippy::too_many_arguments)]
322    pub fn new(
323        correlation_id: UUID4,
324        client_id: ClientId,
325        instrument_id: InstrumentId,
326        data: Vec<OrderBookDepth>,
327        start: Option<UnixNanos>,
328        end: Option<UnixNanos>,
329        ts_init: UnixNanos,
330        params: Option<Params>,
331    ) -> Self {
332        Self {
333            correlation_id,
334            client_id,
335            instrument_id,
336            data,
337            start,
338            end,
339            ts_init,
340            params,
341        }
342    }
343}
344
345#[derive(Clone, Debug, Serialize, Deserialize)]
346pub struct QuotesResponse {
347    pub correlation_id: UUID4,
348    pub client_id: ClientId,
349    pub instrument_id: InstrumentId,
350    pub data: Vec<QuoteTick>,
351    pub start: Option<UnixNanos>,
352    pub end: Option<UnixNanos>,
353    pub ts_init: UnixNanos,
354    pub params: Option<Params>,
355}
356
357impl QuotesResponse {
358    /// Converts to a dyn Any trait object for messaging.
359    pub fn as_any(&self) -> &dyn Any {
360        self
361    }
362
363    /// Creates a new [`QuotesResponse`] instance.
364    #[expect(clippy::too_many_arguments)]
365    pub fn new(
366        correlation_id: UUID4,
367        client_id: ClientId,
368        instrument_id: InstrumentId,
369        data: Vec<QuoteTick>,
370        start: Option<UnixNanos>,
371        end: Option<UnixNanos>,
372        ts_init: UnixNanos,
373        params: Option<Params>,
374    ) -> Self {
375        Self {
376            correlation_id,
377            client_id,
378            instrument_id,
379            data,
380            start,
381            end,
382            ts_init,
383            params,
384        }
385    }
386}
387
388#[derive(Clone, Debug, Serialize, Deserialize)]
389pub struct TradesResponse {
390    pub correlation_id: UUID4,
391    pub client_id: ClientId,
392    pub instrument_id: InstrumentId,
393    pub data: Vec<TradeTick>,
394    pub start: Option<UnixNanos>,
395    pub end: Option<UnixNanos>,
396    pub ts_init: UnixNanos,
397    pub params: Option<Params>,
398}
399
400impl TradesResponse {
401    /// Converts to a dyn Any trait object for messaging.
402    pub fn as_any(&self) -> &dyn Any {
403        self
404    }
405
406    /// Creates a new [`TradesResponse`] instance.
407    #[expect(clippy::too_many_arguments)]
408    pub fn new(
409        correlation_id: UUID4,
410        client_id: ClientId,
411        instrument_id: InstrumentId,
412        data: Vec<TradeTick>,
413        start: Option<UnixNanos>,
414        end: Option<UnixNanos>,
415        ts_init: UnixNanos,
416        params: Option<Params>,
417    ) -> Self {
418        Self {
419            correlation_id,
420            client_id,
421            instrument_id,
422            data,
423            start,
424            end,
425            ts_init,
426            params,
427        }
428    }
429}
430
431#[derive(Clone, Debug, Serialize, Deserialize)]
432pub struct FundingRatesResponse {
433    pub correlation_id: UUID4,
434    pub client_id: ClientId,
435    pub instrument_id: InstrumentId,
436    pub data: Vec<FundingRateUpdate>,
437    pub start: Option<UnixNanos>,
438    pub end: Option<UnixNanos>,
439    pub ts_init: UnixNanos,
440    pub params: Option<Params>,
441}
442
443impl FundingRatesResponse {
444    /// Converts to a dyn Any trait object for messaging.
445    pub fn as_any(&self) -> &dyn Any {
446        self
447    }
448
449    /// Creates a new [`FundingRatesResponse`] instance.
450    #[expect(clippy::too_many_arguments)]
451    pub fn new(
452        correlation_id: UUID4,
453        client_id: ClientId,
454        instrument_id: InstrumentId,
455        data: Vec<FundingRateUpdate>,
456        start: Option<UnixNanos>,
457        end: Option<UnixNanos>,
458        ts_init: UnixNanos,
459        params: Option<Params>,
460    ) -> Self {
461        Self {
462            correlation_id,
463            client_id,
464            instrument_id,
465            data,
466            start,
467            end,
468            ts_init,
469            params,
470        }
471    }
472}
473
474#[derive(Clone, Debug, Serialize, Deserialize)]
475pub struct OptionChainReferencePriceResponse {
476    pub correlation_id: UUID4,
477    pub client_id: ClientId,
478    pub series_id: OptionSeriesId,
479    pub price: Option<Price>,
480    pub ts_init: UnixNanos,
481    pub params: Option<Params>,
482}
483
484impl OptionChainReferencePriceResponse {
485    /// Creates a new [`OptionChainReferencePriceResponse`] instance.
486    pub fn new(
487        correlation_id: UUID4,
488        client_id: ClientId,
489        series_id: OptionSeriesId,
490        price: Option<Price>,
491        ts_init: UnixNanos,
492        params: Option<Params>,
493    ) -> Self {
494        Self {
495            correlation_id,
496            client_id,
497            series_id,
498            price,
499            ts_init,
500            params,
501        }
502    }
503}
504
505#[derive(Clone, Debug, Serialize, Deserialize)]
506pub struct BarsResponse {
507    pub correlation_id: UUID4,
508    pub client_id: ClientId,
509    pub bar_type: BarType,
510    pub data: Vec<Bar>,
511    pub ts_init: UnixNanos,
512    pub start: Option<UnixNanos>,
513    pub end: Option<UnixNanos>,
514    pub params: Option<Params>,
515}
516
517impl BarsResponse {
518    /// Converts to a dyn Any trait object for messaging.
519    pub fn as_any(&self) -> &dyn Any {
520        self
521    }
522
523    /// Creates a new [`BarsResponse`] instance.
524    #[expect(clippy::too_many_arguments)]
525    pub fn new(
526        correlation_id: UUID4,
527        client_id: ClientId,
528        bar_type: BarType,
529        data: Vec<Bar>,
530        start: Option<UnixNanos>,
531        end: Option<UnixNanos>,
532        ts_init: UnixNanos,
533        params: Option<Params>,
534    ) -> Self {
535        Self {
536            correlation_id,
537            client_id,
538            bar_type,
539            data,
540            ts_init,
541            start,
542            end,
543            params,
544        }
545    }
546}