1use std::{any::Any, sync::Arc};
19
20use nautilus_core::{Params, UUID4, UnixNanos};
21use nautilus_model::{
22 data::BarType,
23 identifiers::{ClientId, Venue},
24};
25
26pub mod request;
27pub mod response;
28pub mod subscribe;
29pub mod unsubscribe;
30
31pub use request::{
33 RequestBars, RequestBookDepth, RequestBookSnapshot, RequestCustomData, RequestForwardPrices,
34 RequestFundingRates, RequestInstrument, RequestInstruments, RequestQuotes, RequestTrades,
35};
36pub use response::{
37 BarsResponse, BookResponse, CustomDataResponse, ForwardPricesResponse, FundingRatesResponse,
38 InstrumentResponse, InstrumentsResponse, QuotesResponse, TradesResponse,
39};
40pub use subscribe::{
41 SubscribeBars, SubscribeBookDeltas, SubscribeBookDepth10, SubscribeBookSnapshots,
42 SubscribeCustomData, SubscribeFundingRates, SubscribeIndexPrices, SubscribeInstrument,
43 SubscribeInstrumentClose, SubscribeInstrumentStatus, SubscribeInstruments, SubscribeMarkPrices,
44 SubscribeOptionChain, SubscribeOptionGreeks, SubscribeQuotes, SubscribeTrades,
45};
46pub use unsubscribe::{
47 UnsubscribeBars, UnsubscribeBookDeltas, UnsubscribeBookDepth10, UnsubscribeBookSnapshots,
48 UnsubscribeCustomData, UnsubscribeFundingRates, UnsubscribeIndexPrices, UnsubscribeInstrument,
49 UnsubscribeInstrumentClose, UnsubscribeInstrumentStatus, UnsubscribeInstruments,
50 UnsubscribeMarkPrices, UnsubscribeOptionChain, UnsubscribeOptionGreeks, UnsubscribeQuotes,
51 UnsubscribeTrades,
52};
53
54#[cfg(feature = "defi")]
55use crate::messages::defi::{DefiRequestCommand, DefiSubscribeCommand, DefiUnsubscribeCommand};
56
57#[non_exhaustive]
58#[derive(Clone, Debug, PartialEq)]
59pub enum DataCommand {
60 Request(RequestCommand),
61 Subscribe(SubscribeCommand),
62 Unsubscribe(UnsubscribeCommand),
63 #[cfg(feature = "defi")]
64 DefiRequest(DefiRequestCommand),
65 #[cfg(feature = "defi")]
66 DefiSubscribe(DefiSubscribeCommand),
67 #[cfg(feature = "defi")]
68 DefiUnsubscribe(DefiUnsubscribeCommand),
69}
70
71impl DataCommand {
72 pub fn as_any(&self) -> &dyn Any {
74 self
75 }
76}
77
78#[derive(Clone, Debug)]
79pub enum SubscribeCommand {
80 Data(SubscribeCustomData),
81 Instrument(SubscribeInstrument),
82 Instruments(SubscribeInstruments),
83 BookDeltas(SubscribeBookDeltas),
84 BookDepth10(SubscribeBookDepth10),
85 BookSnapshots(SubscribeBookSnapshots),
86 Quotes(SubscribeQuotes),
87 Trades(SubscribeTrades),
88 Bars(SubscribeBars),
89 MarkPrices(SubscribeMarkPrices),
90 IndexPrices(SubscribeIndexPrices),
91 FundingRates(SubscribeFundingRates),
92 InstrumentStatus(SubscribeInstrumentStatus),
93 InstrumentClose(SubscribeInstrumentClose),
94 OptionGreeks(SubscribeOptionGreeks),
95 OptionChain(SubscribeOptionChain),
96}
97
98impl PartialEq for SubscribeCommand {
99 fn eq(&self, other: &Self) -> bool {
100 self.command_id() == other.command_id()
101 }
102}
103
104impl SubscribeCommand {
105 pub fn as_any(&self) -> &dyn Any {
107 self
108 }
109
110 pub fn command_id(&self) -> UUID4 {
111 match self {
112 Self::Data(cmd) => cmd.command_id,
113 Self::Instrument(cmd) => cmd.command_id,
114 Self::Instruments(cmd) => cmd.command_id,
115 Self::BookDeltas(cmd) => cmd.command_id,
116 Self::BookDepth10(cmd) => cmd.command_id,
117 Self::BookSnapshots(cmd) => cmd.command_id,
118 Self::Quotes(cmd) => cmd.command_id,
119 Self::Trades(cmd) => cmd.command_id,
120 Self::Bars(cmd) => cmd.command_id,
121 Self::MarkPrices(cmd) => cmd.command_id,
122 Self::IndexPrices(cmd) => cmd.command_id,
123 Self::FundingRates(cmd) => cmd.command_id,
124 Self::InstrumentStatus(cmd) => cmd.command_id,
125 Self::InstrumentClose(cmd) => cmd.command_id,
126 Self::OptionGreeks(cmd) => cmd.command_id,
127 Self::OptionChain(cmd) => cmd.command_id,
128 }
129 }
130
131 pub fn client_id(&self) -> Option<&ClientId> {
132 match self {
133 Self::Data(cmd) => cmd.client_id.as_ref(),
134 Self::Instrument(cmd) => cmd.client_id.as_ref(),
135 Self::Instruments(cmd) => cmd.client_id.as_ref(),
136 Self::BookDeltas(cmd) => cmd.client_id.as_ref(),
137 Self::BookDepth10(cmd) => cmd.client_id.as_ref(),
138 Self::BookSnapshots(cmd) => cmd.client_id.as_ref(),
139 Self::Quotes(cmd) => cmd.client_id.as_ref(),
140 Self::Trades(cmd) => cmd.client_id.as_ref(),
141 Self::MarkPrices(cmd) => cmd.client_id.as_ref(),
142 Self::IndexPrices(cmd) => cmd.client_id.as_ref(),
143 Self::FundingRates(cmd) => cmd.client_id.as_ref(),
144 Self::Bars(cmd) => cmd.client_id.as_ref(),
145 Self::InstrumentStatus(cmd) => cmd.client_id.as_ref(),
146 Self::InstrumentClose(cmd) => cmd.client_id.as_ref(),
147 Self::OptionGreeks(cmd) => cmd.client_id.as_ref(),
148 Self::OptionChain(cmd) => cmd.client_id.as_ref(),
149 }
150 }
151
152 pub fn venue(&self) -> Option<&Venue> {
153 match self {
154 Self::Data(cmd) => cmd.venue.as_ref(),
155 Self::Instrument(cmd) => cmd.venue.as_ref(),
156 Self::Instruments(cmd) => Some(&cmd.venue),
157 Self::BookDeltas(cmd) => cmd.venue.as_ref(),
158 Self::BookDepth10(cmd) => cmd.venue.as_ref(),
159 Self::BookSnapshots(cmd) => cmd.venue.as_ref(),
160 Self::Quotes(cmd) => cmd.venue.as_ref(),
161 Self::Trades(cmd) => cmd.venue.as_ref(),
162 Self::MarkPrices(cmd) => cmd.venue.as_ref(),
163 Self::IndexPrices(cmd) => cmd.venue.as_ref(),
164 Self::FundingRates(cmd) => cmd.venue.as_ref(),
165 Self::Bars(cmd) => cmd.venue.as_ref(),
166 Self::InstrumentStatus(cmd) => cmd.venue.as_ref(),
167 Self::InstrumentClose(cmd) => cmd.venue.as_ref(),
168 Self::OptionGreeks(cmd) => cmd.venue.as_ref(),
169 Self::OptionChain(cmd) => cmd.venue.as_ref(),
170 }
171 }
172
173 pub fn ts_init(&self) -> UnixNanos {
174 match self {
175 Self::Data(cmd) => cmd.ts_init,
176 Self::Instrument(cmd) => cmd.ts_init,
177 Self::Instruments(cmd) => cmd.ts_init,
178 Self::BookDeltas(cmd) => cmd.ts_init,
179 Self::BookDepth10(cmd) => cmd.ts_init,
180 Self::BookSnapshots(cmd) => cmd.ts_init,
181 Self::Quotes(cmd) => cmd.ts_init,
182 Self::Trades(cmd) => cmd.ts_init,
183 Self::MarkPrices(cmd) => cmd.ts_init,
184 Self::IndexPrices(cmd) => cmd.ts_init,
185 Self::FundingRates(cmd) => cmd.ts_init,
186 Self::Bars(cmd) => cmd.ts_init,
187 Self::InstrumentStatus(cmd) => cmd.ts_init,
188 Self::InstrumentClose(cmd) => cmd.ts_init,
189 Self::OptionGreeks(cmd) => cmd.ts_init,
190 Self::OptionChain(cmd) => cmd.ts_init,
191 }
192 }
193
194 pub fn correlation_id(&self) -> Option<UUID4> {
195 match self {
196 Self::Data(cmd) => cmd.correlation_id,
197 Self::Instrument(cmd) => cmd.correlation_id,
198 Self::Instruments(cmd) => cmd.correlation_id,
199 Self::BookDeltas(cmd) => cmd.correlation_id,
200 Self::BookDepth10(cmd) => cmd.correlation_id,
201 Self::BookSnapshots(cmd) => cmd.correlation_id,
202 Self::Quotes(cmd) => cmd.correlation_id,
203 Self::Trades(cmd) => cmd.correlation_id,
204 Self::MarkPrices(cmd) => cmd.correlation_id,
205 Self::IndexPrices(cmd) => cmd.correlation_id,
206 Self::FundingRates(cmd) => cmd.correlation_id,
207 Self::Bars(cmd) => cmd.correlation_id,
208 Self::InstrumentStatus(cmd) => cmd.correlation_id,
209 Self::InstrumentClose(cmd) => cmd.correlation_id,
210 Self::OptionGreeks(cmd) => cmd.correlation_id,
211 Self::OptionChain(_) => None,
212 }
213 }
214
215 pub fn params(&self) -> Option<&Params> {
216 match self {
217 Self::Data(cmd) => cmd.params.as_ref(),
218 Self::Instrument(cmd) => cmd.params.as_ref(),
219 Self::Instruments(cmd) => cmd.params.as_ref(),
220 Self::BookDeltas(cmd) => cmd.params.as_ref(),
221 Self::BookDepth10(cmd) => cmd.params.as_ref(),
222 Self::BookSnapshots(cmd) => cmd.params.as_ref(),
223 Self::Quotes(cmd) => cmd.params.as_ref(),
224 Self::Trades(cmd) => cmd.params.as_ref(),
225 Self::Bars(cmd) => cmd.params.as_ref(),
226 Self::MarkPrices(cmd) => cmd.params.as_ref(),
227 Self::IndexPrices(cmd) => cmd.params.as_ref(),
228 Self::FundingRates(cmd) => cmd.params.as_ref(),
229 Self::InstrumentStatus(cmd) => cmd.params.as_ref(),
230 Self::InstrumentClose(cmd) => cmd.params.as_ref(),
231 Self::OptionGreeks(cmd) => cmd.params.as_ref(),
232 Self::OptionChain(cmd) => cmd.params.as_ref(),
233 }
234 }
235}
236
237#[derive(Clone, Debug)]
238pub enum UnsubscribeCommand {
239 Data(UnsubscribeCustomData),
240 Instrument(UnsubscribeInstrument),
241 Instruments(UnsubscribeInstruments),
242 BookDeltas(UnsubscribeBookDeltas),
243 BookDepth10(UnsubscribeBookDepth10),
244 BookSnapshots(UnsubscribeBookSnapshots),
245 Quotes(UnsubscribeQuotes),
246 Trades(UnsubscribeTrades),
247 Bars(UnsubscribeBars),
248 MarkPrices(UnsubscribeMarkPrices),
249 IndexPrices(UnsubscribeIndexPrices),
250 FundingRates(UnsubscribeFundingRates),
251 InstrumentStatus(UnsubscribeInstrumentStatus),
252 InstrumentClose(UnsubscribeInstrumentClose),
253 OptionGreeks(UnsubscribeOptionGreeks),
254 OptionChain(UnsubscribeOptionChain),
255}
256
257impl PartialEq for UnsubscribeCommand {
258 fn eq(&self, other: &Self) -> bool {
259 self.command_id() == other.command_id()
260 }
261}
262
263impl UnsubscribeCommand {
264 pub fn as_any(&self) -> &dyn Any {
266 self
267 }
268
269 pub fn command_id(&self) -> UUID4 {
270 match self {
271 Self::Data(cmd) => cmd.command_id,
272 Self::Instrument(cmd) => cmd.command_id,
273 Self::Instruments(cmd) => cmd.command_id,
274 Self::BookDeltas(cmd) => cmd.command_id,
275 Self::BookDepth10(cmd) => cmd.command_id,
276 Self::BookSnapshots(cmd) => cmd.command_id,
277 Self::Quotes(cmd) => cmd.command_id,
278 Self::Trades(cmd) => cmd.command_id,
279 Self::Bars(cmd) => cmd.command_id,
280 Self::MarkPrices(cmd) => cmd.command_id,
281 Self::IndexPrices(cmd) => cmd.command_id,
282 Self::FundingRates(cmd) => cmd.command_id,
283 Self::InstrumentStatus(cmd) => cmd.command_id,
284 Self::InstrumentClose(cmd) => cmd.command_id,
285 Self::OptionGreeks(cmd) => cmd.command_id,
286 Self::OptionChain(cmd) => cmd.command_id,
287 }
288 }
289
290 pub fn client_id(&self) -> Option<&ClientId> {
291 match self {
292 Self::Data(cmd) => cmd.client_id.as_ref(),
293 Self::Instrument(cmd) => cmd.client_id.as_ref(),
294 Self::Instruments(cmd) => cmd.client_id.as_ref(),
295 Self::BookDeltas(cmd) => cmd.client_id.as_ref(),
296 Self::BookDepth10(cmd) => cmd.client_id.as_ref(),
297 Self::BookSnapshots(cmd) => cmd.client_id.as_ref(),
298 Self::Quotes(cmd) => cmd.client_id.as_ref(),
299 Self::Trades(cmd) => cmd.client_id.as_ref(),
300 Self::Bars(cmd) => cmd.client_id.as_ref(),
301 Self::MarkPrices(cmd) => cmd.client_id.as_ref(),
302 Self::IndexPrices(cmd) => cmd.client_id.as_ref(),
303 Self::FundingRates(cmd) => cmd.client_id.as_ref(),
304 Self::InstrumentStatus(cmd) => cmd.client_id.as_ref(),
305 Self::InstrumentClose(cmd) => cmd.client_id.as_ref(),
306 Self::OptionGreeks(cmd) => cmd.client_id.as_ref(),
307 Self::OptionChain(cmd) => cmd.client_id.as_ref(),
308 }
309 }
310
311 pub fn venue(&self) -> Option<&Venue> {
312 match self {
313 Self::Data(cmd) => cmd.venue.as_ref(),
314 Self::Instrument(cmd) => cmd.venue.as_ref(),
315 Self::Instruments(cmd) => Some(&cmd.venue),
316 Self::BookDeltas(cmd) => cmd.venue.as_ref(),
317 Self::BookDepth10(cmd) => cmd.venue.as_ref(),
318 Self::BookSnapshots(cmd) => cmd.venue.as_ref(),
319 Self::Quotes(cmd) => cmd.venue.as_ref(),
320 Self::Trades(cmd) => cmd.venue.as_ref(),
321 Self::Bars(cmd) => cmd.venue.as_ref(),
322 Self::MarkPrices(cmd) => cmd.venue.as_ref(),
323 Self::IndexPrices(cmd) => cmd.venue.as_ref(),
324 Self::FundingRates(cmd) => cmd.venue.as_ref(),
325 Self::InstrumentStatus(cmd) => cmd.venue.as_ref(),
326 Self::InstrumentClose(cmd) => cmd.venue.as_ref(),
327 Self::OptionGreeks(cmd) => cmd.venue.as_ref(),
328 Self::OptionChain(cmd) => cmd.venue.as_ref(),
329 }
330 }
331
332 pub fn ts_init(&self) -> UnixNanos {
333 match self {
334 Self::Data(cmd) => cmd.ts_init,
335 Self::Instrument(cmd) => cmd.ts_init,
336 Self::Instruments(cmd) => cmd.ts_init,
337 Self::BookDeltas(cmd) => cmd.ts_init,
338 Self::BookDepth10(cmd) => cmd.ts_init,
339 Self::BookSnapshots(cmd) => cmd.ts_init,
340 Self::Quotes(cmd) => cmd.ts_init,
341 Self::Trades(cmd) => cmd.ts_init,
342 Self::MarkPrices(cmd) => cmd.ts_init,
343 Self::IndexPrices(cmd) => cmd.ts_init,
344 Self::FundingRates(cmd) => cmd.ts_init,
345 Self::Bars(cmd) => cmd.ts_init,
346 Self::InstrumentStatus(cmd) => cmd.ts_init,
347 Self::InstrumentClose(cmd) => cmd.ts_init,
348 Self::OptionGreeks(cmd) => cmd.ts_init,
349 Self::OptionChain(cmd) => cmd.ts_init,
350 }
351 }
352
353 pub fn correlation_id(&self) -> Option<UUID4> {
354 match self {
355 Self::Data(cmd) => cmd.correlation_id,
356 Self::Instrument(cmd) => cmd.correlation_id,
357 Self::Instruments(cmd) => cmd.correlation_id,
358 Self::BookDeltas(cmd) => cmd.correlation_id,
359 Self::BookDepth10(cmd) => cmd.correlation_id,
360 Self::BookSnapshots(cmd) => cmd.correlation_id,
361 Self::Quotes(cmd) => cmd.correlation_id,
362 Self::Trades(cmd) => cmd.correlation_id,
363 Self::MarkPrices(cmd) => cmd.correlation_id,
364 Self::IndexPrices(cmd) => cmd.correlation_id,
365 Self::FundingRates(cmd) => cmd.correlation_id,
366 Self::Bars(cmd) => cmd.correlation_id,
367 Self::InstrumentStatus(cmd) => cmd.correlation_id,
368 Self::InstrumentClose(cmd) => cmd.correlation_id,
369 Self::OptionGreeks(cmd) => cmd.correlation_id,
370 Self::OptionChain(_) => None,
371 }
372 }
373}
374
375fn check_client_id_or_venue(client_id: &Option<ClientId>, venue: &Option<Venue>) {
376 assert!(
377 client_id.is_some() || venue.is_some(),
378 "Both `client_id` and `venue` were None"
379 );
380}
381
382#[derive(Clone, Debug)]
383pub enum RequestCommand {
384 Data(RequestCustomData),
385 Instrument(RequestInstrument),
386 Instruments(RequestInstruments),
387 BookSnapshot(RequestBookSnapshot),
388 BookDepth(RequestBookDepth),
389 Quotes(RequestQuotes),
390 Trades(RequestTrades),
391 FundingRates(RequestFundingRates),
392 ForwardPrices(RequestForwardPrices),
393 Bars(RequestBars),
394}
395
396impl PartialEq for RequestCommand {
397 fn eq(&self, other: &Self) -> bool {
398 self.request_id() == other.request_id()
399 }
400}
401
402impl RequestCommand {
403 pub fn as_any(&self) -> &dyn Any {
405 self
406 }
407
408 pub fn request_id(&self) -> &UUID4 {
409 match self {
410 Self::Data(cmd) => &cmd.request_id,
411 Self::Instrument(cmd) => &cmd.request_id,
412 Self::Instruments(cmd) => &cmd.request_id,
413 Self::BookSnapshot(cmd) => &cmd.request_id,
414 Self::BookDepth(cmd) => &cmd.request_id,
415 Self::Quotes(cmd) => &cmd.request_id,
416 Self::Trades(cmd) => &cmd.request_id,
417 Self::FundingRates(cmd) => &cmd.request_id,
418 Self::ForwardPrices(cmd) => &cmd.request_id,
419 Self::Bars(cmd) => &cmd.request_id,
420 }
421 }
422
423 pub fn client_id(&self) -> Option<&ClientId> {
424 match self {
425 Self::Data(cmd) => Some(&cmd.client_id),
426 Self::Instrument(cmd) => cmd.client_id.as_ref(),
427 Self::Instruments(cmd) => cmd.client_id.as_ref(),
428 Self::BookSnapshot(cmd) => cmd.client_id.as_ref(),
429 Self::BookDepth(cmd) => cmd.client_id.as_ref(),
430 Self::Quotes(cmd) => cmd.client_id.as_ref(),
431 Self::Trades(cmd) => cmd.client_id.as_ref(),
432 Self::FundingRates(cmd) => cmd.client_id.as_ref(),
433 Self::ForwardPrices(cmd) => cmd.client_id.as_ref(),
434 Self::Bars(cmd) => cmd.client_id.as_ref(),
435 }
436 }
437
438 pub fn venue(&self) -> Option<&Venue> {
439 match self {
440 Self::Data(_) => None,
441 Self::Instrument(cmd) => Some(&cmd.instrument_id.venue),
442 Self::Instruments(cmd) => cmd.venue.as_ref(),
443 Self::BookSnapshot(cmd) => Some(&cmd.instrument_id.venue),
444 Self::BookDepth(cmd) => Some(&cmd.instrument_id.venue),
445 Self::Quotes(cmd) => Some(&cmd.instrument_id.venue),
446 Self::Trades(cmd) => Some(&cmd.instrument_id.venue),
447 Self::FundingRates(cmd) => Some(&cmd.instrument_id.venue),
448 Self::ForwardPrices(cmd) => Some(&cmd.venue),
449 Self::Bars(cmd) => match &cmd.bar_type {
451 BarType::Standard { instrument_id, .. } => Some(&instrument_id.venue),
452 BarType::Composite { instrument_id, .. } => Some(&instrument_id.venue),
453 },
454 }
455 }
456
457 pub fn ts_init(&self) -> UnixNanos {
458 match self {
459 Self::Data(cmd) => cmd.ts_init,
460 Self::Instrument(cmd) => cmd.ts_init,
461 Self::Instruments(cmd) => cmd.ts_init,
462 Self::BookSnapshot(cmd) => cmd.ts_init,
463 Self::BookDepth(cmd) => cmd.ts_init,
464 Self::Quotes(cmd) => cmd.ts_init,
465 Self::Trades(cmd) => cmd.ts_init,
466 Self::FundingRates(cmd) => cmd.ts_init,
467 Self::ForwardPrices(cmd) => cmd.ts_init,
468 Self::Bars(cmd) => cmd.ts_init,
469 }
470 }
471}
472
473#[derive(Clone, Debug)]
474pub enum DataResponse {
475 Data(CustomDataResponse),
476 Instrument(Box<InstrumentResponse>),
477 Instruments(InstrumentsResponse),
478 Book(BookResponse),
479 Quotes(QuotesResponse),
480 Trades(TradesResponse),
481 FundingRates(FundingRatesResponse),
482 ForwardPrices(ForwardPricesResponse),
483 Bars(BarsResponse),
484}
485
486impl DataResponse {
487 pub fn as_any(&self) -> &dyn Any {
489 self
490 }
491
492 pub fn correlation_id(&self) -> &UUID4 {
493 match self {
494 Self::Data(resp) => &resp.correlation_id,
495 Self::Instrument(resp) => &resp.correlation_id,
496 Self::Instruments(resp) => &resp.correlation_id,
497 Self::Book(resp) => &resp.correlation_id,
498 Self::Quotes(resp) => &resp.correlation_id,
499 Self::Trades(resp) => &resp.correlation_id,
500 Self::FundingRates(resp) => &resp.correlation_id,
501 Self::ForwardPrices(resp) => &resp.correlation_id,
502 Self::Bars(resp) => &resp.correlation_id,
503 }
504 }
505}
506
507pub type Payload = Arc<dyn Any + Send + Sync>;