1use crate::{
2 symbology::MarketdataVenue,
3 utils::{chrono::DateTimeOrUtc, pagination::OffsetAndLimit},
4 Dir, DirPair, SequenceIdAndNumber,
5};
6use chrono::{DateTime, NaiveDate, Utc};
7use derive::grpc;
8use derive_more::Deref;
9use rust_decimal::Decimal;
10use rust_decimal_macros::dec;
11use schemars::JsonSchema;
12use serde::{Deserialize, Serialize};
13use serde_with::{serde_as, skip_serializing_none};
14use strum::EnumString;
15
16pub mod candle_width;
17pub use candle_width::CandleWidth;
18pub mod options_marketdata;
19
20#[grpc(package = "json.architect")]
21#[grpc(service = "Marketdata", name = "l1_book_snapshot", response = "L1BookSnapshot")]
22#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
23pub struct L1BookSnapshotRequest {
24 #[serde(default, skip_serializing_if = "Option::is_none")]
25 pub venue: Option<MarketdataVenue>,
26 pub symbol: String,
27}
28
29#[grpc(package = "json.architect")]
30#[grpc(service = "Marketdata", name = "l1_book_snapshots", response = "L1BookSnapshot")]
31#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
32pub struct L1BookSnapshotsRequest {
33 #[serde(default, skip_serializing_if = "Option::is_none")]
34 pub venue: Option<MarketdataVenue>,
35 #[serde(default, skip_serializing_if = "Option::is_none")]
36 pub symbols: Option<Vec<String>>,
37}
38
39pub type L1BookSnapshots = Vec<L1BookSnapshot>;
40
41#[grpc(package = "json.architect")]
42#[grpc(
43 service = "Marketdata",
44 name = "subscribe_l1_book_snapshots",
45 response = "L1BookSnapshot",
46 server_streaming
47)]
48#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
49pub struct SubscribeL1BookSnapshotsRequest {
50 #[serde(default, skip_serializing_if = "Option::is_none")]
51 pub venue: Option<MarketdataVenue>,
52 #[serde(default, skip_serializing_if = "Option::is_none")]
54 pub symbols: Option<Vec<String>>,
55 #[serde(default)]
57 pub send_initial_snapshots: bool,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
61pub struct L1BookSnapshot {
62 #[serde(rename = "s")]
63 #[schemars(title = "symbol")]
64 pub symbol: String,
65 #[serde(rename = "ts")]
67 #[schemars(title = "timestamp")]
68 pub timestamp: i64,
69 #[serde(rename = "tn")]
70 #[schemars(title = "timestamp_ns")]
71 pub timestamp_ns: u32,
72 #[serde(rename = "rt", default, skip_serializing_if = "Option::is_none")]
74 #[schemars(title = "recv_time")]
75 pub recv_time: Option<i64>,
76 #[serde(rename = "rtn", default, skip_serializing_if = "Option::is_none")]
77 #[schemars(title = "recv_time_ns")]
78 pub recv_time_ns: Option<u32>,
79 #[serde(rename = "b")]
81 #[schemars(title = "best_bid")]
82 pub best_bid: Option<(Decimal, Decimal)>,
83 #[serde(rename = "a")]
85 #[schemars(title = "best_ask")]
86 pub best_ask: Option<(Decimal, Decimal)>,
87}
88
89impl L1BookSnapshot {
90 pub fn timestamp(&self) -> Option<DateTime<Utc>> {
91 chrono::DateTime::from_timestamp(self.timestamp, self.timestamp_ns)
92 }
93
94 pub fn bbo(&self) -> DirPair<Option<Decimal>> {
95 DirPair {
96 buy: self.best_bid.map(|(px, _)| px),
97 sell: self.best_ask.map(|(px, _)| px),
98 }
99 }
100
101 pub fn recv_time(&self) -> Option<DateTime<Utc>> {
102 match (self.recv_time, self.recv_time_ns) {
103 (Some(ts), Some(ns)) => chrono::DateTime::from_timestamp(ts, ns),
104 _ => None,
105 }
106 }
107
108 pub fn mid_price(&self) -> Option<Decimal> {
109 match (self.best_bid, self.best_ask) {
110 (Some((bid_px, _)), Some((ask_px, _))) => Some((bid_px + ask_px) / dec!(2)),
111 _ => None,
112 }
113 }
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
117pub struct L2BookSnapshot {
118 #[serde(rename = "ts")]
119 #[schemars(title = "timestamp")]
120 pub timestamp: i64,
121 #[serde(rename = "tn")]
122 #[schemars(title = "timestamp_ns")]
123 pub timestamp_ns: u32,
124 #[serde(flatten)]
125 pub sequence: SequenceIdAndNumber,
126 #[serde(rename = "b")]
127 #[schemars(title = "bids")]
128 pub bids: Vec<(Decimal, Decimal)>,
129 #[serde(rename = "a")]
130 #[schemars(title = "asks")]
131 pub asks: Vec<(Decimal, Decimal)>,
132}
133
134impl L2BookSnapshot {
135 pub fn timestamp(&self) -> Option<DateTime<Utc>> {
136 chrono::DateTime::from_timestamp(self.timestamp, self.timestamp_ns)
137 }
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
141pub struct L2BookDiff {
142 #[serde(rename = "ts")]
143 #[schemars(title = "timestamp")]
144 pub timestamp: i64,
145 #[serde(rename = "tn")]
146 #[schemars(title = "timestamp_ns")]
147 pub timestamp_ns: u32,
148 #[serde(flatten)]
149 pub sequence: SequenceIdAndNumber,
150 #[serde(rename = "b")]
153 #[schemars(title = "bids")]
154 pub bids: Vec<(Decimal, Decimal)>,
155 #[serde(rename = "a")]
158 #[schemars(title = "asks")]
159 pub asks: Vec<(Decimal, Decimal)>,
160}
161
162impl L2BookDiff {
163 pub fn timestamp(&self) -> Option<DateTime<Utc>> {
164 chrono::DateTime::from_timestamp(self.timestamp, self.timestamp_ns)
165 }
166}
167
168#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
248#[serde(tag = "t")]
249pub enum L2BookUpdate {
251 #[serde(rename = "s")]
252 #[schemars(title = "Snapshot|L2BookSnapshot")]
253 Snapshot(L2BookSnapshot),
254 #[serde(rename = "d")]
255 #[schemars(title = "Diff|L2BookDiff")]
256 Diff(L2BookDiff),
257}
258
259impl L2BookUpdate {
260 pub fn timestamp(&self) -> Option<DateTime<Utc>> {
261 match self {
262 Self::Snapshot(snapshot) => snapshot.timestamp(),
263 Self::Diff(diff) => diff.timestamp(),
264 }
265 }
266
267 pub fn sequence(&self) -> SequenceIdAndNumber {
268 match self {
269 Self::Snapshot(snapshot) => snapshot.sequence,
270 Self::Diff(diff) => diff.sequence,
271 }
272 }
273
274 pub fn is_snapshot(&self) -> bool {
275 match self {
276 Self::Snapshot(_) => true,
277 Self::Diff(_) => false,
278 }
279 }
280}
281
282#[grpc(package = "json.architect")]
283#[grpc(service = "Marketdata", name = "l2_book_snapshot", response = "L2BookSnapshot")]
284#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
285pub struct L2BookSnapshotRequest {
286 #[serde(default, skip_serializing_if = "Option::is_none")]
287 pub venue: Option<MarketdataVenue>,
288 pub symbol: String,
289}
290
291#[grpc(package = "json.architect")]
292#[grpc(
293 service = "Marketdata",
294 name = "subscribe_l2_book_updates",
295 response = "L2BookUpdate",
296 server_streaming
297)]
298#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
299pub struct SubscribeL2BookUpdatesRequest {
300 #[serde(default, skip_serializing_if = "Option::is_none")]
301 pub venue: Option<MarketdataVenue>,
302 pub symbol: String,
303}
304
305#[grpc(package = "json.architect")]
307#[grpc(
308 service = "Marketdata",
309 name = "subscribe_candles",
310 response = "Candle",
311 server_streaming
312)]
313#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
314pub struct SubscribeCandlesRequest {
315 #[serde(default, skip_serializing_if = "Option::is_none")]
316 pub venue: Option<MarketdataVenue>,
317 pub symbol: String,
318 pub candle_widths: Option<Vec<CandleWidth>>,
320}
321
322#[grpc(package = "json.architect")]
324#[grpc(
325 service = "Marketdata",
326 name = "subscribe_many_candles",
327 response = "Candle",
328 server_streaming
329)]
330#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
331pub struct SubscribeManyCandlesRequest {
332 #[serde(default, skip_serializing_if = "Option::is_none")]
333 pub venue: Option<MarketdataVenue>,
334 #[serde(default, skip_serializing_if = "Option::is_none")]
336 pub symbols: Option<Vec<String>>,
337 pub candle_width: CandleWidth,
338}
339
340#[grpc(package = "json.architect")]
343#[grpc(
344 service = "Marketdata",
345 name = "subscribe_current_candles",
346 response = "Candle",
347 server_streaming
348)]
349#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
350pub struct SubscribeCurrentCandlesRequest {
351 #[serde(default, skip_serializing_if = "Option::is_none")]
352 pub venue: Option<MarketdataVenue>,
353 pub symbol: String,
354 pub candle_width: CandleWidth,
355 #[serde(default, skip_serializing_if = "Option::is_none")]
358 pub tick_period_ms: Option<u32>,
359}
360
361#[derive(
362 Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, JsonSchema,
363)]
364pub struct Candle {
365 #[serde(rename = "ts")]
366 #[schemars(title = "timestamp")]
367 pub timestamp: i64,
368 #[serde(rename = "tn")]
369 #[schemars(title = "timestamp_ns")]
370 pub timestamp_ns: u32,
371 #[serde(rename = "w")]
372 #[schemars(title = "width")]
373 pub width: CandleWidth,
374 #[serde(rename = "s")]
375 #[schemars(title = "symbol")]
376 pub symbol: String,
377 #[serde(rename = "o")]
378 #[schemars(title = "open")]
379 pub open: Option<Decimal>,
380 #[serde(rename = "h")]
381 #[schemars(title = "high")]
382 pub high: Option<Decimal>,
383 #[serde(rename = "l")]
384 #[schemars(title = "low")]
385 pub low: Option<Decimal>,
386 #[serde(rename = "c")]
387 #[schemars(title = "close")]
388 pub close: Option<Decimal>,
389 #[serde(rename = "v")]
390 #[schemars(title = "volume")]
391 pub volume: Decimal,
392 #[serde(rename = "bv")]
393 #[schemars(title = "buy_volume")]
394 pub buy_volume: Decimal,
395 #[serde(rename = "av")]
396 #[schemars(title = "sell_volume")]
397 pub sell_volume: Decimal,
398 #[serde(default, rename = "mo", skip_serializing_if = "Option::is_none")]
399 #[schemars(title = "mid_open")]
400 pub mid_open: Option<Decimal>,
401 #[serde(default, rename = "mc", skip_serializing_if = "Option::is_none")]
402 #[schemars(title = "mid_close")]
403 pub mid_close: Option<Decimal>,
404 #[serde(default, rename = "mh", skip_serializing_if = "Option::is_none")]
405 #[schemars(title = "mid_high")]
406 pub mid_high: Option<Decimal>,
407 #[serde(default, rename = "ml", skip_serializing_if = "Option::is_none")]
408 #[schemars(title = "mid_low")]
409 pub mid_low: Option<Decimal>,
410 #[serde(default, rename = "bo", skip_serializing_if = "Option::is_none")]
411 #[schemars(title = "bid_open")]
412 pub bid_open: Option<Decimal>,
413 #[serde(default, rename = "bc", skip_serializing_if = "Option::is_none")]
414 #[schemars(title = "bid_close")]
415 pub bid_close: Option<Decimal>,
416 #[serde(default, rename = "bh", skip_serializing_if = "Option::is_none")]
417 #[schemars(title = "bid_high")]
418 pub bid_high: Option<Decimal>,
419 #[serde(default, rename = "bl", skip_serializing_if = "Option::is_none")]
420 #[schemars(title = "bid_low")]
421 pub bid_low: Option<Decimal>,
422 #[serde(default, rename = "ao", skip_serializing_if = "Option::is_none")]
423 #[schemars(title = "ask_open")]
424 pub ask_open: Option<Decimal>,
425 #[serde(default, rename = "ac", skip_serializing_if = "Option::is_none")]
426 #[schemars(title = "ask_close")]
427 pub ask_close: Option<Decimal>,
428 #[serde(default, rename = "ah", skip_serializing_if = "Option::is_none")]
429 #[schemars(title = "ask_high")]
430 pub ask_high: Option<Decimal>,
431 #[serde(default, rename = "al", skip_serializing_if = "Option::is_none")]
432 #[schemars(title = "ask_low")]
433 pub ask_low: Option<Decimal>,
434}
435
436impl Candle {
437 pub fn default(timestamp: DateTime<Utc>, width: CandleWidth, symbol: String) -> Self {
438 Self {
439 timestamp: timestamp.timestamp(),
440 timestamp_ns: timestamp.timestamp_subsec_nanos(),
441 width,
442 symbol,
443 open: None,
444 high: None,
445 low: None,
446 close: None,
447 volume: dec!(0),
448 buy_volume: dec!(0),
449 sell_volume: dec!(0),
450 mid_open: None,
451 mid_close: None,
452 mid_high: None,
453 mid_low: None,
454 bid_open: None,
455 bid_close: None,
456 bid_high: None,
457 bid_low: None,
458 ask_open: None,
459 ask_close: None,
460 ask_high: None,
461 ask_low: None,
462 }
463 }
464
465 pub fn timestamp(&self) -> Option<DateTime<Utc>> {
466 DateTime::<Utc>::from_timestamp(self.timestamp, self.timestamp_ns)
467 }
468}
469
470#[grpc(package = "json.architect")]
472#[grpc(
473 service = "Marketdata",
474 name = "historical_candles",
475 response = "HistoricalCandlesResponse"
476)]
477#[serde_as]
478#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
479pub struct HistoricalCandlesRequest {
480 #[serde(default, skip_serializing_if = "Option::is_none")]
481 pub venue: Option<MarketdataVenue>,
482 pub symbol: String,
483 pub candle_width: CandleWidth,
484 #[serde_as(as = "DateTimeOrUtc")]
485 #[schemars(with = "DateTimeOrUtc")]
486 pub start_date: DateTime<Utc>,
487 #[serde_as(as = "DateTimeOrUtc")]
488 #[schemars(with = "DateTimeOrUtc")]
489 pub end_date: DateTime<Utc>,
490}
491
492#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
493pub struct HistoricalCandlesResponse {
494 pub candles: Vec<Candle>,
495}
496
497#[grpc(package = "json.architect")]
498#[grpc(
499 service = "Marketdata",
500 name = "subscribe_trades",
501 response = "Trade",
502 server_streaming
503)]
504#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
505pub struct SubscribeTradesRequest {
506 #[serde(default, skip_serializing_if = "Option::is_none")]
507 pub venue: Option<MarketdataVenue>,
508 #[serde(default, skip_serializing_if = "Option::is_none")]
510 pub symbol: Option<String>,
511}
512
513#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
514pub struct Trade {
515 #[serde(rename = "s")]
516 #[schemars(title = "symbol")]
517 pub symbol: String,
518 #[serde(rename = "ts")]
519 #[schemars(title = "timestamp")]
520 pub timestamp: i64,
521 #[serde(rename = "tn")]
522 #[schemars(title = "timestamp_ns")]
523 pub timestamp_ns: u32,
524 #[serde(rename = "d")]
525 #[schemars(title = "direction")]
526 pub direction: Option<Dir>, #[serde(rename = "p")]
528 #[schemars(title = "price")]
529 pub price: Decimal,
530 #[serde(rename = "q")]
531 #[schemars(title = "size")]
532 pub size: Decimal,
533}
534
535impl Trade {
536 pub fn timestamp(&self) -> Option<DateTime<Utc>> {
537 DateTime::<Utc>::from_timestamp(self.timestamp, self.timestamp_ns)
538 }
539}
540
541#[grpc(package = "json.architect")]
542#[grpc(service = "Marketdata", name = "market_status", response = "MarketStatus")]
543#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
544pub struct MarketStatusRequest {
545 #[serde(default, skip_serializing_if = "Option::is_none")]
546 pub venue: Option<MarketdataVenue>,
547 pub symbol: String,
548}
549
550#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
551#[cfg_attr(feature = "graphql", derive(juniper::GraphQLObject))]
552pub struct MarketStatus {
553 #[serde(rename = "s")]
554 #[schemars(title = "symbol")]
555 pub symbol: String,
556 pub is_trading: Option<bool>,
557 pub is_quoting: Option<bool>,
558}
559
560#[grpc(package = "json.architect")]
561#[grpc(service = "Marketdata", name = "ticker", response = "Ticker")]
562#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
563pub struct TickerRequest {
564 #[serde(default, skip_serializing_if = "Option::is_none")]
565 pub venue: Option<MarketdataVenue>,
566 pub symbol: String,
567}
568
569#[skip_serializing_none]
570#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, JsonSchema)]
571pub struct TickerValues {
572 #[serde(rename = "bp")]
573 #[schemars(title = "bid_price")]
574 pub bid_price: Option<Decimal>,
575 #[serde(rename = "bs")]
576 #[schemars(title = "bid_size")]
577 pub bid_size: Option<Decimal>,
578 #[serde(rename = "ap")]
579 #[schemars(title = "ask_price")]
580 pub ask_price: Option<Decimal>,
581 #[serde(rename = "as")]
582 #[schemars(title = "ask_size")]
583 pub ask_size: Option<Decimal>,
584 #[serde(rename = "p")]
585 #[schemars(title = "last_price")]
586 pub last_price: Option<Decimal>,
587 #[serde(rename = "q")]
588 #[schemars(title = "last_size")]
589 pub last_size: Option<Decimal>,
590 #[serde(rename = "xo")]
591 #[schemars(title = "session_open")]
592 pub session_open: Option<Decimal>,
593 #[serde(rename = "xl")]
594 #[schemars(title = "session_low")]
595 pub session_low: Option<Decimal>,
596 #[serde(rename = "xh")]
597 #[schemars(title = "session_high")]
598 pub session_high: Option<Decimal>,
599 #[serde(rename = "xv")]
600 #[schemars(title = "session_volume")]
601 pub session_volume: Option<Decimal>,
602 #[serde(rename = "o")]
603 #[schemars(title = "open_24h")]
604 pub open_24h: Option<Decimal>,
605 #[serde(rename = "l")]
606 #[schemars(title = "low_24h")]
607 pub low_24h: Option<Decimal>,
608 #[serde(rename = "h")]
609 #[schemars(title = "high_24h")]
610 pub high_24h: Option<Decimal>,
611 #[serde(rename = "v")]
612 #[schemars(title = "volume_24h")]
613 pub volume_24h: Option<Decimal>,
614 #[serde(rename = "vm")]
615 #[schemars(title = "volume_30d")]
616 pub volume_30d: Option<Decimal>,
617 #[serde(rename = "oi")]
618 #[schemars(title = "open_interest")]
619 pub open_interest: Option<Decimal>,
620 #[serde(rename = "sp")]
621 #[schemars(title = "last_settlement_price")]
622 pub last_settlement_price: Option<Decimal>,
623 #[serde(rename = "sd")]
624 #[schemars(title = "last_settlement_date")]
625 pub last_settlement_date: Option<NaiveDate>,
626 #[serde(rename = "isp")]
627 #[schemars(title = "indicative_settlement_price")]
628 pub indicative_settlement_price: Option<Decimal>,
629 #[serde(rename = "mp")]
630 #[schemars(title = "mark_price")]
631 pub mark_price: Option<Decimal>,
632 #[serde(rename = "ip")]
633 #[schemars(title = "index_price")]
634 pub index_price: Option<Decimal>,
635 #[serde(rename = "fr")]
636 #[schemars(title = "funding_rate")]
637 pub funding_rate: Option<Decimal>,
638 #[serde(rename = "ft")]
639 #[schemars(title = "next_funding_time")]
640 pub next_funding_time: Option<DateTime<Utc>>,
641 pub market_cap: Option<Decimal>,
642 pub price_to_earnings: Option<Decimal>,
643 pub eps_adj: Option<Decimal>,
644 pub shares_outstanding_weighted_adj: Option<Decimal>,
645 pub dividend: Option<Decimal>,
646 pub dividend_yield: Option<Decimal>,
647 }
653
654impl TickerValues {
655 pub fn is_none(&self) -> bool {
656 self.session_open.is_none()
657 && self.session_low.is_none()
658 && self.session_high.is_none()
659 && self.open_24h.is_none()
660 && self.low_24h.is_none()
661 && self.high_24h.is_none()
662 && self.volume_24h.is_none()
663 && self.volume_30d.is_none()
664 && self.session_volume.is_none()
665 && self.open_interest.is_none()
666 && self.last_settlement_price.is_none()
667 && self.mark_price.is_none()
668 && self.index_price.is_none()
669 && self.funding_rate.is_none()
670 && self.next_funding_time.is_none()
671 }
672
673 pub fn last_or_mid_price(&self) -> Option<Decimal> {
674 self.last_price.or_else(|| {
675 let bid_price = self.bid_price?;
676 let ask_price = self.ask_price?;
677 Some((bid_price + ask_price) / dec!(2))
678 })
679 }
680}
681
682#[derive(Debug, Deref, Clone, Serialize, Deserialize, JsonSchema)]
683pub struct Ticker {
684 #[serde(rename = "s")]
685 #[schemars(title = "symbol")]
686 pub symbol: String,
687 #[serde(rename = "ve")]
688 #[schemars(title = "venue")]
689 pub venue: MarketdataVenue,
690 #[serde(rename = "ts")]
691 #[schemars(title = "timestamp")]
692 pub timestamp: i64,
693 #[serde(rename = "tn")]
694 #[schemars(title = "timestamp_ns")]
695 pub timestamp_ns: u32,
696 #[serde(flatten)]
697 #[deref]
698 pub values: TickerValues,
699}
700
701impl Ticker {
702 pub fn timestamp(&self) -> Option<DateTime<Utc>> {
703 DateTime::<Utc>::from_timestamp(self.timestamp, self.timestamp_ns)
704 }
705}
706
707#[derive(Debug, Copy, Clone, EnumString, Serialize, Deserialize, JsonSchema)]
708#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
709#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
710#[cfg_attr(feature = "graphql", derive(juniper::GraphQLEnum))]
711pub enum SortTickersBy {
712 VolumeDesc,
713 ChangeAsc,
714 ChangeDesc,
715 AbsChangeDesc,
716}
717
718#[grpc(package = "json.architect")]
719#[grpc(service = "Marketdata", name = "tickers", response = "TickersResponse")]
720#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
721pub struct TickersRequest {
722 #[serde(default, skip_serializing_if = "Option::is_none")]
723 pub venue: Option<MarketdataVenue>,
724 #[serde(default, skip_serializing_if = "Option::is_none")]
725 pub symbols: Option<Vec<String>>,
726 #[serde(default, flatten)]
727 pub pagination: OffsetAndLimit<SortTickersBy>,
728 #[serde(default, skip_serializing_if = "Option::is_none")]
729 pub include_options: Option<bool>,
730}
731
732#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
733pub struct TickersResponse {
734 pub tickers: Vec<Ticker>,
735}
736
737#[grpc(package = "json.architect")]
740#[grpc(
741 service = "Marketdata",
742 name = "ticker",
743 response = "TickerUpdate",
744 server_streaming
745)]
746#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
747pub struct SubscribeTickersRequest {
748 #[serde(default, skip_serializing_if = "Option::is_none")]
750 pub symbols: Option<Vec<String>>,
751}
752
753#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
754#[serde(tag = "t")]
755pub enum TickerUpdate {
757 #[serde(rename = "s")]
758 #[schemars(title = "Snapshot|Ticker")]
759 Snapshot(Ticker),
760 #[serde(rename = "d")]
761 #[schemars(title = "Diff|Ticker")]
762 Diff(Ticker),
763}
764
765#[grpc(package = "json.architect")]
766#[grpc(service = "Marketdata", name = "subscribe_liquidations", response = "Liquidation")]
767#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize, JsonSchema)]
768pub struct SubscribeLiquidationsRequest {
769 #[serde(default, skip_serializing_if = "Option::is_none")]
770 pub symbols: Option<Vec<String>>,
771}
772
773#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
774pub struct Liquidation {
775 #[serde(rename = "s")]
776 #[schemars(title = "symbol")]
777 pub symbol: String,
778 #[serde(rename = "ts")]
779 #[schemars(title = "timestamp")]
780 pub timestamp: i64,
781 #[serde(rename = "tn")]
782 #[schemars(title = "timestamp_ns")]
783 pub timestamp_ns: u32,
784 #[serde(rename = "d")]
785 #[schemars(title = "direction")]
786 pub direction: Dir,
787 #[serde(rename = "p")]
788 #[schemars(title = "price")]
789 pub price: Decimal,
790 #[serde(rename = "q")]
791 #[schemars(title = "size")]
792 pub size: Decimal,
793}