1use serde::{Deserialize, Serialize};
16use std::collections::HashSet;
17use std::fmt::{Debug, Display};
18
19#[derive(Clone, Deserialize, Serialize, PartialEq, Eq, Default, Hash)]
24#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
25pub enum StreamingMarketField {
26 MidOpen,
28 High,
30 Low,
32 Change,
34 ChangePct,
36 UpdateTime,
38 MarketDelay,
40 MarketState,
42 Bid,
44 #[default]
46 Offer,
47}
48
49impl Debug for StreamingMarketField {
50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51 let field_name = match self {
52 StreamingMarketField::MidOpen => "MID_OPEN",
53 StreamingMarketField::High => "HIGH",
54 StreamingMarketField::Low => "LOW",
55 StreamingMarketField::Change => "CHANGE",
56 StreamingMarketField::ChangePct => "CHANGE_PCT",
57 StreamingMarketField::UpdateTime => "UPDATE_TIME",
58 StreamingMarketField::MarketDelay => "MARKET_DELAY",
59 StreamingMarketField::MarketState => "MARKET_STATE",
60 StreamingMarketField::Bid => "BID",
61 StreamingMarketField::Offer => "OFFER",
62 };
63 write!(f, "{}", field_name)
64 }
65}
66
67impl Display for StreamingMarketField {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 write!(f, "{:?}", self)
70 }
71}
72
73pub(crate) fn get_streaming_market_fields(fields: &HashSet<StreamingMarketField>) -> Vec<String> {
84 fields.iter().map(|field| field.to_string()).collect()
87}
88
89#[derive(Clone, Deserialize, Serialize, PartialEq, Eq, Default, Hash)]
94#[serde(rename_all = "UPPERCASE")]
95pub enum StreamingPriceField {
96 #[serde(rename = "MID_OPEN")]
98 MidOpen,
99 High,
101 Low,
103 BidQuoteId,
105 AskQuoteId,
107 BidPrice1,
109 BidPrice2,
111 BidPrice3,
113 BidPrice4,
115 BidPrice5,
117 AskPrice1,
119 AskPrice2,
121 AskPrice3,
123 AskPrice4,
125 #[default]
127 AskPrice5,
128 BidSize1,
130 BidSize2,
132 BidSize3,
134 BidSize4,
136 BidSize5,
138 AskSize1,
140 AskSize2,
142 AskSize3,
144 AskSize4,
146 AskSize5,
148 Currency0,
150 Currency1,
152 C1BidSize1,
154 C1BidSize2,
156 C1BidSize3,
158 C1BidSize4,
160 C1BidSize5,
162 C1AskSize1,
164 C1AskSize2,
166 C1AskSize3,
168 C1AskSize4,
170 C1AskSize5,
172 Currency2,
174 C2BidSize1,
176 C2BidSize2,
178 C2BidSize3,
180 C2BidSize4,
182 C2BidSize5,
184 C2AskSize1,
186 C2AskSize2,
188 C2AskSize3,
190 C2AskSize4,
192 C2AskSize5,
194 Currency3,
196 C3BidSize1,
198 C3BidSize2,
200 C3BidSize3,
202 C3BidSize4,
204 C3BidSize5,
206 C3AskSize1,
208 C3AskSize2,
210 C3AskSize3,
212 C3AskSize4,
214 C3AskSize5,
216 Currency4,
218 C4BidSize1,
220 C4BidSize2,
222 C4BidSize3,
224 C4BidSize4,
226 C4BidSize5,
228 C4AskSize1,
230 C4AskSize2,
232 C4AskSize3,
234 C4AskSize4,
236 C4AskSize5,
238 Currency5,
240 C5BidSize1,
242 C5BidSize2,
244 C5BidSize3,
246 C5BidSize4,
248 C5BidSize5,
250 C5AskSize1,
252 C5AskSize2,
254 C5AskSize3,
256 C5AskSize4,
258 C5AskSize5,
260 Timestamp,
262 #[serde(rename = "DLG_FLAG")]
264 DlgFlag,
265 #[serde(rename = "NET_CHG")]
267 NetChg,
268 #[serde(rename = "NET_CHG_PCT")]
270 NetChgPct,
271 Delay,
273}
274
275impl Debug for StreamingPriceField {
276 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
277 let field_name = match self {
278 StreamingPriceField::MidOpen => "MID_OPEN",
279 StreamingPriceField::High => "HIGH",
280 StreamingPriceField::Low => "LOW",
281 StreamingPriceField::BidQuoteId => "BIDQUOTEID",
282 StreamingPriceField::AskQuoteId => "ASKQUOTEID",
283 StreamingPriceField::BidPrice1 => "BIDPRICE1",
284 StreamingPriceField::BidPrice2 => "BIDPRICE2",
285 StreamingPriceField::BidPrice3 => "BIDPRICE3",
286 StreamingPriceField::BidPrice4 => "BIDPRICE4",
287 StreamingPriceField::BidPrice5 => "BIDPRICE5",
288 StreamingPriceField::AskPrice1 => "ASKPRICE1",
289 StreamingPriceField::AskPrice2 => "ASKPRICE2",
290 StreamingPriceField::AskPrice3 => "ASKPRICE3",
291 StreamingPriceField::AskPrice4 => "ASKPRICE4",
292 StreamingPriceField::AskPrice5 => "ASKPRICE5",
293 StreamingPriceField::BidSize1 => "BIDSIZE1",
294 StreamingPriceField::BidSize2 => "BIDSIZE2",
295 StreamingPriceField::BidSize3 => "BIDSIZE3",
296 StreamingPriceField::BidSize4 => "BIDSIZE4",
297 StreamingPriceField::BidSize5 => "BIDSIZE5",
298 StreamingPriceField::AskSize1 => "ASKSIZE1",
299 StreamingPriceField::AskSize2 => "ASKSIZE2",
300 StreamingPriceField::AskSize3 => "ASKSIZE3",
301 StreamingPriceField::AskSize4 => "ASKSIZE4",
302 StreamingPriceField::AskSize5 => "ASKSIZE5",
303 StreamingPriceField::Currency0 => "CURRENCY0",
304 StreamingPriceField::Currency1 => "CURRENCY1",
305 StreamingPriceField::C1BidSize1 => "C1BIDSIZE1",
306 StreamingPriceField::C1BidSize2 => "C1BIDSIZE2",
307 StreamingPriceField::C1BidSize3 => "C1BIDSIZE3",
308 StreamingPriceField::C1BidSize4 => "C1BIDSIZE4",
309 StreamingPriceField::C1BidSize5 => "C1BIDSIZE5",
310 StreamingPriceField::C1AskSize1 => "C1ASKSIZE1",
311 StreamingPriceField::C1AskSize2 => "C1ASKSIZE2",
312 StreamingPriceField::C1AskSize3 => "C1ASKSIZE3",
313 StreamingPriceField::C1AskSize4 => "C1ASKSIZE4",
314 StreamingPriceField::C1AskSize5 => "C1ASKSIZE5",
315 StreamingPriceField::Currency2 => "CURRENCY2",
316 StreamingPriceField::C2BidSize1 => "C2BIDSIZE1",
317 StreamingPriceField::C2BidSize2 => "C2BIDSIZE2",
318 StreamingPriceField::C2BidSize3 => "C2BIDSIZE3",
319 StreamingPriceField::C2BidSize4 => "C2BIDSIZE4",
320 StreamingPriceField::C2BidSize5 => "C2BIDSIZE5",
321 StreamingPriceField::C2AskSize1 => "C2ASKSIZE1",
322 StreamingPriceField::C2AskSize2 => "C2ASKSIZE2",
323 StreamingPriceField::C2AskSize3 => "C2ASKSIZE3",
324 StreamingPriceField::C2AskSize4 => "C2ASKSIZE4",
325 StreamingPriceField::C2AskSize5 => "C2ASKSIZE5",
326 StreamingPriceField::Currency3 => "CURRENCY3",
327 StreamingPriceField::C3BidSize1 => "C3BIDSIZE1",
328 StreamingPriceField::C3BidSize2 => "C3BIDSIZE2",
329 StreamingPriceField::C3BidSize3 => "C3BIDSIZE3",
330 StreamingPriceField::C3BidSize4 => "C3BIDSIZE4",
331 StreamingPriceField::C3BidSize5 => "C3BIDSIZE5",
332 StreamingPriceField::C3AskSize1 => "C3ASKSIZE1",
333 StreamingPriceField::C3AskSize2 => "C3ASKSIZE2",
334 StreamingPriceField::C3AskSize3 => "C3ASKSIZE3",
335 StreamingPriceField::C3AskSize4 => "C3ASKSIZE4",
336 StreamingPriceField::C3AskSize5 => "C3ASKSIZE5",
337 StreamingPriceField::Currency4 => "CURRENCY4",
338 StreamingPriceField::C4BidSize1 => "C4BIDSIZE1",
339 StreamingPriceField::C4BidSize2 => "C4BIDSIZE2",
340 StreamingPriceField::C4BidSize3 => "C4BIDSIZE3",
341 StreamingPriceField::C4BidSize4 => "C4BIDSIZE4",
342 StreamingPriceField::C4BidSize5 => "C4BIDSIZE5",
343 StreamingPriceField::C4AskSize1 => "C4ASKSIZE1",
344 StreamingPriceField::C4AskSize2 => "C4ASKSIZE2",
345 StreamingPriceField::C4AskSize3 => "C4ASKSIZE3",
346 StreamingPriceField::C4AskSize4 => "C4ASKSIZE4",
347 StreamingPriceField::C4AskSize5 => "C4ASKSIZE5",
348 StreamingPriceField::Currency5 => "CURRENCY5",
349 StreamingPriceField::C5BidSize1 => "C5BIDSIZE1",
350 StreamingPriceField::C5BidSize2 => "C5BIDSIZE2",
351 StreamingPriceField::C5BidSize3 => "C5BIDSIZE3",
352 StreamingPriceField::C5BidSize4 => "C5BIDSIZE4",
353 StreamingPriceField::C5BidSize5 => "C5BIDSIZE5",
354 StreamingPriceField::C5AskSize1 => "C5ASKSIZE1",
355 StreamingPriceField::C5AskSize2 => "C5ASKSIZE2",
356 StreamingPriceField::C5AskSize3 => "C5ASKSIZE3",
357 StreamingPriceField::C5AskSize4 => "C5ASKSIZE4",
358 StreamingPriceField::C5AskSize5 => "C5ASKSIZE5",
359 StreamingPriceField::Timestamp => "TIMESTAMP",
360 StreamingPriceField::DlgFlag => "DLG_FLAG",
361 StreamingPriceField::NetChg => "NET_CHG",
362 StreamingPriceField::NetChgPct => "NET_CHG_PCT",
363 StreamingPriceField::Delay => "DELAY",
364 };
365 write!(f, "{}", field_name)
366 }
367}
368
369impl Display for StreamingPriceField {
370 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
371 write!(f, "{:?}", self)
372 }
373}
374
375pub(crate) fn get_streaming_price_fields(fields: &HashSet<StreamingPriceField>) -> Vec<String> {
386 fields.iter().map(|field| field.to_string()).collect()
390}
391
392#[derive(Clone, Deserialize, Serialize, PartialEq, Eq, Default, Hash)]
397#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
398pub enum StreamingAccountDataField {
399 #[default]
401 Pnl,
402 Deposit,
404 AvailableCash,
406 PnlLr,
408 PnlNlr,
410 Funds,
412 Margin,
414 MarginLr,
416 MarginNlr,
418 AvailableToDeal,
420 Equity,
422 EquityUsed,
424}
425
426impl Debug for StreamingAccountDataField {
427 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
428 let field_name = match self {
429 StreamingAccountDataField::Pnl => "PNL",
430 StreamingAccountDataField::Deposit => "DEPOSIT",
431 StreamingAccountDataField::AvailableCash => "AVAILABLE_CASH",
432 StreamingAccountDataField::PnlLr => "PNL_LR",
433 StreamingAccountDataField::PnlNlr => "PNL_NLR",
434 StreamingAccountDataField::Funds => "FUNDS",
435 StreamingAccountDataField::Margin => "MARGIN",
436 StreamingAccountDataField::MarginLr => "MARGIN_LR",
437 StreamingAccountDataField::MarginNlr => "MARGIN_NLR",
438 StreamingAccountDataField::AvailableToDeal => "AVAILABLE_TO_DEAL",
439 StreamingAccountDataField::Equity => "EQUITY",
440 StreamingAccountDataField::EquityUsed => "EQUITY_USED",
441 };
442 write!(f, "{}", field_name)
443 }
444}
445
446impl Display for StreamingAccountDataField {
447 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
448 write!(f, "{:?}", self)
449 }
450}
451
452pub(crate) fn get_streaming_account_data_fields(
463 fields: &HashSet<StreamingAccountDataField>,
464) -> Vec<String> {
465 fields.iter().map(|field| field.to_string()).collect()
468}
469
470#[derive(Clone, Deserialize, Serialize, PartialEq, Eq, Default, Hash)]
475#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
476pub enum StreamingChartField {
477 #[default]
480 Ltv,
481 Ttv,
483 Utm,
485 DayOpenMid,
487 DayNetChgMid,
489 DayPercChgMid,
491 DayHigh,
493 DayLow,
495
496 Bid,
499 Ofr,
501 Ltp,
503
504 OfrOpen,
507 OfrHigh,
509 OfrLow,
511 OfrClose,
513 BidOpen,
515 BidHigh,
517 BidLow,
519 BidClose,
521 LtpOpen,
523 LtpHigh,
525 LtpLow,
527 LtpClose,
529 ConsEnd,
531 ConsTickCount,
533}
534
535impl std::fmt::Debug for StreamingChartField {
536 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
537 let name = match self {
538 StreamingChartField::Ltv => "LTV",
539 StreamingChartField::Ttv => "TTV",
540 StreamingChartField::Utm => "UTM",
541 StreamingChartField::DayOpenMid => "DAY_OPEN_MID",
542 StreamingChartField::DayNetChgMid => "DAY_NET_CHG_MID",
543 StreamingChartField::DayPercChgMid => "DAY_PERC_CHG_MID",
544 StreamingChartField::DayHigh => "DAY_HIGH",
545 StreamingChartField::DayLow => "DAY_LOW",
546
547 StreamingChartField::Bid => "BID",
548 StreamingChartField::Ofr => "OFR",
549 StreamingChartField::Ltp => "LTP",
550
551 StreamingChartField::OfrOpen => "OFR_OPEN",
552 StreamingChartField::OfrHigh => "OFR_HIGH",
553 StreamingChartField::OfrLow => "OFR_LOW",
554 StreamingChartField::OfrClose => "OFR_CLOSE",
555 StreamingChartField::BidOpen => "BID_OPEN",
556 StreamingChartField::BidHigh => "BID_HIGH",
557 StreamingChartField::BidLow => "BID_LOW",
558 StreamingChartField::BidClose => "BID_CLOSE",
559 StreamingChartField::LtpOpen => "LTP_OPEN",
560 StreamingChartField::LtpHigh => "LTP_HIGH",
561 StreamingChartField::LtpLow => "LTP_LOW",
562 StreamingChartField::LtpClose => "LTP_CLOSE",
563 StreamingChartField::ConsEnd => "CONS_END",
564 StreamingChartField::ConsTickCount => "CONS_TICK_COUNT",
565 };
566 write!(f, "{}", name)
567 }
568}
569
570impl std::fmt::Display for StreamingChartField {
571 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
572 write!(f, "{:?}", self)
573 }
574}
575
576pub(crate) fn get_streaming_chart_fields(fields: &HashSet<StreamingChartField>) -> Vec<String> {
587 fields.iter().map(|field| field.to_string()).collect()
590}
591
592#[cfg(test)]
593mod tests {
594 use super::*;
595
596 #[test]
597 fn test_streaming_market_field_default() {
598 let field = StreamingMarketField::default();
599 assert_eq!(field, StreamingMarketField::Offer);
600 }
601
602 #[test]
603 fn test_streaming_market_field_debug() {
604 assert_eq!(format!("{:?}", StreamingMarketField::Bid), "BID");
605 assert_eq!(format!("{:?}", StreamingMarketField::Offer), "OFFER");
606 assert_eq!(format!("{:?}", StreamingMarketField::High), "HIGH");
607 assert_eq!(format!("{:?}", StreamingMarketField::Low), "LOW");
608 assert_eq!(format!("{:?}", StreamingMarketField::Change), "CHANGE");
609 assert_eq!(
610 format!("{:?}", StreamingMarketField::ChangePct),
611 "CHANGE_PCT"
612 );
613 assert_eq!(
614 format!("{:?}", StreamingMarketField::UpdateTime),
615 "UPDATE_TIME"
616 );
617 assert_eq!(
618 format!("{:?}", StreamingMarketField::MarketDelay),
619 "MARKET_DELAY"
620 );
621 assert_eq!(
622 format!("{:?}", StreamingMarketField::MarketState),
623 "MARKET_STATE"
624 );
625 assert_eq!(format!("{:?}", StreamingMarketField::MidOpen), "MID_OPEN");
626 }
627
628 #[test]
629 fn test_streaming_market_field_display() {
630 assert_eq!(format!("{}", StreamingMarketField::Bid), "BID");
631 assert_eq!(format!("{}", StreamingMarketField::Offer), "OFFER");
632 }
633
634 #[test]
635 fn test_get_streaming_market_fields_empty() {
636 let fields: HashSet<StreamingMarketField> = HashSet::new();
637 let result = get_streaming_market_fields(&fields);
638 assert!(result.is_empty());
639 }
640
641 #[test]
642 fn test_get_streaming_market_fields_single() {
643 let mut fields = HashSet::new();
644 fields.insert(StreamingMarketField::Bid);
645 let result = get_streaming_market_fields(&fields);
646 assert_eq!(result.len(), 1);
647 assert!(result.contains(&"BID".to_string()));
648 }
649
650 #[test]
651 fn test_get_streaming_market_fields_multiple() {
652 let mut fields = HashSet::new();
653 fields.insert(StreamingMarketField::Bid);
654 fields.insert(StreamingMarketField::Offer);
655 fields.insert(StreamingMarketField::High);
656 let result = get_streaming_market_fields(&fields);
657 assert_eq!(result.len(), 3);
658 assert!(result.contains(&"BID".to_string()));
659 assert!(result.contains(&"OFFER".to_string()));
660 assert!(result.contains(&"HIGH".to_string()));
661 }
662
663 #[test]
664 fn test_get_streaming_account_data_fields_wire_names() {
665 let mut fields = HashSet::new();
669 fields.insert(StreamingAccountDataField::Pnl);
670 fields.insert(StreamingAccountDataField::AvailableCash);
671 fields.insert(StreamingAccountDataField::PnlLr);
672 let result = get_streaming_account_data_fields(&fields);
673 assert_eq!(result.len(), 3);
674 assert!(result.contains(&"PNL".to_string()));
675 assert!(result.contains(&"AVAILABLE_CASH".to_string()));
676 assert!(result.contains(&"PNL_LR".to_string()));
677 }
678
679 #[test]
680 fn test_streaming_price_field_default() {
681 let field = StreamingPriceField::default();
682 assert_eq!(field, StreamingPriceField::AskPrice5);
683 }
684
685 #[test]
686 fn test_streaming_price_field_debug() {
687 assert_eq!(format!("{:?}", StreamingPriceField::High), "HIGH");
688 assert_eq!(format!("{:?}", StreamingPriceField::Low), "LOW");
689 assert_eq!(format!("{:?}", StreamingPriceField::MidOpen), "MID_OPEN");
690 assert_eq!(format!("{:?}", StreamingPriceField::BidPrice1), "BIDPRICE1");
691 assert_eq!(format!("{:?}", StreamingPriceField::AskPrice1), "ASKPRICE1");
692 }
693
694 #[test]
695 fn test_streaming_price_field_display() {
696 assert_eq!(format!("{}", StreamingPriceField::High), "HIGH");
697 assert_eq!(format!("{}", StreamingPriceField::BidPrice1), "BIDPRICE1");
698 }
699
700 #[test]
701 fn test_streaming_account_field_default() {
702 let field = StreamingAccountDataField::default();
703 assert_eq!(field, StreamingAccountDataField::Pnl);
704 }
705
706 #[test]
707 fn test_streaming_account_field_debug() {
708 assert_eq!(format!("{:?}", StreamingAccountDataField::Pnl), "PNL");
709 assert_eq!(
710 format!("{:?}", StreamingAccountDataField::Deposit),
711 "DEPOSIT"
712 );
713 assert_eq!(format!("{:?}", StreamingAccountDataField::Margin), "MARGIN");
714 assert_eq!(format!("{:?}", StreamingAccountDataField::Equity), "EQUITY");
715 }
716
717 #[test]
718 fn test_streaming_account_field_display() {
719 assert_eq!(format!("{}", StreamingAccountDataField::Pnl), "PNL");
720 assert_eq!(format!("{}", StreamingAccountDataField::Equity), "EQUITY");
721 }
722
723 #[test]
724 fn test_get_streaming_account_fields_empty() {
725 let fields: HashSet<StreamingAccountDataField> = HashSet::new();
726 let result = get_streaming_account_data_fields(&fields);
727 assert!(result.is_empty());
728 }
729
730 #[test]
731 fn test_get_streaming_account_fields_multiple() {
732 let mut fields = HashSet::new();
733 fields.insert(StreamingAccountDataField::Pnl);
734 fields.insert(StreamingAccountDataField::Equity);
735 let result = get_streaming_account_data_fields(&fields);
736 assert_eq!(result.len(), 2);
737 assert!(result.contains(&"PNL".to_string()));
738 assert!(result.contains(&"EQUITY".to_string()));
739 }
740
741 #[test]
742 fn test_streaming_chart_field_default() {
743 let field = StreamingChartField::default();
744 assert_eq!(field, StreamingChartField::Ltv);
745 }
746
747 #[test]
748 fn test_streaming_chart_field_debug() {
749 assert_eq!(format!("{:?}", StreamingChartField::Bid), "BID");
750 assert_eq!(format!("{:?}", StreamingChartField::Ofr), "OFR");
751 assert_eq!(format!("{:?}", StreamingChartField::Ltp), "LTP");
752 assert_eq!(format!("{:?}", StreamingChartField::Ltv), "LTV");
753 assert_eq!(format!("{:?}", StreamingChartField::Utm), "UTM");
754 assert_eq!(format!("{:?}", StreamingChartField::DayHigh), "DAY_HIGH");
755 assert_eq!(format!("{:?}", StreamingChartField::DayLow), "DAY_LOW");
756 }
757
758 #[test]
759 fn test_streaming_chart_field_display() {
760 assert_eq!(format!("{}", StreamingChartField::Bid), "BID");
761 assert_eq!(format!("{}", StreamingChartField::Ofr), "OFR");
762 }
763
764 #[test]
765 fn test_get_streaming_chart_fields_empty() {
766 let fields: HashSet<StreamingChartField> = HashSet::new();
767 let result = get_streaming_chart_fields(&fields);
768 assert!(result.is_empty());
769 }
770
771 #[test]
772 fn test_get_streaming_chart_fields_multiple() {
773 let mut fields = HashSet::new();
774 fields.insert(StreamingChartField::Bid);
775 fields.insert(StreamingChartField::Ofr);
776 fields.insert(StreamingChartField::Ltp);
777 let result = get_streaming_chart_fields(&fields);
778 assert_eq!(result.len(), 3);
779 assert!(result.contains(&"BID".to_string()));
780 assert!(result.contains(&"OFR".to_string()));
781 assert!(result.contains(&"LTP".to_string()));
782 }
783
784 #[test]
785 fn test_streaming_market_field_serialization() {
786 let field = StreamingMarketField::Bid;
787 let json = serde_json::to_string(&field).expect("serialize failed");
788 assert_eq!(json, "\"BID\"");
789
790 let deserialized: StreamingMarketField =
791 serde_json::from_str(&json).expect("deserialize failed");
792 assert_eq!(deserialized, StreamingMarketField::Bid);
793 }
794
795 #[test]
796 fn test_streaming_account_field_serialization() {
797 let field = StreamingAccountDataField::Pnl;
798 let json = serde_json::to_string(&field).expect("serialize failed");
799 assert_eq!(json, "\"PNL\"");
800
801 let deserialized: StreamingAccountDataField =
802 serde_json::from_str(&json).expect("deserialize failed");
803 assert_eq!(deserialized, StreamingAccountDataField::Pnl);
804 }
805
806 #[test]
807 fn test_streaming_chart_field_serialization() {
808 let field = StreamingChartField::Bid;
809 let json = serde_json::to_string(&field).expect("serialize failed");
810 assert_eq!(json, "\"BID\"");
811
812 let deserialized: StreamingChartField =
813 serde_json::from_str(&json).expect("deserialize failed");
814 assert_eq!(deserialized, StreamingChartField::Bid);
815 }
816
817 #[test]
818 fn test_streaming_market_field_equality() {
819 let field1 = StreamingMarketField::Bid;
820 let field2 = StreamingMarketField::Bid;
821 let field3 = StreamingMarketField::Offer;
822
823 assert_eq!(field1, field2);
824 assert_ne!(field1, field3);
825 }
826
827 #[test]
828 fn test_streaming_market_field_hash() {
829 let mut set = HashSet::new();
830 set.insert(StreamingMarketField::Bid);
831 set.insert(StreamingMarketField::Bid); assert_eq!(set.len(), 1);
834 }
835
836 #[test]
837 fn test_streaming_market_field_clone() {
838 let field = StreamingMarketField::High;
839 let cloned = field.clone();
840 assert_eq!(field, cloned);
841 }
842
843 fn assert_wire_name<T>(field: &T, expected: &str)
848 where
849 T: Serialize + Debug + Display,
850 {
851 let serialized = serde_json::to_string(field).expect("serialize failed");
852 assert_eq!(serialized, format!("\"{expected}\""));
853 assert_eq!(format!("{field:?}"), expected);
854 assert_eq!(format!("{field}"), expected);
855 }
856
857 #[test]
858 fn test_streaming_market_field_all_variants_wire_names() {
859 for (field, expected) in [
860 (StreamingMarketField::MidOpen, "MID_OPEN"),
861 (StreamingMarketField::High, "HIGH"),
862 (StreamingMarketField::Low, "LOW"),
863 (StreamingMarketField::Change, "CHANGE"),
864 (StreamingMarketField::ChangePct, "CHANGE_PCT"),
865 (StreamingMarketField::UpdateTime, "UPDATE_TIME"),
866 (StreamingMarketField::MarketDelay, "MARKET_DELAY"),
867 (StreamingMarketField::MarketState, "MARKET_STATE"),
868 (StreamingMarketField::Bid, "BID"),
869 (StreamingMarketField::Offer, "OFFER"),
870 ] {
871 assert_wire_name(&field, expected);
872 }
873 }
874
875 #[test]
876 fn test_streaming_account_field_all_variants_wire_names() {
877 for (field, expected) in [
878 (StreamingAccountDataField::Pnl, "PNL"),
879 (StreamingAccountDataField::Deposit, "DEPOSIT"),
880 (StreamingAccountDataField::AvailableCash, "AVAILABLE_CASH"),
881 (StreamingAccountDataField::PnlLr, "PNL_LR"),
882 (StreamingAccountDataField::PnlNlr, "PNL_NLR"),
883 (StreamingAccountDataField::Funds, "FUNDS"),
884 (StreamingAccountDataField::Margin, "MARGIN"),
885 (StreamingAccountDataField::MarginLr, "MARGIN_LR"),
886 (StreamingAccountDataField::MarginNlr, "MARGIN_NLR"),
887 (
888 StreamingAccountDataField::AvailableToDeal,
889 "AVAILABLE_TO_DEAL",
890 ),
891 (StreamingAccountDataField::Equity, "EQUITY"),
892 (StreamingAccountDataField::EquityUsed, "EQUITY_USED"),
893 ] {
894 assert_wire_name(&field, expected);
895 }
896 }
897
898 #[test]
899 fn test_streaming_price_field_special_variants_wire_names() {
900 for (field, expected) in [
904 (StreamingPriceField::MidOpen, "MID_OPEN"),
905 (StreamingPriceField::High, "HIGH"),
906 (StreamingPriceField::Low, "LOW"),
907 (StreamingPriceField::BidQuoteId, "BIDQUOTEID"),
908 (StreamingPriceField::AskQuoteId, "ASKQUOTEID"),
909 (StreamingPriceField::BidPrice1, "BIDPRICE1"),
910 (StreamingPriceField::AskPrice5, "ASKPRICE5"),
911 (StreamingPriceField::Currency0, "CURRENCY0"),
912 (StreamingPriceField::C1BidSize1, "C1BIDSIZE1"),
913 (StreamingPriceField::C5AskSize5, "C5ASKSIZE5"),
914 (StreamingPriceField::Timestamp, "TIMESTAMP"),
915 (StreamingPriceField::DlgFlag, "DLG_FLAG"),
916 ] {
917 assert_wire_name(&field, expected);
918 }
919 }
920
921 #[test]
922 fn test_streaming_chart_field_all_variants_wire_names() {
923 for (field, expected) in [
924 (StreamingChartField::Ltv, "LTV"),
925 (StreamingChartField::Ttv, "TTV"),
926 (StreamingChartField::Utm, "UTM"),
927 (StreamingChartField::DayOpenMid, "DAY_OPEN_MID"),
928 (StreamingChartField::DayNetChgMid, "DAY_NET_CHG_MID"),
929 (StreamingChartField::DayPercChgMid, "DAY_PERC_CHG_MID"),
930 (StreamingChartField::DayHigh, "DAY_HIGH"),
931 (StreamingChartField::DayLow, "DAY_LOW"),
932 (StreamingChartField::Bid, "BID"),
933 (StreamingChartField::Ofr, "OFR"),
934 (StreamingChartField::Ltp, "LTP"),
935 (StreamingChartField::OfrOpen, "OFR_OPEN"),
936 (StreamingChartField::OfrHigh, "OFR_HIGH"),
937 (StreamingChartField::OfrLow, "OFR_LOW"),
938 (StreamingChartField::OfrClose, "OFR_CLOSE"),
939 (StreamingChartField::BidOpen, "BID_OPEN"),
940 (StreamingChartField::BidHigh, "BID_HIGH"),
941 (StreamingChartField::BidLow, "BID_LOW"),
942 (StreamingChartField::BidClose, "BID_CLOSE"),
943 (StreamingChartField::LtpOpen, "LTP_OPEN"),
944 (StreamingChartField::LtpHigh, "LTP_HIGH"),
945 (StreamingChartField::LtpLow, "LTP_LOW"),
946 (StreamingChartField::LtpClose, "LTP_CLOSE"),
947 (StreamingChartField::ConsEnd, "CONS_END"),
948 (StreamingChartField::ConsTickCount, "CONS_TICK_COUNT"),
949 ] {
950 assert_wire_name(&field, expected);
951 }
952 }
953
954 const ALL_MARKET_FIELDS: &[StreamingMarketField] = &[
958 StreamingMarketField::MidOpen,
959 StreamingMarketField::High,
960 StreamingMarketField::Low,
961 StreamingMarketField::Change,
962 StreamingMarketField::ChangePct,
963 StreamingMarketField::UpdateTime,
964 StreamingMarketField::MarketDelay,
965 StreamingMarketField::MarketState,
966 StreamingMarketField::Bid,
967 StreamingMarketField::Offer,
968 ];
969
970 const ALL_ACCOUNT_FIELDS: &[StreamingAccountDataField] = &[
971 StreamingAccountDataField::Pnl,
972 StreamingAccountDataField::Deposit,
973 StreamingAccountDataField::AvailableCash,
974 StreamingAccountDataField::PnlLr,
975 StreamingAccountDataField::PnlNlr,
976 StreamingAccountDataField::Funds,
977 StreamingAccountDataField::Margin,
978 StreamingAccountDataField::MarginLr,
979 StreamingAccountDataField::MarginNlr,
980 StreamingAccountDataField::AvailableToDeal,
981 StreamingAccountDataField::Equity,
982 StreamingAccountDataField::EquityUsed,
983 ];
984
985 const ALL_CHART_FIELDS: &[StreamingChartField] = &[
986 StreamingChartField::Ltv,
987 StreamingChartField::Ttv,
988 StreamingChartField::Utm,
989 StreamingChartField::DayOpenMid,
990 StreamingChartField::DayNetChgMid,
991 StreamingChartField::DayPercChgMid,
992 StreamingChartField::DayHigh,
993 StreamingChartField::DayLow,
994 StreamingChartField::Bid,
995 StreamingChartField::Ofr,
996 StreamingChartField::Ltp,
997 StreamingChartField::OfrOpen,
998 StreamingChartField::OfrHigh,
999 StreamingChartField::OfrLow,
1000 StreamingChartField::OfrClose,
1001 StreamingChartField::BidOpen,
1002 StreamingChartField::BidHigh,
1003 StreamingChartField::BidLow,
1004 StreamingChartField::BidClose,
1005 StreamingChartField::LtpOpen,
1006 StreamingChartField::LtpHigh,
1007 StreamingChartField::LtpLow,
1008 StreamingChartField::LtpClose,
1009 StreamingChartField::ConsEnd,
1010 StreamingChartField::ConsTickCount,
1011 ];
1012
1013 const ALL_PRICE_FIELDS: &[StreamingPriceField] = &[
1014 StreamingPriceField::MidOpen,
1015 StreamingPriceField::High,
1016 StreamingPriceField::Low,
1017 StreamingPriceField::BidQuoteId,
1018 StreamingPriceField::AskQuoteId,
1019 StreamingPriceField::BidPrice1,
1020 StreamingPriceField::BidPrice2,
1021 StreamingPriceField::BidPrice3,
1022 StreamingPriceField::BidPrice4,
1023 StreamingPriceField::BidPrice5,
1024 StreamingPriceField::AskPrice1,
1025 StreamingPriceField::AskPrice2,
1026 StreamingPriceField::AskPrice3,
1027 StreamingPriceField::AskPrice4,
1028 StreamingPriceField::AskPrice5,
1029 StreamingPriceField::BidSize1,
1030 StreamingPriceField::BidSize2,
1031 StreamingPriceField::BidSize3,
1032 StreamingPriceField::BidSize4,
1033 StreamingPriceField::BidSize5,
1034 StreamingPriceField::AskSize1,
1035 StreamingPriceField::AskSize2,
1036 StreamingPriceField::AskSize3,
1037 StreamingPriceField::AskSize4,
1038 StreamingPriceField::AskSize5,
1039 StreamingPriceField::Currency0,
1040 StreamingPriceField::Currency1,
1041 StreamingPriceField::C1BidSize1,
1042 StreamingPriceField::C1BidSize2,
1043 StreamingPriceField::C1BidSize3,
1044 StreamingPriceField::C1BidSize4,
1045 StreamingPriceField::C1BidSize5,
1046 StreamingPriceField::C1AskSize1,
1047 StreamingPriceField::C1AskSize2,
1048 StreamingPriceField::C1AskSize3,
1049 StreamingPriceField::C1AskSize4,
1050 StreamingPriceField::C1AskSize5,
1051 StreamingPriceField::Currency2,
1052 StreamingPriceField::C2BidSize1,
1053 StreamingPriceField::C2BidSize2,
1054 StreamingPriceField::C2BidSize3,
1055 StreamingPriceField::C2BidSize4,
1056 StreamingPriceField::C2BidSize5,
1057 StreamingPriceField::C2AskSize1,
1058 StreamingPriceField::C2AskSize2,
1059 StreamingPriceField::C2AskSize3,
1060 StreamingPriceField::C2AskSize4,
1061 StreamingPriceField::C2AskSize5,
1062 StreamingPriceField::Currency3,
1063 StreamingPriceField::C3BidSize1,
1064 StreamingPriceField::C3BidSize2,
1065 StreamingPriceField::C3BidSize3,
1066 StreamingPriceField::C3BidSize4,
1067 StreamingPriceField::C3BidSize5,
1068 StreamingPriceField::C3AskSize1,
1069 StreamingPriceField::C3AskSize2,
1070 StreamingPriceField::C3AskSize3,
1071 StreamingPriceField::C3AskSize4,
1072 StreamingPriceField::C3AskSize5,
1073 StreamingPriceField::Currency4,
1074 StreamingPriceField::C4BidSize1,
1075 StreamingPriceField::C4BidSize2,
1076 StreamingPriceField::C4BidSize3,
1077 StreamingPriceField::C4BidSize4,
1078 StreamingPriceField::C4BidSize5,
1079 StreamingPriceField::C4AskSize1,
1080 StreamingPriceField::C4AskSize2,
1081 StreamingPriceField::C4AskSize3,
1082 StreamingPriceField::C4AskSize4,
1083 StreamingPriceField::C4AskSize5,
1084 StreamingPriceField::Currency5,
1085 StreamingPriceField::C5BidSize1,
1086 StreamingPriceField::C5BidSize2,
1087 StreamingPriceField::C5BidSize3,
1088 StreamingPriceField::C5BidSize4,
1089 StreamingPriceField::C5BidSize5,
1090 StreamingPriceField::C5AskSize1,
1091 StreamingPriceField::C5AskSize2,
1092 StreamingPriceField::C5AskSize3,
1093 StreamingPriceField::C5AskSize4,
1094 StreamingPriceField::C5AskSize5,
1095 StreamingPriceField::Timestamp,
1096 StreamingPriceField::DlgFlag,
1097 StreamingPriceField::NetChg,
1098 StreamingPriceField::NetChgPct,
1099 StreamingPriceField::Delay,
1100 ];
1101
1102 fn assert_serde_matches_display<T>(field: &T)
1107 where
1108 T: Serialize + Display,
1109 {
1110 let value = serde_json::to_value(field).expect("serialize to value failed");
1111 let wire = value
1112 .as_str()
1113 .expect("a streaming field enum variant must serialize to a JSON string");
1114 assert_eq!(
1115 wire,
1116 field.to_string(),
1117 "serde wire name and Display disagree for a streaming field variant"
1118 );
1119 }
1120
1121 #[test]
1122 fn test_all_streaming_fields_serde_matches_display() {
1123 for field in ALL_MARKET_FIELDS {
1124 assert_serde_matches_display(field);
1125 }
1126 for field in ALL_ACCOUNT_FIELDS {
1127 assert_serde_matches_display(field);
1128 }
1129 for field in ALL_CHART_FIELDS {
1130 assert_serde_matches_display(field);
1131 }
1132 for field in ALL_PRICE_FIELDS {
1133 assert_serde_matches_display(field);
1134 }
1135 }
1136
1137 #[test]
1138 fn test_get_streaming_price_fields_uses_display_wire_names() {
1139 let mut fields = HashSet::new();
1142 fields.insert(StreamingPriceField::MidOpen);
1143 fields.insert(StreamingPriceField::C1BidSize1);
1144 fields.insert(StreamingPriceField::DlgFlag);
1145 let result = get_streaming_price_fields(&fields);
1146 assert_eq!(result.len(), 3);
1147 assert!(result.contains(&"MID_OPEN".to_string()));
1148 assert!(result.contains(&"C1BIDSIZE1".to_string()));
1149 assert!(result.contains(&"DLG_FLAG".to_string()));
1150 }
1151
1152 #[test]
1153 fn test_streaming_price_field_in_hashset() {
1154 let mut set = HashSet::new();
1155 set.insert(StreamingPriceField::MidOpen);
1156 set.insert(StreamingPriceField::High);
1157 set.insert(StreamingPriceField::MidOpen); assert_eq!(set.len(), 2);
1159 assert!(set.contains(&StreamingPriceField::MidOpen));
1160 assert!(!set.contains(&StreamingPriceField::Low));
1161 }
1162
1163 #[test]
1164 fn test_streaming_chart_field_in_hashset() {
1165 let mut set = HashSet::new();
1166 set.insert(StreamingChartField::Bid);
1167 set.insert(StreamingChartField::Ofr);
1168 set.insert(StreamingChartField::Bid); assert_eq!(set.len(), 2);
1170 assert!(set.contains(&StreamingChartField::Bid));
1171 assert!(!set.contains(&StreamingChartField::Ltp));
1172 }
1173
1174 #[test]
1175 fn test_streaming_account_field_in_hashset() {
1176 let mut set = HashSet::new();
1177 set.insert(StreamingAccountDataField::Pnl);
1178 set.insert(StreamingAccountDataField::Deposit);
1179 set.insert(StreamingAccountDataField::Pnl); assert_eq!(set.len(), 2);
1181 assert!(set.contains(&StreamingAccountDataField::Pnl));
1182 assert!(!set.contains(&StreamingAccountDataField::AvailableCash));
1183 }
1184}