1use std::fmt::Display;
8use std::io::Write;
9use std::ops::Index;
10use std::str::{self, FromStr};
11
12use byteorder::{BigEndian, WriteBytesExt};
13
14use log::debug;
15use serde::{Deserialize, Serialize};
16use time::OffsetDateTime;
17
18use crate::{Error, ToField};
19
20pub mod parser_registry;
21pub(crate) mod shared_channel_configuration;
22#[cfg(test)]
23mod tests;
24
25#[cfg(test)]
26mod from_str_tests {
27 use super::*;
28 use std::str::FromStr;
29
30 #[test]
31 fn test_outgoing_messages_from_str() {
32 assert_eq!(OutgoingMessages::from_str("1").unwrap(), OutgoingMessages::RequestMarketData);
34 assert_eq!(OutgoingMessages::from_str("17").unwrap(), OutgoingMessages::RequestManagedAccounts);
35 assert_eq!(OutgoingMessages::from_str("49").unwrap(), OutgoingMessages::RequestCurrentTime);
36 assert_eq!(OutgoingMessages::from_str("61").unwrap(), OutgoingMessages::RequestPositions);
37
38 assert!(OutgoingMessages::from_str("999").is_err());
40 assert!(OutgoingMessages::from_str("abc").is_err());
41 assert!(OutgoingMessages::from_str("").is_err());
42 }
43
44 #[test]
45 fn test_outgoing_messages_roundtrip() {
46 let msg = OutgoingMessages::RequestCurrentTime;
48 let as_string = msg.to_string();
49 let parsed = OutgoingMessages::from_str(&as_string).unwrap();
50 assert_eq!(parsed, OutgoingMessages::RequestCurrentTime);
51
52 let msg = OutgoingMessages::RequestManagedAccounts;
54 let as_string = msg.to_string();
55 let parsed = OutgoingMessages::from_str(&as_string).unwrap();
56 assert_eq!(parsed, OutgoingMessages::RequestManagedAccounts);
57 }
58
59 #[test]
60 fn test_incoming_messages_from_str() {
61 assert_eq!(IncomingMessages::from_str("4").unwrap(), IncomingMessages::Error);
63 assert_eq!(IncomingMessages::from_str("15").unwrap(), IncomingMessages::ManagedAccounts);
64 assert_eq!(IncomingMessages::from_str("49").unwrap(), IncomingMessages::CurrentTime);
65 assert_eq!(IncomingMessages::from_str("61").unwrap(), IncomingMessages::Position);
66
67 assert_eq!(IncomingMessages::from_str("999").unwrap(), IncomingMessages::NotValid);
69 assert_eq!(IncomingMessages::from_str("0").unwrap(), IncomingMessages::NotValid);
70 assert_eq!(IncomingMessages::from_str("-1").unwrap(), IncomingMessages::NotValid);
71
72 assert!(IncomingMessages::from_str("abc").is_err());
74 assert!(IncomingMessages::from_str("").is_err());
75 assert!(IncomingMessages::from_str("1.5").is_err());
76 }
77
78 #[test]
79 fn test_incoming_messages_roundtrip() {
80 let n = 49;
82 let msg = IncomingMessages::from(n);
83 let as_string = n.to_string();
84 let parsed = IncomingMessages::from_str(&as_string).unwrap();
85 assert_eq!(parsed, msg);
86
87 let n = 15;
89 let msg = IncomingMessages::from(n);
90 let as_string = n.to_string();
91 let parsed = IncomingMessages::from_str(&as_string).unwrap();
92 assert_eq!(parsed, msg);
93
94 let n = 999;
96 let msg = IncomingMessages::from(n);
97 let as_string = n.to_string();
98 let parsed = IncomingMessages::from_str(&as_string).unwrap();
99 assert_eq!(parsed, msg);
100 assert_eq!(parsed, IncomingMessages::NotValid);
101 }
102}
103
104const INFINITY_STR: &str = "Infinity";
105const UNSET_DOUBLE: &str = "1.7976931348623157E308";
106const UNSET_INTEGER: &str = "2147483647";
107const UNSET_LONG: &str = "9223372036854775807";
108
109pub(crate) const MESSAGE_INDEX: usize = 4;
111pub(crate) const CODE_INDEX: usize = 3;
113
114#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
116pub enum IncomingMessages {
117 Shutdown = -2,
119 NotValid = -1,
121 TickPrice = 1,
123 TickSize = 2,
125 OrderStatus = 3,
127 Error = 4,
129 OpenOrder = 5,
131 AccountValue = 6,
133 PortfolioValue = 7,
135 AccountUpdateTime = 8,
137 NextValidId = 9,
139 ContractData = 10,
141 ExecutionData = 11,
143 MarketDepth = 12,
145 MarketDepthL2 = 13,
147 NewsBulletins = 14,
149 ManagedAccounts = 15,
151 ReceiveFA = 16,
153 HistoricalData = 17,
155 BondContractData = 18,
157 ScannerParameters = 19,
159 ScannerData = 20,
161 TickOptionComputation = 21,
163 TickGeneric = 45,
165 TickString = 46,
167 TickEFP = 47, CurrentTime = 49,
171 RealTimeBars = 50,
173 FundamentalData = 51,
175 ContractDataEnd = 52,
177 OpenOrderEnd = 53,
179 AccountDownloadEnd = 54,
181 ExecutionDataEnd = 55,
183 DeltaNeutralValidation = 56,
185 TickSnapshotEnd = 57,
187 MarketDataType = 58,
189 CommissionsReport = 59,
191 Position = 61,
193 PositionEnd = 62,
195 AccountSummary = 63,
197 AccountSummaryEnd = 64,
199 VerifyMessageApi = 65,
201 VerifyCompleted = 66,
203 DisplayGroupList = 67,
205 DisplayGroupUpdated = 68,
207 VerifyAndAuthMessageApi = 69,
209 VerifyAndAuthCompleted = 70,
211 PositionMulti = 71,
213 PositionMultiEnd = 72,
215 AccountUpdateMulti = 73,
217 AccountUpdateMultiEnd = 74,
219 SecurityDefinitionOptionParameter = 75,
221 SecurityDefinitionOptionParameterEnd = 76,
223 SoftDollarTier = 77,
225 FamilyCodes = 78,
227 SymbolSamples = 79,
229 MktDepthExchanges = 80,
231 TickReqParams = 81,
233 SmartComponents = 82,
235 NewsArticle = 83,
237 TickNews = 84,
239 NewsProviders = 85,
241 HistoricalNews = 86,
243 HistoricalNewsEnd = 87,
245 HeadTimestamp = 88,
247 HistogramData = 89,
249 HistoricalDataUpdate = 90,
251 RerouteMktDataReq = 91,
253 RerouteMktDepthReq = 92,
255 MarketRule = 93,
257 PnL = 94,
259 PnLSingle = 95,
261 HistoricalTick = 96,
263 HistoricalTickBidAsk = 97,
265 HistoricalTickLast = 98,
267 TickByTick = 99,
269 OrderBound = 100,
271 CompletedOrder = 101,
273 CompletedOrdersEnd = 102,
275 ReplaceFAEnd = 103,
277 WshMetaData = 104,
279 WshEventData = 105,
281 HistoricalSchedule = 106,
283 UserInfo = 107,
285}
286
287impl From<i32> for IncomingMessages {
288 fn from(value: i32) -> IncomingMessages {
289 match value {
290 -2 => IncomingMessages::Shutdown,
291 1 => IncomingMessages::TickPrice,
292 2 => IncomingMessages::TickSize,
293 3 => IncomingMessages::OrderStatus,
294 4 => IncomingMessages::Error,
295 5 => IncomingMessages::OpenOrder,
296 6 => IncomingMessages::AccountValue,
297 7 => IncomingMessages::PortfolioValue,
298 8 => IncomingMessages::AccountUpdateTime,
299 9 => IncomingMessages::NextValidId,
300 10 => IncomingMessages::ContractData,
301 11 => IncomingMessages::ExecutionData,
302 12 => IncomingMessages::MarketDepth,
303 13 => IncomingMessages::MarketDepthL2,
304 14 => IncomingMessages::NewsBulletins,
305 15 => IncomingMessages::ManagedAccounts,
306 16 => IncomingMessages::ReceiveFA,
307 17 => IncomingMessages::HistoricalData,
308 18 => IncomingMessages::BondContractData,
309 19 => IncomingMessages::ScannerParameters,
310 20 => IncomingMessages::ScannerData,
311 21 => IncomingMessages::TickOptionComputation,
312 45 => IncomingMessages::TickGeneric,
313 46 => IncomingMessages::TickString,
314 47 => IncomingMessages::TickEFP, 49 => IncomingMessages::CurrentTime,
316 50 => IncomingMessages::RealTimeBars,
317 51 => IncomingMessages::FundamentalData,
318 52 => IncomingMessages::ContractDataEnd,
319 53 => IncomingMessages::OpenOrderEnd,
320 54 => IncomingMessages::AccountDownloadEnd,
321 55 => IncomingMessages::ExecutionDataEnd,
322 56 => IncomingMessages::DeltaNeutralValidation,
323 57 => IncomingMessages::TickSnapshotEnd,
324 58 => IncomingMessages::MarketDataType,
325 59 => IncomingMessages::CommissionsReport,
326 61 => IncomingMessages::Position,
327 62 => IncomingMessages::PositionEnd,
328 63 => IncomingMessages::AccountSummary,
329 64 => IncomingMessages::AccountSummaryEnd,
330 65 => IncomingMessages::VerifyMessageApi,
331 66 => IncomingMessages::VerifyCompleted,
332 67 => IncomingMessages::DisplayGroupList,
333 68 => IncomingMessages::DisplayGroupUpdated,
334 69 => IncomingMessages::VerifyAndAuthMessageApi,
335 70 => IncomingMessages::VerifyAndAuthCompleted,
336 71 => IncomingMessages::PositionMulti,
337 72 => IncomingMessages::PositionMultiEnd,
338 73 => IncomingMessages::AccountUpdateMulti,
339 74 => IncomingMessages::AccountUpdateMultiEnd,
340 75 => IncomingMessages::SecurityDefinitionOptionParameter,
341 76 => IncomingMessages::SecurityDefinitionOptionParameterEnd,
342 77 => IncomingMessages::SoftDollarTier,
343 78 => IncomingMessages::FamilyCodes,
344 79 => IncomingMessages::SymbolSamples,
345 80 => IncomingMessages::MktDepthExchanges,
346 81 => IncomingMessages::TickReqParams,
347 82 => IncomingMessages::SmartComponents,
348 83 => IncomingMessages::NewsArticle,
349 84 => IncomingMessages::TickNews,
350 85 => IncomingMessages::NewsProviders,
351 86 => IncomingMessages::HistoricalNews,
352 87 => IncomingMessages::HistoricalNewsEnd,
353 88 => IncomingMessages::HeadTimestamp,
354 89 => IncomingMessages::HistogramData,
355 90 => IncomingMessages::HistoricalDataUpdate,
356 91 => IncomingMessages::RerouteMktDataReq,
357 92 => IncomingMessages::RerouteMktDepthReq,
358 93 => IncomingMessages::MarketRule,
359 94 => IncomingMessages::PnL,
360 95 => IncomingMessages::PnLSingle,
361 96 => IncomingMessages::HistoricalTick,
362 97 => IncomingMessages::HistoricalTickBidAsk,
363 98 => IncomingMessages::HistoricalTickLast,
364 99 => IncomingMessages::TickByTick,
365 100 => IncomingMessages::OrderBound,
366 101 => IncomingMessages::CompletedOrder,
367 102 => IncomingMessages::CompletedOrdersEnd,
368 103 => IncomingMessages::ReplaceFAEnd,
369 104 => IncomingMessages::WshMetaData,
370 105 => IncomingMessages::WshEventData,
371 106 => IncomingMessages::HistoricalSchedule,
372 107 => IncomingMessages::UserInfo,
373 _ => IncomingMessages::NotValid,
374 }
375 }
376}
377
378impl FromStr for IncomingMessages {
379 type Err = Error;
380
381 fn from_str(s: &str) -> Result<Self, Self::Err> {
382 match s.parse::<i32>() {
383 Ok(n) => Ok(IncomingMessages::from(n)),
384 Err(_) => Err(Error::Simple(format!("Invalid incoming message type: {}", s))),
385 }
386 }
387}
388
389pub fn order_id_index(kind: IncomingMessages) -> Option<usize> {
391 match kind {
392 IncomingMessages::OpenOrder | IncomingMessages::OrderStatus => Some(1),
393 IncomingMessages::ExecutionData | IncomingMessages::ExecutionDataEnd => Some(2),
394 _ => None,
395 }
396}
397
398pub fn request_id_index(kind: IncomingMessages) -> Option<usize> {
400 match kind {
401 IncomingMessages::AccountSummary => Some(2),
402 IncomingMessages::AccountSummaryEnd => Some(2),
403 IncomingMessages::AccountUpdateMulti => Some(2),
404 IncomingMessages::AccountUpdateMultiEnd => Some(2),
405 IncomingMessages::ContractData => Some(1),
406 IncomingMessages::ContractDataEnd => Some(2),
407 IncomingMessages::Error => Some(2),
408 IncomingMessages::ExecutionData => Some(1),
409 IncomingMessages::ExecutionDataEnd => Some(2),
410 IncomingMessages::HeadTimestamp => Some(1),
411 IncomingMessages::HistogramData => Some(1),
412 IncomingMessages::HistoricalData => Some(1),
413 IncomingMessages::HistoricalNews => Some(1),
414 IncomingMessages::HistoricalNewsEnd => Some(1),
415 IncomingMessages::HistoricalSchedule => Some(1),
416 IncomingMessages::HistoricalTick => Some(1),
417 IncomingMessages::HistoricalTickBidAsk => Some(1),
418 IncomingMessages::HistoricalTickLast => Some(1),
419 IncomingMessages::MarketDepth => Some(2),
420 IncomingMessages::MarketDepthL2 => Some(2),
421 IncomingMessages::NewsArticle => Some(1),
422 IncomingMessages::OpenOrder => Some(1),
423 IncomingMessages::PnL => Some(1),
424 IncomingMessages::PnLSingle => Some(1),
425 IncomingMessages::PositionMulti => Some(2),
426 IncomingMessages::PositionMultiEnd => Some(2),
427 IncomingMessages::RealTimeBars => Some(2),
428 IncomingMessages::ScannerData => Some(2),
429 IncomingMessages::SecurityDefinitionOptionParameter => Some(1),
430 IncomingMessages::SecurityDefinitionOptionParameterEnd => Some(1),
431 IncomingMessages::SymbolSamples => Some(1),
432 IncomingMessages::TickByTick => Some(1),
433 IncomingMessages::TickEFP => Some(2),
434 IncomingMessages::TickGeneric => Some(2),
435 IncomingMessages::TickNews => Some(1),
436 IncomingMessages::TickOptionComputation => Some(1),
437 IncomingMessages::TickPrice => Some(2),
438 IncomingMessages::TickReqParams => Some(1),
439 IncomingMessages::TickSize => Some(2),
440 IncomingMessages::TickSnapshotEnd => Some(2),
441 IncomingMessages::TickString => Some(2),
442 IncomingMessages::WshEventData => Some(1),
443 IncomingMessages::WshMetaData => Some(1),
444
445 _ => {
446 debug!("could not determine request id index for {kind:?} (this message type may not have a request id).");
447 None
448 }
449 }
450}
451
452#[allow(dead_code)]
454#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
455pub enum OutgoingMessages {
456 RequestMarketData = 1,
458 CancelMarketData = 2,
460 PlaceOrder = 3,
462 CancelOrder = 4,
464 RequestOpenOrders = 5,
466 RequestAccountData = 6,
468 RequestExecutions = 7,
470 RequestIds = 8,
472 RequestContractData = 9,
474 RequestMarketDepth = 10,
476 CancelMarketDepth = 11,
478 RequestNewsBulletins = 12,
480 CancelNewsBulletin = 13,
482 ChangeServerLog = 14,
484 RequestAutoOpenOrders = 15,
486 RequestAllOpenOrders = 16,
488 RequestManagedAccounts = 17,
490 RequestFA = 18,
492 ReplaceFA = 19,
494 RequestHistoricalData = 20,
496 ExerciseOptions = 21,
498 RequestScannerSubscription = 22,
500 CancelScannerSubscription = 23,
502 RequestScannerParameters = 24,
504 CancelHistoricalData = 25,
506 RequestCurrentTime = 49,
508 RequestRealTimeBars = 50,
510 CancelRealTimeBars = 51,
512 RequestFundamentalData = 52,
514 CancelFundamentalData = 53,
516 ReqCalcImpliedVolat = 54,
518 ReqCalcOptionPrice = 55,
520 CancelImpliedVolatility = 56,
522 CancelOptionPrice = 57,
524 RequestGlobalCancel = 58,
526 RequestMarketDataType = 59,
528 RequestPositions = 61,
530 RequestAccountSummary = 62,
532 CancelAccountSummary = 63,
534 CancelPositions = 64,
536 VerifyRequest = 65,
538 VerifyMessage = 66,
540 QueryDisplayGroups = 67,
542 SubscribeToGroupEvents = 68,
544 UpdateDisplayGroup = 69,
546 UnsubscribeFromGroupEvents = 70,
548 StartApi = 71,
550 VerifyAndAuthRequest = 72,
552 VerifyAndAuthMessage = 73,
554 RequestPositionsMulti = 74,
556 CancelPositionsMulti = 75,
558 RequestAccountUpdatesMulti = 76,
560 CancelAccountUpdatesMulti = 77,
562 RequestSecurityDefinitionOptionalParameters = 78,
564 RequestSoftDollarTiers = 79,
566 RequestFamilyCodes = 80,
568 RequestMatchingSymbols = 81,
570 RequestMktDepthExchanges = 82,
572 RequestSmartComponents = 83,
574 RequestNewsArticle = 84,
576 RequestNewsProviders = 85,
578 RequestHistoricalNews = 86,
580 RequestHeadTimestamp = 87,
582 RequestHistogramData = 88,
584 CancelHistogramData = 89,
586 CancelHeadTimestamp = 90,
588 RequestMarketRule = 91,
590 RequestPnL = 92,
592 CancelPnL = 93,
594 RequestPnLSingle = 94,
596 CancelPnLSingle = 95,
598 RequestHistoricalTicks = 96,
600 RequestTickByTickData = 97,
602 CancelTickByTickData = 98,
604 RequestCompletedOrders = 99,
606 RequestWshMetaData = 100,
608 CancelWshMetaData = 101,
610 RequestWshEventData = 102,
612 CancelWshEventData = 103,
614 RequestUserInfo = 104,
616}
617
618impl ToField for OutgoingMessages {
619 fn to_field(&self) -> String {
620 (*self as i32).to_string()
621 }
622}
623
624impl std::fmt::Display for OutgoingMessages {
625 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
626 write!(f, "{}", *self as i32)
627 }
628}
629
630impl FromStr for OutgoingMessages {
631 type Err = Error;
632
633 fn from_str(s: &str) -> Result<Self, Self::Err> {
634 match s.parse::<i32>() {
635 Ok(1) => Ok(OutgoingMessages::RequestMarketData),
636 Ok(2) => Ok(OutgoingMessages::CancelMarketData),
637 Ok(3) => Ok(OutgoingMessages::PlaceOrder),
638 Ok(4) => Ok(OutgoingMessages::CancelOrder),
639 Ok(5) => Ok(OutgoingMessages::RequestOpenOrders),
640 Ok(6) => Ok(OutgoingMessages::RequestAccountData),
641 Ok(7) => Ok(OutgoingMessages::RequestExecutions),
642 Ok(8) => Ok(OutgoingMessages::RequestIds),
643 Ok(9) => Ok(OutgoingMessages::RequestContractData),
644 Ok(10) => Ok(OutgoingMessages::RequestMarketDepth),
645 Ok(11) => Ok(OutgoingMessages::CancelMarketDepth),
646 Ok(12) => Ok(OutgoingMessages::RequestNewsBulletins),
647 Ok(13) => Ok(OutgoingMessages::CancelNewsBulletin),
648 Ok(14) => Ok(OutgoingMessages::ChangeServerLog),
649 Ok(15) => Ok(OutgoingMessages::RequestAutoOpenOrders),
650 Ok(16) => Ok(OutgoingMessages::RequestAllOpenOrders),
651 Ok(17) => Ok(OutgoingMessages::RequestManagedAccounts),
652 Ok(18) => Ok(OutgoingMessages::RequestFA),
653 Ok(19) => Ok(OutgoingMessages::ReplaceFA),
654 Ok(20) => Ok(OutgoingMessages::RequestHistoricalData),
655 Ok(21) => Ok(OutgoingMessages::ExerciseOptions),
656 Ok(22) => Ok(OutgoingMessages::RequestScannerSubscription),
657 Ok(23) => Ok(OutgoingMessages::CancelScannerSubscription),
658 Ok(24) => Ok(OutgoingMessages::RequestScannerParameters),
659 Ok(25) => Ok(OutgoingMessages::CancelHistoricalData),
660 Ok(49) => Ok(OutgoingMessages::RequestCurrentTime),
661 Ok(50) => Ok(OutgoingMessages::RequestRealTimeBars),
662 Ok(51) => Ok(OutgoingMessages::CancelRealTimeBars),
663 Ok(52) => Ok(OutgoingMessages::RequestFundamentalData),
664 Ok(53) => Ok(OutgoingMessages::CancelFundamentalData),
665 Ok(54) => Ok(OutgoingMessages::ReqCalcImpliedVolat),
666 Ok(55) => Ok(OutgoingMessages::ReqCalcOptionPrice),
667 Ok(56) => Ok(OutgoingMessages::CancelImpliedVolatility),
668 Ok(57) => Ok(OutgoingMessages::CancelOptionPrice),
669 Ok(58) => Ok(OutgoingMessages::RequestGlobalCancel),
670 Ok(59) => Ok(OutgoingMessages::RequestMarketDataType),
671 Ok(61) => Ok(OutgoingMessages::RequestPositions),
672 Ok(62) => Ok(OutgoingMessages::RequestAccountSummary),
673 Ok(63) => Ok(OutgoingMessages::CancelAccountSummary),
674 Ok(64) => Ok(OutgoingMessages::CancelPositions),
675 Ok(65) => Ok(OutgoingMessages::VerifyRequest),
676 Ok(66) => Ok(OutgoingMessages::VerifyMessage),
677 Ok(67) => Ok(OutgoingMessages::QueryDisplayGroups),
678 Ok(68) => Ok(OutgoingMessages::SubscribeToGroupEvents),
679 Ok(69) => Ok(OutgoingMessages::UpdateDisplayGroup),
680 Ok(70) => Ok(OutgoingMessages::UnsubscribeFromGroupEvents),
681 Ok(71) => Ok(OutgoingMessages::StartApi),
682 Ok(72) => Ok(OutgoingMessages::VerifyAndAuthRequest),
683 Ok(73) => Ok(OutgoingMessages::VerifyAndAuthMessage),
684 Ok(74) => Ok(OutgoingMessages::RequestPositionsMulti),
685 Ok(75) => Ok(OutgoingMessages::CancelPositionsMulti),
686 Ok(76) => Ok(OutgoingMessages::RequestAccountUpdatesMulti),
687 Ok(77) => Ok(OutgoingMessages::CancelAccountUpdatesMulti),
688 Ok(78) => Ok(OutgoingMessages::RequestSecurityDefinitionOptionalParameters),
689 Ok(79) => Ok(OutgoingMessages::RequestSoftDollarTiers),
690 Ok(80) => Ok(OutgoingMessages::RequestFamilyCodes),
691 Ok(81) => Ok(OutgoingMessages::RequestMatchingSymbols),
692 Ok(82) => Ok(OutgoingMessages::RequestMktDepthExchanges),
693 Ok(83) => Ok(OutgoingMessages::RequestSmartComponents),
694 Ok(84) => Ok(OutgoingMessages::RequestNewsArticle),
695 Ok(85) => Ok(OutgoingMessages::RequestNewsProviders),
696 Ok(86) => Ok(OutgoingMessages::RequestHistoricalNews),
697 Ok(87) => Ok(OutgoingMessages::RequestHeadTimestamp),
698 Ok(88) => Ok(OutgoingMessages::RequestHistogramData),
699 Ok(89) => Ok(OutgoingMessages::CancelHistogramData),
700 Ok(90) => Ok(OutgoingMessages::CancelHeadTimestamp),
701 Ok(91) => Ok(OutgoingMessages::RequestMarketRule),
702 Ok(92) => Ok(OutgoingMessages::RequestPnL),
703 Ok(93) => Ok(OutgoingMessages::CancelPnL),
704 Ok(94) => Ok(OutgoingMessages::RequestPnLSingle),
705 Ok(95) => Ok(OutgoingMessages::CancelPnLSingle),
706 Ok(96) => Ok(OutgoingMessages::RequestHistoricalTicks),
707 Ok(97) => Ok(OutgoingMessages::RequestTickByTickData),
708 Ok(98) => Ok(OutgoingMessages::CancelTickByTickData),
709 Ok(99) => Ok(OutgoingMessages::RequestCompletedOrders),
710 Ok(100) => Ok(OutgoingMessages::RequestWshMetaData),
711 Ok(101) => Ok(OutgoingMessages::CancelWshMetaData),
712 Ok(102) => Ok(OutgoingMessages::RequestWshEventData),
713 Ok(103) => Ok(OutgoingMessages::CancelWshEventData),
714 Ok(104) => Ok(OutgoingMessages::RequestUserInfo),
715 Ok(n) => Err(Error::Simple(format!("Unknown outgoing message type: {}", n))),
716 Err(_) => Err(Error::Simple(format!("Invalid outgoing message type: {}", s))),
717 }
718 }
719}
720
721pub fn encode_length(message: &str) -> Vec<u8> {
723 let data = message.as_bytes();
724
725 let mut packet: Vec<u8> = Vec::with_capacity(data.len() + 4);
726
727 packet.write_u32::<BigEndian>(data.len() as u32).unwrap();
728 packet.write_all(data).unwrap();
729 packet
730}
731
732#[derive(Default, Debug, Clone)]
734pub struct RequestMessage {
735 pub(crate) fields: Vec<String>,
736}
737
738impl RequestMessage {
739 pub fn new() -> Self {
741 Self::default()
742 }
743
744 pub(crate) fn push_field<T: ToField>(&mut self, val: &T) -> &RequestMessage {
745 let field = val.to_field();
746 self.fields.push(field);
747 self
748 }
749
750 pub fn encode(&self) -> String {
752 let mut data = self.fields.join("\0");
753 data.push('\0');
754 data
755 }
756
757 #[cfg(test)]
758 pub(crate) fn len(&self) -> usize {
759 self.fields.len()
760 }
761
762 #[cfg(test)]
763 pub(crate) fn encode_simple(&self) -> String {
765 let mut data = self.fields.join("|");
766 data.push('|');
767 data
768 }
769 #[cfg(test)]
770 pub fn from(fields: &str) -> RequestMessage {
772 RequestMessage {
773 fields: fields.split_terminator('\x00').map(|x| x.to_string()).collect(),
774 }
775 }
776 #[cfg(test)]
777 pub fn from_simple(fields: &str) -> RequestMessage {
779 RequestMessage {
780 fields: fields.split_terminator('|').map(|x| x.to_string()).collect(),
781 }
782 }
783}
784
785impl Index<usize> for RequestMessage {
786 type Output = String;
787
788 fn index(&self, i: usize) -> &Self::Output {
789 &self.fields[i]
790 }
791}
792
793#[derive(Clone, Default, Debug)]
795pub struct ResponseMessage {
796 pub i: usize,
798 pub fields: Vec<String>,
800}
801
802impl ResponseMessage {
803 pub fn len(&self) -> usize {
805 self.fields.len()
806 }
807
808 pub fn is_empty(&self) -> bool {
810 self.fields.is_empty()
811 }
812
813 pub fn is_shutdown(&self) -> bool {
815 self.message_type() == IncomingMessages::Shutdown
816 }
817
818 pub fn message_type(&self) -> IncomingMessages {
820 if self.fields.is_empty() {
821 IncomingMessages::NotValid
822 } else {
823 let message_id = i32::from_str(&self.fields[0]).unwrap_or(-1);
824 IncomingMessages::from(message_id)
825 }
826 }
827
828 pub fn request_id(&self) -> Option<i32> {
830 if let Some(i) = request_id_index(self.message_type()) {
831 if let Ok(request_id) = self.peek_int(i) {
832 return Some(request_id);
833 }
834 }
835 None
836 }
837
838 pub fn order_id(&self) -> Option<i32> {
840 if let Some(i) = order_id_index(self.message_type()) {
841 if let Ok(order_id) = self.peek_int(i) {
842 return Some(order_id);
843 }
844 }
845 None
846 }
847
848 pub fn execution_id(&self) -> Option<String> {
850 match self.message_type() {
851 IncomingMessages::ExecutionData => Some(self.peek_string(14)),
852 IncomingMessages::CommissionsReport => Some(self.peek_string(2)),
853 _ => None,
854 }
855 }
856
857 pub fn peek_int(&self, i: usize) -> Result<i32, Error> {
859 if i >= self.fields.len() {
860 return Err(Error::Simple("expected int and found end of message".into()));
861 }
862
863 let field = &self.fields[i];
864 match field.parse() {
865 Ok(val) => Ok(val),
866 Err(err) => Err(Error::Parse(i, field.into(), err.to_string())),
867 }
868 }
869
870 pub fn peek_string(&self, i: usize) -> String {
872 self.fields[i].to_owned()
873 }
874
875 pub fn next_int(&mut self) -> Result<i32, Error> {
877 if self.i >= self.fields.len() {
878 return Err(Error::Simple("expected int and found end of message".into()));
879 }
880
881 let field = &self.fields[self.i];
882 self.i += 1;
883
884 match field.parse() {
885 Ok(val) => Ok(val),
886 Err(err) => Err(Error::Parse(self.i, field.into(), err.to_string())),
887 }
888 }
889
890 pub fn next_optional_int(&mut self) -> Result<Option<i32>, Error> {
892 if self.i >= self.fields.len() {
893 return Err(Error::Simple("expected optional int and found end of message".into()));
894 }
895
896 let field = &self.fields[self.i];
897 self.i += 1;
898
899 if field.is_empty() || field == UNSET_INTEGER {
900 return Ok(None);
901 }
902
903 match field.parse::<i32>() {
904 Ok(val) => Ok(Some(val)),
905 Err(err) => Err(Error::Parse(self.i, field.into(), err.to_string())),
906 }
907 }
908
909 pub fn next_bool(&mut self) -> Result<bool, Error> {
911 if self.i >= self.fields.len() {
912 return Err(Error::Simple("expected bool and found end of message".into()));
913 }
914
915 let field = &self.fields[self.i];
916 self.i += 1;
917
918 Ok(field == "1")
919 }
920
921 pub fn next_long(&mut self) -> Result<i64, Error> {
923 if self.i >= self.fields.len() {
924 return Err(Error::Simple("expected long and found end of message".into()));
925 }
926
927 let field = &self.fields[self.i];
928 self.i += 1;
929
930 match field.parse() {
931 Ok(val) => Ok(val),
932 Err(err) => Err(Error::Parse(self.i, field.into(), err.to_string())),
933 }
934 }
935
936 pub fn next_optional_long(&mut self) -> Result<Option<i64>, Error> {
938 if self.i >= self.fields.len() {
939 return Err(Error::Simple("expected optional long and found end of message".into()));
940 }
941
942 let field = &self.fields[self.i];
943 self.i += 1;
944
945 if field.is_empty() || field == UNSET_LONG {
946 return Ok(None);
947 }
948
949 match field.parse::<i64>() {
950 Ok(val) => Ok(Some(val)),
951 Err(err) => Err(Error::Parse(self.i, field.into(), err.to_string())),
952 }
953 }
954
955 pub fn next_date_time(&mut self) -> Result<OffsetDateTime, Error> {
957 if self.i >= self.fields.len() {
958 return Err(Error::Simple("expected datetime and found end of message".into()));
959 }
960
961 let field = &self.fields[self.i];
962 self.i += 1;
963
964 if field.is_empty() {
965 return Err(Error::Simple("expected timestamp and found empty string".into()));
966 }
967
968 let timestamp: i64 = field.parse()?;
970 match OffsetDateTime::from_unix_timestamp(timestamp) {
971 Ok(val) => Ok(val),
972 Err(err) => Err(Error::Parse(self.i, field.into(), err.to_string())),
973 }
974 }
975
976 pub fn next_string(&mut self) -> Result<String, Error> {
978 if self.i >= self.fields.len() {
979 return Err(Error::Simple("expected string and found end of message".into()));
980 }
981
982 let field = &self.fields[self.i];
983 self.i += 1;
984 Ok(String::from(field))
985 }
986
987 pub fn next_double(&mut self) -> Result<f64, Error> {
989 if self.i >= self.fields.len() {
990 return Err(Error::Simple("expected double and found end of message".into()));
991 }
992
993 let field = &self.fields[self.i];
994 self.i += 1;
995
996 if field.is_empty() || field == "0" || field == "0.0" {
997 return Ok(0.0);
998 }
999
1000 match field.parse() {
1001 Ok(val) => Ok(val),
1002 Err(err) => Err(Error::Parse(self.i, field.into(), err.to_string())),
1003 }
1004 }
1005
1006 pub fn next_optional_double(&mut self) -> Result<Option<f64>, Error> {
1008 if self.i >= self.fields.len() {
1009 return Err(Error::Simple("expected optional double and found end of message".into()));
1010 }
1011
1012 let field = &self.fields[self.i];
1013 self.i += 1;
1014
1015 if field.is_empty() || field == UNSET_DOUBLE {
1016 return Ok(None);
1017 }
1018
1019 if field == INFINITY_STR {
1020 return Ok(Some(f64::INFINITY));
1021 }
1022
1023 match field.parse() {
1024 Ok(val) => Ok(Some(val)),
1025 Err(err) => Err(Error::Parse(self.i, field.into(), err.to_string())),
1026 }
1027 }
1028
1029 pub fn from(fields: &str) -> ResponseMessage {
1031 ResponseMessage {
1032 i: 0,
1033 fields: fields.split_terminator('\x00').map(|x| x.to_string()).collect(),
1034 }
1035 }
1036 #[cfg(test)]
1037 pub fn from_simple(fields: &str) -> ResponseMessage {
1039 ResponseMessage {
1040 i: 0,
1041 fields: fields.split_terminator('|').map(|x| x.to_string()).collect(),
1042 }
1043 }
1044
1045 pub fn skip(&mut self) {
1047 self.i += 1;
1048 }
1049
1050 pub fn encode(&self) -> String {
1052 let mut data = self.fields.join("\0");
1053 data.push('\0');
1054 data
1055 }
1056
1057 #[cfg(test)]
1058 pub fn encode_simple(&self) -> String {
1060 let mut data = self.fields.join("|");
1061 data.push('|');
1062 data
1063 }
1064}
1065
1066#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1068pub struct Notice {
1069 pub code: i32,
1071 pub message: String,
1073}
1074
1075impl Notice {
1076 #[allow(private_interfaces)]
1077 pub fn from(message: &ResponseMessage) -> Notice {
1079 let code = message.peek_int(CODE_INDEX).unwrap_or(-1);
1080 let message = message.peek_string(MESSAGE_INDEX);
1081 Notice { code, message }
1082 }
1083}
1084
1085impl Display for Notice {
1086 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1087 write!(f, "[{}] {}", self.code, self.message)
1088 }
1089}