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