1use digdigdig3::core::traits::Credentials;
2use digdigdig3::core::types::{AccountType, ExchangeId, SymbolInfo};
3use digdigdig3::core::websocket::KlineInterval;
4
5use crate::data::{
6 AggTradePoint, AuctionEventPoint, BalanceUpdatePoint, BarPoint, BasisPoint, BlockTradePoint,
7 CompositeIndexPoint,
8 FootprintPoint, FundingRatePoint, FundingSettlementPoint, HistoricalVolatilityPoint,
9 IndexPriceKlinePoint, IndexPricePoint, InsuranceFundPoint, LiquidationPoint,
10 LiquidationBucketPoint,
11 LongShortRatioPoint, MarkPriceKlinePoint, MarkPricePoint,
12 MarketWarningPoint, ObDeltaPoint, ObSnapshotPoint, OpenInterestPoint, OptionGreeksPoint,
13 OrderUpdatePoint, OrderbookL3Point, PositionUpdatePoint, PredictedFundingPoint,
14 PremiumIndexKlinePoint, RiskLimitPoint,
15 SettlementEventPoint, TakerVolumePoint, TickerPoint, TradePoint, VolatilityIndexPoint,
16 KagiSegmentPoint, PnfColumnPoint, RenkoBrickPoint, ScalarBarPoint,
17 ThreeLineBreakLinePoint, TpoSessionPoint,
18};
19use crate::series::{Kind, SeriesKey};
20
21#[derive(Debug, Clone, PartialEq, Eq, Hash)]
26pub enum Stream {
27 Ticker,
28 Trade,
29 Orderbook,
30 OrderbookDelta,
31 Kline(KlineInterval),
32 MarkPrice,
33 FundingRate,
34 OpenInterest,
35 Liquidation,
36 AggTrade,
37 BlockTrade,
39 AuctionEvent,
40 IndexPrice,
41 CompositeIndex,
42 OptionGreeks,
43 VolatilityIndex,
44 HistoricalVolatility,
45 LongShortRatio,
46 TakerVolume,
47 LiquidationBucket,
48 Basis,
49 InsuranceFund,
50 OrderbookL3,
51 SettlementEvent,
52 MarketWarning,
53 RiskLimit,
54 PredictedFunding,
55 FundingSettlement,
56 MarkPriceKline(KlineInterval),
57 IndexPriceKline(KlineInterval),
58 PremiumIndexKline(KlineInterval),
59 RangeBar(u64),
63 TickBar(u32),
65 VolumeBar(u64),
68 Footprint(KlineInterval),
70 RenkoBar(u64, u8),
73 PnfBar(u64, u8),
75 KagiBar(u64),
77 CvdLine,
79 ThreeLineBreak { lines_back: u8 },
83 TpoProfile(u16, crate::series::TpoSource),
86 DollarBar { dollar_threshold: u64 },
89 TickImbalanceBar { alpha_x100: u16, min_ticks: u32 },
93 VolumeImbalanceBar { alpha_x100: u16, min_ticks: u32 },
96 RunBar { alpha_x100: u16, min_ticks: u32 },
99 OrderUpdate,
102 BalanceUpdate,
104 PositionUpdate,
106}
107
108impl Stream {
109 pub(crate) fn to_kind(&self) -> Kind {
110 match self {
111 Stream::Trade => Kind::Trade,
112 Stream::AggTrade => Kind::AggTrade,
113 Stream::Kline(iv) => Kind::Kline(iv.clone()),
114 Stream::Ticker => Kind::Ticker,
115 Stream::Orderbook => Kind::Orderbook,
116 Stream::OrderbookDelta => Kind::OrderbookDelta,
117 Stream::MarkPrice => Kind::MarkPrice,
118 Stream::FundingRate => Kind::FundingRate,
119 Stream::OpenInterest => Kind::OpenInterest,
120 Stream::Liquidation => Kind::Liquidation,
121 Stream::BlockTrade => Kind::BlockTrade,
122 Stream::AuctionEvent => Kind::AuctionEvent,
123 Stream::IndexPrice => Kind::IndexPrice,
124 Stream::CompositeIndex => Kind::CompositeIndex,
125 Stream::OptionGreeks => Kind::OptionGreeks,
126 Stream::VolatilityIndex => Kind::VolatilityIndex,
127 Stream::HistoricalVolatility => Kind::HistoricalVolatility,
128 Stream::LongShortRatio => Kind::LongShortRatio,
129 Stream::TakerVolume => Kind::TakerVolume,
130 Stream::LiquidationBucket => Kind::LiquidationBucket,
131 Stream::Basis => Kind::Basis,
132 Stream::InsuranceFund => Kind::InsuranceFund,
133 Stream::OrderbookL3 => Kind::OrderbookL3,
134 Stream::SettlementEvent => Kind::SettlementEvent,
135 Stream::MarketWarning => Kind::MarketWarning,
136 Stream::RiskLimit => Kind::RiskLimit,
137 Stream::PredictedFunding => Kind::PredictedFunding,
138 Stream::FundingSettlement => Kind::FundingSettlement,
139 Stream::MarkPriceKline(iv) => Kind::MarkPriceKline(iv.clone()),
140 Stream::IndexPriceKline(iv) => Kind::IndexPriceKline(iv.clone()),
141 Stream::PremiumIndexKline(iv) => Kind::PremiumIndexKline(iv.clone()),
142 Stream::RangeBar(r) => Kind::RangeBar(*r),
143 Stream::TickBar(n) => Kind::TickBar(*n),
144 Stream::VolumeBar(v) => Kind::VolumeBar(*v),
145 Stream::Footprint(iv) => Kind::Footprint(iv.clone()),
146 Stream::RenkoBar(b, r) => Kind::RenkoBar(*b, *r),
147 Stream::PnfBar(b, r) => Kind::PnfBar(*b, *r),
148 Stream::KagiBar(r) => Kind::KagiBar(*r),
149 Stream::CvdLine => Kind::CvdLine,
150 Stream::ThreeLineBreak { lines_back } => Kind::ThreeLineBreak { lines_back: *lines_back },
151 Stream::TpoProfile(freq, src) => Kind::TpoProfile(*freq, *src),
152 Stream::DollarBar { dollar_threshold } => Kind::DollarBar { dollar_threshold: *dollar_threshold },
153 Stream::TickImbalanceBar { alpha_x100, min_ticks } => Kind::TickImbalanceBar { alpha_x100: *alpha_x100, min_ticks: *min_ticks },
154 Stream::VolumeImbalanceBar { alpha_x100, min_ticks } => Kind::VolumeImbalanceBar { alpha_x100: *alpha_x100, min_ticks: *min_ticks },
155 Stream::RunBar { alpha_x100, min_ticks } => Kind::RunBar { alpha_x100: *alpha_x100, min_ticks: *min_ticks },
156 Stream::OrderUpdate => Kind::OrderUpdate,
157 Stream::BalanceUpdate => Kind::BalanceUpdate,
158 Stream::PositionUpdate => Kind::PositionUpdate,
159 }
160 }
161
162 pub fn is_private(&self) -> bool {
164 matches!(self, Stream::OrderUpdate | Stream::BalanceUpdate | Stream::PositionUpdate)
165 }
166}
167
168#[derive(Debug, Clone)]
169pub(crate) struct Entry {
170 pub(crate) exchange: ExchangeId,
171 pub(crate) symbol: String,
172 pub(crate) account_type: AccountType,
173 pub(crate) streams: Vec<Stream>,
174 pub(crate) is_raw: bool,
181 pub(crate) credentials: Option<Credentials>,
184 pub(crate) warm_override: Option<usize>,
189}
190
191#[derive(Debug, Default, Clone)]
194pub struct SubscriptionSet {
195 pub(crate) entries: Vec<Entry>,
196}
197
198impl SubscriptionSet {
199 pub fn new() -> Self { Self::default() }
200
201 pub fn add(
208 mut self,
209 exchange: ExchangeId,
210 symbol: impl Into<String>,
211 account_type: AccountType,
212 streams: impl IntoIterator<Item = Stream>,
213 ) -> Self {
214 self.entries.push(Entry {
215 exchange,
216 symbol: symbol.into(),
217 account_type,
218 streams: streams.into_iter().collect(),
219 is_raw: false,
220 credentials: None,
221 warm_override: None,
222 });
223 self
224 }
225
226 pub fn add_with_warm(
238 mut self,
239 exchange: ExchangeId,
240 symbol: impl Into<String>,
241 account_type: AccountType,
242 streams: impl IntoIterator<Item = Stream>,
243 warm_n: usize,
244 ) -> Self {
245 self.entries.push(Entry {
246 exchange,
247 symbol: symbol.into(),
248 account_type,
249 streams: streams.into_iter().collect(),
250 is_raw: false,
251 credentials: None,
252 warm_override: Some(warm_n),
253 });
254 self
255 }
256
257 pub fn add_raw(
269 mut self,
270 exchange: ExchangeId,
271 symbol: impl Into<String>,
272 account_type: AccountType,
273 streams: impl IntoIterator<Item = Stream>,
274 ) -> Self {
275 self.entries.push(Entry {
276 exchange,
277 symbol: symbol.into(),
278 account_type,
279 streams: streams.into_iter().collect(),
280 is_raw: true,
281 credentials: None,
282 warm_override: None,
283 });
284 self
285 }
286
287 pub fn add_authenticated(
299 mut self,
300 exchange: ExchangeId,
301 account_type: AccountType,
302 credentials: Credentials,
303 streams: impl IntoIterator<Item = Stream>,
304 ) -> Self {
305 self.entries.push(Entry {
306 exchange,
307 symbol: String::new(),
308 account_type,
309 streams: streams.into_iter().collect(),
310 is_raw: true,
311 credentials: Some(credentials),
312 warm_override: None,
313 });
314 self
315 }
316
317 pub fn len(&self) -> usize { self.entries.len() }
318 pub fn is_empty(&self) -> bool { self.entries.is_empty() }
319}
320
321#[derive(Debug, Clone)]
323pub enum Event {
324 Trade {
325 exchange: ExchangeId,
326 symbol: String,
327 point: TradePoint,
328 },
329 AggTrade {
330 exchange: ExchangeId,
331 symbol: String,
332 point: AggTradePoint,
333 },
334 Bar {
335 exchange: ExchangeId,
336 symbol: String,
337 timeframe: KlineInterval,
338 point: BarPoint,
339 },
340 Ticker {
341 exchange: ExchangeId,
342 symbol: String,
343 point: TickerPoint,
344 },
345 OrderbookSnapshot {
346 exchange: ExchangeId,
347 symbol: String,
348 point: ObSnapshotPoint,
349 },
350 OrderbookDelta {
351 exchange: ExchangeId,
352 symbol: String,
353 point: ObDeltaPoint,
354 },
355 MarkPrice {
356 exchange: ExchangeId,
357 symbol: String,
358 point: MarkPricePoint,
359 },
360 FundingRate {
361 exchange: ExchangeId,
362 symbol: String,
363 point: FundingRatePoint,
364 },
365 OpenInterest {
366 exchange: ExchangeId,
367 symbol: String,
368 point: OpenInterestPoint,
369 },
370 Liquidation {
371 exchange: ExchangeId,
372 symbol: String,
373 point: LiquidationPoint,
374 },
375 BlockTrade {
377 exchange: ExchangeId,
378 symbol: String,
379 point: BlockTradePoint,
380 },
381 AuctionEvent {
382 exchange: ExchangeId,
383 symbol: String,
384 point: AuctionEventPoint,
385 },
386 IndexPrice {
387 exchange: ExchangeId,
388 symbol: String,
389 point: IndexPricePoint,
390 },
391 CompositeIndex {
392 exchange: ExchangeId,
393 symbol: String,
394 point: CompositeIndexPoint,
395 },
396 OptionGreeks {
397 exchange: ExchangeId,
398 symbol: String,
399 point: OptionGreeksPoint,
400 },
401 VolatilityIndex {
402 exchange: ExchangeId,
403 symbol: String,
404 point: VolatilityIndexPoint,
405 },
406 HistoricalVolatility {
407 exchange: ExchangeId,
408 symbol: String,
409 point: HistoricalVolatilityPoint,
410 },
411 LongShortRatio {
412 exchange: ExchangeId,
413 symbol: String,
414 point: LongShortRatioPoint,
415 },
416 TakerVolume {
417 exchange: ExchangeId,
418 symbol: String,
419 point: TakerVolumePoint,
420 },
421 LiquidationBucket {
422 exchange: ExchangeId,
423 symbol: String,
424 point: LiquidationBucketPoint,
425 },
426 Basis {
427 exchange: ExchangeId,
428 symbol: String,
429 point: BasisPoint,
430 },
431 InsuranceFund {
432 exchange: ExchangeId,
433 symbol: String,
434 point: InsuranceFundPoint,
435 },
436 OrderbookL3 {
437 exchange: ExchangeId,
438 symbol: String,
439 point: OrderbookL3Point,
440 },
441 SettlementEvent {
442 exchange: ExchangeId,
443 symbol: String,
444 point: SettlementEventPoint,
445 },
446 MarketWarning {
447 exchange: ExchangeId,
448 symbol: String,
449 point: MarketWarningPoint,
450 },
451 RiskLimit {
452 exchange: ExchangeId,
453 symbol: String,
454 point: RiskLimitPoint,
455 },
456 PredictedFunding {
457 exchange: ExchangeId,
458 symbol: String,
459 point: PredictedFundingPoint,
460 },
461 FundingSettlement {
462 exchange: ExchangeId,
463 symbol: String,
464 point: FundingSettlementPoint,
465 },
466 MarkPriceKline {
467 exchange: ExchangeId,
468 symbol: String,
469 timeframe: KlineInterval,
470 point: MarkPriceKlinePoint,
471 },
472 IndexPriceKline {
473 exchange: ExchangeId,
474 symbol: String,
475 timeframe: KlineInterval,
476 point: IndexPriceKlinePoint,
477 },
478 PremiumIndexKline {
479 exchange: ExchangeId,
480 symbol: String,
481 timeframe: KlineInterval,
482 point: PremiumIndexKlinePoint,
483 },
484 Footprint {
488 exchange: ExchangeId,
489 symbol: String,
490 point: FootprintPoint,
491 },
492 RenkoBar {
495 exchange: ExchangeId,
496 symbol: String,
497 point: RenkoBrickPoint,
498 },
499 PnfBar {
503 exchange: ExchangeId,
504 symbol: String,
505 point: PnfColumnPoint,
506 },
507 KagiBar {
509 exchange: ExchangeId,
510 symbol: String,
511 point: KagiSegmentPoint,
512 },
513 CvdLine {
516 exchange: ExchangeId,
517 symbol: String,
518 point: ScalarBarPoint,
519 },
520 ThreeLineBreakUpdate {
524 exchange: ExchangeId,
525 symbol: String,
526 point: ThreeLineBreakLinePoint,
527 },
528 TpoProfile {
533 exchange: ExchangeId,
534 symbol: String,
535 point: TpoSessionPoint,
536 },
537 ConnectorReady {
541 exchange: ExchangeId,
542 },
543 SymbolsLoaded {
547 exchange: ExchangeId,
548 account_type: AccountType,
549 symbols: Vec<SymbolInfo>,
550 },
551 OrderUpdate {
556 exchange: ExchangeId,
557 account_type: AccountType,
558 symbol: String,
559 point: OrderUpdatePoint,
560 },
561 BalanceUpdate {
564 exchange: ExchangeId,
565 account_type: AccountType,
566 symbol: String,
567 point: BalanceUpdatePoint,
568 },
569 PositionUpdate {
572 exchange: ExchangeId,
573 account_type: AccountType,
574 symbol: String,
575 point: PositionUpdatePoint,
576 },
577}
578
579impl Event {
580 pub fn exchange(&self) -> ExchangeId {
581 match self {
582 Event::Trade { exchange, .. } | Event::AggTrade { exchange, .. } |
583 Event::Bar { exchange, .. } | Event::Ticker { exchange, .. } |
584 Event::OrderbookSnapshot { exchange, .. } | Event::OrderbookDelta { exchange, .. } |
585 Event::MarkPrice { exchange, .. } |
586 Event::FundingRate { exchange, .. } | Event::OpenInterest { exchange, .. } |
587 Event::Liquidation { exchange, .. } |
588 Event::BlockTrade { exchange, .. } | Event::AuctionEvent { exchange, .. } |
589 Event::IndexPrice { exchange, .. } |
590 Event::CompositeIndex { exchange, .. } | Event::OptionGreeks { exchange, .. } |
591 Event::VolatilityIndex { exchange, .. } | Event::HistoricalVolatility { exchange, .. } |
592 Event::LongShortRatio { exchange, .. } |
593 Event::TakerVolume { exchange, .. } | Event::LiquidationBucket { exchange, .. } |
594 Event::Basis { exchange, .. } | Event::InsuranceFund { exchange, .. } |
595 Event::OrderbookL3 { exchange, .. } | Event::SettlementEvent { exchange, .. } |
596 Event::MarketWarning { exchange, .. } |
597 Event::RiskLimit { exchange, .. } | Event::PredictedFunding { exchange, .. } |
598 Event::FundingSettlement { exchange, .. } |
599 Event::MarkPriceKline { exchange, .. } | Event::IndexPriceKline { exchange, .. } |
600 Event::PremiumIndexKline { exchange, .. } |
601 Event::Footprint { exchange, .. } |
602 Event::RenkoBar { exchange, .. } | Event::PnfBar { exchange, .. } |
603 Event::KagiBar { exchange, .. } | Event::CvdLine { exchange, .. } |
604 Event::ThreeLineBreakUpdate { exchange, .. } |
605 Event::TpoProfile { exchange, .. } => *exchange,
606 Event::OrderUpdate { exchange, .. } | Event::BalanceUpdate { exchange, .. } |
607 Event::PositionUpdate { exchange, .. } => *exchange,
608 Event::ConnectorReady { exchange } => *exchange,
609 Event::SymbolsLoaded { exchange, .. } => *exchange,
610 }
611 }
612 pub fn symbol(&self) -> &str {
613 match self {
614 Event::Trade { symbol, .. } | Event::AggTrade { symbol, .. } |
615 Event::Bar { symbol, .. } | Event::Ticker { symbol, .. } |
616 Event::OrderbookSnapshot { symbol, .. } | Event::OrderbookDelta { symbol, .. } |
617 Event::MarkPrice { symbol, .. } |
618 Event::FundingRate { symbol, .. } | Event::OpenInterest { symbol, .. } |
619 Event::Liquidation { symbol, .. } |
620 Event::BlockTrade { symbol, .. } | Event::AuctionEvent { symbol, .. } |
621 Event::IndexPrice { symbol, .. } |
622 Event::CompositeIndex { symbol, .. } | Event::OptionGreeks { symbol, .. } |
623 Event::VolatilityIndex { symbol, .. } | Event::HistoricalVolatility { symbol, .. } |
624 Event::LongShortRatio { symbol, .. } |
625 Event::TakerVolume { symbol, .. } | Event::LiquidationBucket { symbol, .. } |
626 Event::Basis { symbol, .. } | Event::InsuranceFund { symbol, .. } |
627 Event::OrderbookL3 { symbol, .. } | Event::SettlementEvent { symbol, .. } |
628 Event::MarketWarning { symbol, .. } |
629 Event::RiskLimit { symbol, .. } | Event::PredictedFunding { symbol, .. } |
630 Event::FundingSettlement { symbol, .. } |
631 Event::MarkPriceKline { symbol, .. } | Event::IndexPriceKline { symbol, .. } |
632 Event::PremiumIndexKline { symbol, .. } |
633 Event::Footprint { symbol, .. } |
634 Event::RenkoBar { symbol, .. } | Event::PnfBar { symbol, .. } |
635 Event::KagiBar { symbol, .. } | Event::CvdLine { symbol, .. } |
636 Event::ThreeLineBreakUpdate { symbol, .. } |
637 Event::TpoProfile { symbol, .. } => symbol,
638 Event::OrderUpdate { symbol, .. } | Event::BalanceUpdate { symbol, .. } |
639 Event::PositionUpdate { symbol, .. } => symbol,
640 Event::ConnectorReady { .. } | Event::SymbolsLoaded { .. } => "",
642 }
643 }
644
645 pub(crate) fn set_symbol(&mut self, new_symbol: String) {
653 match self {
654 Event::Trade { symbol, .. }
655 | Event::AggTrade { symbol, .. }
656 | Event::Bar { symbol, .. }
657 | Event::Ticker { symbol, .. }
658 | Event::OrderbookSnapshot { symbol, .. }
659 | Event::OrderbookDelta { symbol, .. }
660 | Event::MarkPrice { symbol, .. }
661 | Event::FundingRate { symbol, .. }
662 | Event::OpenInterest { symbol, .. }
663 | Event::Liquidation { symbol, .. }
664 | Event::BlockTrade { symbol, .. }
665 | Event::AuctionEvent { symbol, .. }
666 | Event::IndexPrice { symbol, .. }
667 | Event::CompositeIndex { symbol, .. }
668 | Event::OptionGreeks { symbol, .. }
669 | Event::VolatilityIndex { symbol, .. }
670 | Event::HistoricalVolatility { symbol, .. }
671 | Event::LongShortRatio { symbol, .. }
672 | Event::TakerVolume { symbol, .. }
673 | Event::LiquidationBucket { symbol, .. }
674 | Event::Basis { symbol, .. }
675 | Event::InsuranceFund { symbol, .. }
676 | Event::OrderbookL3 { symbol, .. }
677 | Event::SettlementEvent { symbol, .. }
678 | Event::MarketWarning { symbol, .. }
679 | Event::RiskLimit { symbol, .. }
680 | Event::PredictedFunding { symbol, .. }
681 | Event::FundingSettlement { symbol, .. }
682 | Event::MarkPriceKline { symbol, .. }
683 | Event::IndexPriceKline { symbol, .. }
684 | Event::PremiumIndexKline { symbol, .. }
685 | Event::Footprint { symbol, .. }
686 | Event::RenkoBar { symbol, .. }
687 | Event::PnfBar { symbol, .. }
688 | Event::KagiBar { symbol, .. }
689 | Event::CvdLine { symbol, .. }
690 | Event::ThreeLineBreakUpdate { symbol, .. }
691 | Event::TpoProfile { symbol, .. }
692 | Event::OrderUpdate { symbol, .. }
693 | Event::BalanceUpdate { symbol, .. }
694 | Event::PositionUpdate { symbol, .. } => *symbol = new_symbol,
695 Event::ConnectorReady { .. } | Event::SymbolsLoaded { .. } => {}
697 }
698 }
699 pub fn timestamp_ms(&self) -> i64 {
700 use crate::series::DataPoint;
701 match self {
702 Event::Trade { point, .. } => point.timestamp_ms(),
703 Event::AggTrade { point, .. } => point.timestamp_ms(),
704 Event::Bar { point, .. } => point.timestamp_ms(),
705 Event::Ticker { point, .. } => point.timestamp_ms(),
706 Event::OrderbookSnapshot { point, .. } => point.timestamp_ms(),
707 Event::OrderbookDelta { point, .. } => point.timestamp_ms(),
708 Event::MarkPrice { point, .. } => point.timestamp_ms(),
709 Event::FundingRate { point, .. } => point.timestamp_ms(),
710 Event::OpenInterest { point, .. } => point.timestamp_ms(),
711 Event::Liquidation { point, .. } => point.timestamp_ms(),
712 Event::BlockTrade { point, .. } => point.timestamp_ms(),
713 Event::AuctionEvent { point, .. } => point.timestamp_ms(),
714 Event::IndexPrice { point, .. } => point.timestamp_ms(),
715 Event::CompositeIndex { point, .. } => point.timestamp_ms(),
716 Event::OptionGreeks { point, .. } => point.timestamp_ms(),
717 Event::VolatilityIndex { point, .. } => point.timestamp_ms(),
718 Event::HistoricalVolatility { point, .. } => point.timestamp_ms(),
719 Event::LongShortRatio { point, .. } => point.timestamp_ms(),
720 Event::TakerVolume { point, .. } => point.timestamp_ms(),
721 Event::LiquidationBucket { point, .. } => point.timestamp_ms(),
722 Event::Basis { point, .. } => point.timestamp_ms(),
723 Event::InsuranceFund { point, .. } => point.timestamp_ms(),
724 Event::OrderbookL3 { point, .. } => point.timestamp_ms(),
725 Event::SettlementEvent { point, .. } => point.timestamp_ms(),
726 Event::MarketWarning { point, .. } => point.timestamp_ms(),
727 Event::RiskLimit { point, .. } => point.timestamp_ms(),
728 Event::PredictedFunding { point, .. } => point.timestamp_ms(),
729 Event::FundingSettlement { point, .. } => point.timestamp_ms(),
730 Event::MarkPriceKline { point, .. } => point.timestamp_ms(),
731 Event::IndexPriceKline { point, .. } => point.timestamp_ms(),
732 Event::PremiumIndexKline { point, .. } => point.timestamp_ms(),
733 Event::Footprint { point, .. } => point.timestamp_ms(),
734 Event::RenkoBar { point, .. } => point.timestamp_ms(),
735 Event::PnfBar { point, .. } => point.timestamp_ms(),
736 Event::KagiBar { point, .. } => point.timestamp_ms(),
737 Event::CvdLine { point, .. } => point.timestamp_ms(),
738 Event::ThreeLineBreakUpdate { point, .. } => point.timestamp_ms(),
739 Event::TpoProfile { point, .. } => point.timestamp_ms(),
740 Event::OrderUpdate { point, .. } => point.timestamp_ms(),
741 Event::BalanceUpdate { point, .. } => point.timestamp_ms(),
742 Event::PositionUpdate { point, .. } => point.timestamp_ms(),
743 Event::ConnectorReady { .. } | Event::SymbolsLoaded { .. } => {
745 chrono::Utc::now().timestamp_millis()
746 }
747 }
748 }
749}
750
751#[derive(Debug, Clone)]
757pub struct WarmupReport {
758 pub ok: Vec<ExchangeId>,
761 pub failed: Vec<(ExchangeId, String)>,
763}
764
765pub struct SubscriptionHandle {
769 pub(crate) rx: tokio::sync::mpsc::UnboundedReceiver<Event>,
770 pub(crate) _refs: Vec<MultiplexRef>,
771}
772
773impl std::fmt::Debug for SubscriptionHandle {
774 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
775 f.debug_struct("SubscriptionHandle").finish()
776 }
777}
778
779impl SubscriptionHandle {
780 pub async fn recv(&mut self) -> Option<Event> {
781 self.rx.recv().await
782 }
783}
784
785#[derive(Debug)]
792pub struct FailedStream {
793 pub exchange: ExchangeId,
794 pub account_type: AccountType,
795 pub symbol: String,
797 pub stream: Stream,
798 pub error: crate::StationError,
799}
800
801pub struct SubscribeReport {
814 pub handle: SubscriptionHandle,
815 pub ok: Vec<SeriesKey>,
816 pub failed: Vec<FailedStream>,
817 pub seed_outcomes: Vec<(SeriesKey, crate::SeedOutcome)>,
828}
829
830impl SubscribeReport {
831 pub fn is_fully_ok(&self) -> bool { self.failed.is_empty() }
833 pub fn total(&self) -> usize { self.ok.len() + self.failed.len() }
835
836 pub(crate) fn take_refs_into(mut self, dest: &mut Vec<MultiplexRef>) -> Self {
846 dest.extend(std::mem::take(&mut self.handle._refs));
847 self
848 }
849}
850
851impl std::fmt::Debug for SubscribeReport {
852 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
853 f.debug_struct("SubscribeReport")
854 .field("ok", &self.ok.len())
855 .field("failed", &self.failed.len())
856 .field("seed_outcomes", &self.seed_outcomes.len())
857 .finish()
858 }
859}
860
861pub(crate) struct MultiplexRef {
862 pub(crate) station: std::sync::Weak<crate::station::StationInner>,
863 pub(crate) key: SeriesKey,
864}
865
866impl Drop for MultiplexRef {
867 fn drop(&mut self) {
868 if let Some(inner) = self.station.upgrade() {
869 inner.release_consumer(&self.key);
870 }
871 }
872}