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
109#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
111pub enum IncomingMessages {
112 Shutdown = -2,
114 NotValid = -1,
116 TickPrice = 1,
118 TickSize = 2,
120 OrderStatus = 3,
122 Error = 4,
124 OpenOrder = 5,
126 AccountValue = 6,
128 PortfolioValue = 7,
130 AccountUpdateTime = 8,
132 NextValidId = 9,
134 ContractData = 10,
136 ExecutionData = 11,
138 MarketDepth = 12,
140 MarketDepthL2 = 13,
142 NewsBulletins = 14,
144 ManagedAccounts = 15,
146 ReceiveFA = 16,
148 HistoricalData = 17,
150 BondContractData = 18,
152 ScannerParameters = 19,
154 ScannerData = 20,
156 TickOptionComputation = 21,
158 TickGeneric = 45,
160 TickString = 46,
162 TickEFP = 47, CurrentTime = 49,
166 RealTimeBars = 50,
168 FundamentalData = 51,
170 ContractDataEnd = 52,
172 OpenOrderEnd = 53,
174 AccountDownloadEnd = 54,
176 ExecutionDataEnd = 55,
178 DeltaNeutralValidation = 56,
180 TickSnapshotEnd = 57,
182 MarketDataType = 58,
184 CommissionsReport = 59,
186 Position = 61,
188 PositionEnd = 62,
190 AccountSummary = 63,
192 AccountSummaryEnd = 64,
194 VerifyMessageApi = 65,
196 VerifyCompleted = 66,
198 DisplayGroupList = 67,
200 DisplayGroupUpdated = 68,
202 VerifyAndAuthMessageApi = 69,
204 VerifyAndAuthCompleted = 70,
206 PositionMulti = 71,
208 PositionMultiEnd = 72,
210 AccountUpdateMulti = 73,
212 AccountUpdateMultiEnd = 74,
214 SecurityDefinitionOptionParameter = 75,
216 SecurityDefinitionOptionParameterEnd = 76,
218 SoftDollarTier = 77,
220 FamilyCodes = 78,
222 SymbolSamples = 79,
224 MktDepthExchanges = 80,
226 TickReqParams = 81,
228 SmartComponents = 82,
230 NewsArticle = 83,
232 TickNews = 84,
234 NewsProviders = 85,
236 HistoricalNews = 86,
238 HistoricalNewsEnd = 87,
240 HeadTimestamp = 88,
242 HistogramData = 89,
244 HistoricalDataUpdate = 90,
246 RerouteMktDataReq = 91,
248 RerouteMktDepthReq = 92,
250 MarketRule = 93,
252 PnL = 94,
254 PnLSingle = 95,
256 HistoricalTick = 96,
258 HistoricalTickBidAsk = 97,
260 HistoricalTickLast = 98,
262 TickByTick = 99,
264 OrderBound = 100,
266 CompletedOrder = 101,
268 CompletedOrdersEnd = 102,
270 ReplaceFAEnd = 103,
272 WshMetaData = 104,
274 WshEventData = 105,
276 HistoricalSchedule = 106,
278 UserInfo = 107,
280 HistoricalDataEnd = 108,
282 CurrentTimeInMillis = 109,
284 ConfigResponse = 110,
286 UpdateConfigResponse = 111,
288}
289
290impl From<i32> for IncomingMessages {
291 fn from(value: i32) -> IncomingMessages {
292 match value {
293 -2 => IncomingMessages::Shutdown,
294 1 => IncomingMessages::TickPrice,
295 2 => IncomingMessages::TickSize,
296 3 => IncomingMessages::OrderStatus,
297 4 => IncomingMessages::Error,
298 5 => IncomingMessages::OpenOrder,
299 6 => IncomingMessages::AccountValue,
300 7 => IncomingMessages::PortfolioValue,
301 8 => IncomingMessages::AccountUpdateTime,
302 9 => IncomingMessages::NextValidId,
303 10 => IncomingMessages::ContractData,
304 11 => IncomingMessages::ExecutionData,
305 12 => IncomingMessages::MarketDepth,
306 13 => IncomingMessages::MarketDepthL2,
307 14 => IncomingMessages::NewsBulletins,
308 15 => IncomingMessages::ManagedAccounts,
309 16 => IncomingMessages::ReceiveFA,
310 17 => IncomingMessages::HistoricalData,
311 18 => IncomingMessages::BondContractData,
312 19 => IncomingMessages::ScannerParameters,
313 20 => IncomingMessages::ScannerData,
314 21 => IncomingMessages::TickOptionComputation,
315 45 => IncomingMessages::TickGeneric,
316 46 => IncomingMessages::TickString,
317 47 => IncomingMessages::TickEFP, 49 => IncomingMessages::CurrentTime,
319 50 => IncomingMessages::RealTimeBars,
320 51 => IncomingMessages::FundamentalData,
321 52 => IncomingMessages::ContractDataEnd,
322 53 => IncomingMessages::OpenOrderEnd,
323 54 => IncomingMessages::AccountDownloadEnd,
324 55 => IncomingMessages::ExecutionDataEnd,
325 56 => IncomingMessages::DeltaNeutralValidation,
326 57 => IncomingMessages::TickSnapshotEnd,
327 58 => IncomingMessages::MarketDataType,
328 59 => IncomingMessages::CommissionsReport,
329 61 => IncomingMessages::Position,
330 62 => IncomingMessages::PositionEnd,
331 63 => IncomingMessages::AccountSummary,
332 64 => IncomingMessages::AccountSummaryEnd,
333 65 => IncomingMessages::VerifyMessageApi,
334 66 => IncomingMessages::VerifyCompleted,
335 67 => IncomingMessages::DisplayGroupList,
336 68 => IncomingMessages::DisplayGroupUpdated,
337 69 => IncomingMessages::VerifyAndAuthMessageApi,
338 70 => IncomingMessages::VerifyAndAuthCompleted,
339 71 => IncomingMessages::PositionMulti,
340 72 => IncomingMessages::PositionMultiEnd,
341 73 => IncomingMessages::AccountUpdateMulti,
342 74 => IncomingMessages::AccountUpdateMultiEnd,
343 75 => IncomingMessages::SecurityDefinitionOptionParameter,
344 76 => IncomingMessages::SecurityDefinitionOptionParameterEnd,
345 77 => IncomingMessages::SoftDollarTier,
346 78 => IncomingMessages::FamilyCodes,
347 79 => IncomingMessages::SymbolSamples,
348 80 => IncomingMessages::MktDepthExchanges,
349 81 => IncomingMessages::TickReqParams,
350 82 => IncomingMessages::SmartComponents,
351 83 => IncomingMessages::NewsArticle,
352 84 => IncomingMessages::TickNews,
353 85 => IncomingMessages::NewsProviders,
354 86 => IncomingMessages::HistoricalNews,
355 87 => IncomingMessages::HistoricalNewsEnd,
356 88 => IncomingMessages::HeadTimestamp,
357 89 => IncomingMessages::HistogramData,
358 90 => IncomingMessages::HistoricalDataUpdate,
359 91 => IncomingMessages::RerouteMktDataReq,
360 92 => IncomingMessages::RerouteMktDepthReq,
361 93 => IncomingMessages::MarketRule,
362 94 => IncomingMessages::PnL,
363 95 => IncomingMessages::PnLSingle,
364 96 => IncomingMessages::HistoricalTick,
365 97 => IncomingMessages::HistoricalTickBidAsk,
366 98 => IncomingMessages::HistoricalTickLast,
367 99 => IncomingMessages::TickByTick,
368 100 => IncomingMessages::OrderBound,
369 101 => IncomingMessages::CompletedOrder,
370 102 => IncomingMessages::CompletedOrdersEnd,
371 103 => IncomingMessages::ReplaceFAEnd,
372 104 => IncomingMessages::WshMetaData,
373 105 => IncomingMessages::WshEventData,
374 106 => IncomingMessages::HistoricalSchedule,
375 107 => IncomingMessages::UserInfo,
376 108 => IncomingMessages::HistoricalDataEnd,
377 109 => IncomingMessages::CurrentTimeInMillis,
378 110 => IncomingMessages::ConfigResponse,
379 111 => IncomingMessages::UpdateConfigResponse,
380 _ => IncomingMessages::NotValid,
381 }
382 }
383}
384
385impl FromStr for IncomingMessages {
386 type Err = Error;
387
388 fn from_str(s: &str) -> Result<Self, Self::Err> {
389 match s.parse::<i32>() {
390 Ok(n) => Ok(IncomingMessages::from(n)),
391 Err(_) => Err(Error::Simple(format!("Invalid incoming message type: {}", s))),
392 }
393 }
394}
395
396pub fn order_id_index(kind: IncomingMessages) -> Option<usize> {
398 match kind {
399 IncomingMessages::OpenOrder | IncomingMessages::OrderStatus => Some(1),
400 IncomingMessages::ExecutionData | IncomingMessages::ExecutionDataEnd => Some(2),
401 _ => None,
402 }
403}
404
405pub fn request_id_index(kind: IncomingMessages) -> Option<usize> {
407 match kind {
408 IncomingMessages::AccountSummary => Some(2),
409 IncomingMessages::AccountSummaryEnd => Some(2),
410 IncomingMessages::AccountUpdateMulti => Some(2),
411 IncomingMessages::AccountUpdateMultiEnd => Some(2),
412 IncomingMessages::ContractData => Some(1),
413 IncomingMessages::ContractDataEnd => Some(2),
414 IncomingMessages::ExecutionData => Some(1),
416 IncomingMessages::ExecutionDataEnd => Some(2),
417 IncomingMessages::HeadTimestamp => Some(1),
418 IncomingMessages::HistogramData => Some(1),
419 IncomingMessages::HistoricalData => Some(1),
420 IncomingMessages::HistoricalDataEnd => Some(1),
421 IncomingMessages::HistoricalDataUpdate => Some(1),
422 IncomingMessages::HistoricalNews => Some(1),
423 IncomingMessages::HistoricalNewsEnd => Some(1),
424 IncomingMessages::HistoricalSchedule => Some(1),
425 IncomingMessages::HistoricalTick => Some(1),
426 IncomingMessages::HistoricalTickBidAsk => Some(1),
427 IncomingMessages::HistoricalTickLast => Some(1),
428 IncomingMessages::MarketDepth => Some(2),
429 IncomingMessages::MarketDepthL2 => Some(2),
430 IncomingMessages::NewsArticle => Some(1),
431 IncomingMessages::OpenOrder => Some(1),
432 IncomingMessages::PnL => Some(1),
433 IncomingMessages::PnLSingle => Some(1),
434 IncomingMessages::PositionMulti => Some(2),
435 IncomingMessages::PositionMultiEnd => Some(2),
436 IncomingMessages::RealTimeBars => Some(2),
437 IncomingMessages::ScannerData => Some(2),
438 IncomingMessages::SecurityDefinitionOptionParameter => Some(1),
439 IncomingMessages::SecurityDefinitionOptionParameterEnd => Some(1),
440 IncomingMessages::SymbolSamples => Some(1),
441 IncomingMessages::TickByTick => Some(1),
442 IncomingMessages::TickEFP => Some(2),
443 IncomingMessages::TickGeneric => Some(2),
444 IncomingMessages::TickNews => Some(1),
445 IncomingMessages::TickOptionComputation => Some(1),
446 IncomingMessages::TickPrice => Some(2),
447 IncomingMessages::TickReqParams => Some(1),
448 IncomingMessages::TickSize => Some(2),
449 IncomingMessages::TickSnapshotEnd => Some(2),
450 IncomingMessages::TickString => Some(2),
451 IncomingMessages::WshEventData => Some(1),
452 IncomingMessages::WshMetaData => Some(1),
453 IncomingMessages::DisplayGroupList => Some(2),
454 IncomingMessages::DisplayGroupUpdated => Some(2),
455
456 _ => {
457 debug!("could not determine request id index for {kind:?} (this message type may not have a request id).");
458 None
459 }
460 }
461}
462
463#[allow(dead_code)]
465#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
466pub enum OutgoingMessages {
467 RequestMarketData = 1,
469 CancelMarketData = 2,
471 PlaceOrder = 3,
473 CancelOrder = 4,
475 RequestOpenOrders = 5,
477 RequestAccountData = 6,
479 RequestExecutions = 7,
481 RequestIds = 8,
483 RequestContractData = 9,
485 RequestMarketDepth = 10,
487 CancelMarketDepth = 11,
489 RequestNewsBulletins = 12,
491 CancelNewsBulletin = 13,
493 ChangeServerLog = 14,
495 RequestAutoOpenOrders = 15,
497 RequestAllOpenOrders = 16,
499 RequestManagedAccounts = 17,
501 RequestFA = 18,
503 ReplaceFA = 19,
505 RequestHistoricalData = 20,
507 ExerciseOptions = 21,
509 RequestScannerSubscription = 22,
511 CancelScannerSubscription = 23,
513 RequestScannerParameters = 24,
515 CancelHistoricalData = 25,
517 RequestCurrentTime = 49,
519 RequestRealTimeBars = 50,
521 CancelRealTimeBars = 51,
523 RequestFundamentalData = 52,
525 CancelFundamentalData = 53,
527 ReqCalcImpliedVolat = 54,
529 ReqCalcOptionPrice = 55,
531 CancelImpliedVolatility = 56,
533 CancelOptionPrice = 57,
535 RequestGlobalCancel = 58,
537 RequestMarketDataType = 59,
539 RequestPositions = 61,
541 RequestAccountSummary = 62,
543 CancelAccountSummary = 63,
545 CancelPositions = 64,
547 VerifyRequest = 65,
549 VerifyMessage = 66,
551 QueryDisplayGroups = 67,
553 SubscribeToGroupEvents = 68,
555 UpdateDisplayGroup = 69,
557 UnsubscribeFromGroupEvents = 70,
559 StartApi = 71,
561 VerifyAndAuthRequest = 72,
563 VerifyAndAuthMessage = 73,
565 RequestPositionsMulti = 74,
567 CancelPositionsMulti = 75,
569 RequestAccountUpdatesMulti = 76,
571 CancelAccountUpdatesMulti = 77,
573 RequestSecurityDefinitionOptionalParameters = 78,
575 RequestSoftDollarTiers = 79,
577 RequestFamilyCodes = 80,
579 RequestMatchingSymbols = 81,
581 RequestMktDepthExchanges = 82,
583 RequestSmartComponents = 83,
585 RequestNewsArticle = 84,
587 RequestNewsProviders = 85,
589 RequestHistoricalNews = 86,
591 RequestHeadTimestamp = 87,
593 RequestHistogramData = 88,
595 CancelHistogramData = 89,
597 CancelHeadTimestamp = 90,
599 RequestMarketRule = 91,
601 RequestPnL = 92,
603 CancelPnL = 93,
605 RequestPnLSingle = 94,
607 CancelPnLSingle = 95,
609 RequestHistoricalTicks = 96,
611 RequestTickByTickData = 97,
613 CancelTickByTickData = 98,
615 RequestCompletedOrders = 99,
617 RequestWshMetaData = 100,
619 CancelWshMetaData = 101,
621 RequestWshEventData = 102,
623 CancelWshEventData = 103,
625 RequestUserInfo = 104,
627 RequestCurrentTimeInMillis = 105,
629 CancelContractData = 106,
631 CancelHistoricalTicks = 107,
633 ReqConfig = 108,
635 UpdateConfig = 109,
637}
638
639impl ToField for OutgoingMessages {
640 fn to_field(&self) -> String {
641 (*self as i32).to_string()
642 }
643}
644
645impl std::fmt::Display for OutgoingMessages {
646 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
647 write!(f, "{}", *self as i32)
648 }
649}
650
651impl FromStr for OutgoingMessages {
652 type Err = Error;
653
654 fn from_str(s: &str) -> Result<Self, Self::Err> {
655 match s.parse::<i32>() {
656 Ok(1) => Ok(OutgoingMessages::RequestMarketData),
657 Ok(2) => Ok(OutgoingMessages::CancelMarketData),
658 Ok(3) => Ok(OutgoingMessages::PlaceOrder),
659 Ok(4) => Ok(OutgoingMessages::CancelOrder),
660 Ok(5) => Ok(OutgoingMessages::RequestOpenOrders),
661 Ok(6) => Ok(OutgoingMessages::RequestAccountData),
662 Ok(7) => Ok(OutgoingMessages::RequestExecutions),
663 Ok(8) => Ok(OutgoingMessages::RequestIds),
664 Ok(9) => Ok(OutgoingMessages::RequestContractData),
665 Ok(10) => Ok(OutgoingMessages::RequestMarketDepth),
666 Ok(11) => Ok(OutgoingMessages::CancelMarketDepth),
667 Ok(12) => Ok(OutgoingMessages::RequestNewsBulletins),
668 Ok(13) => Ok(OutgoingMessages::CancelNewsBulletin),
669 Ok(14) => Ok(OutgoingMessages::ChangeServerLog),
670 Ok(15) => Ok(OutgoingMessages::RequestAutoOpenOrders),
671 Ok(16) => Ok(OutgoingMessages::RequestAllOpenOrders),
672 Ok(17) => Ok(OutgoingMessages::RequestManagedAccounts),
673 Ok(18) => Ok(OutgoingMessages::RequestFA),
674 Ok(19) => Ok(OutgoingMessages::ReplaceFA),
675 Ok(20) => Ok(OutgoingMessages::RequestHistoricalData),
676 Ok(21) => Ok(OutgoingMessages::ExerciseOptions),
677 Ok(22) => Ok(OutgoingMessages::RequestScannerSubscription),
678 Ok(23) => Ok(OutgoingMessages::CancelScannerSubscription),
679 Ok(24) => Ok(OutgoingMessages::RequestScannerParameters),
680 Ok(25) => Ok(OutgoingMessages::CancelHistoricalData),
681 Ok(49) => Ok(OutgoingMessages::RequestCurrentTime),
682 Ok(50) => Ok(OutgoingMessages::RequestRealTimeBars),
683 Ok(51) => Ok(OutgoingMessages::CancelRealTimeBars),
684 Ok(52) => Ok(OutgoingMessages::RequestFundamentalData),
685 Ok(53) => Ok(OutgoingMessages::CancelFundamentalData),
686 Ok(54) => Ok(OutgoingMessages::ReqCalcImpliedVolat),
687 Ok(55) => Ok(OutgoingMessages::ReqCalcOptionPrice),
688 Ok(56) => Ok(OutgoingMessages::CancelImpliedVolatility),
689 Ok(57) => Ok(OutgoingMessages::CancelOptionPrice),
690 Ok(58) => Ok(OutgoingMessages::RequestGlobalCancel),
691 Ok(59) => Ok(OutgoingMessages::RequestMarketDataType),
692 Ok(61) => Ok(OutgoingMessages::RequestPositions),
693 Ok(62) => Ok(OutgoingMessages::RequestAccountSummary),
694 Ok(63) => Ok(OutgoingMessages::CancelAccountSummary),
695 Ok(64) => Ok(OutgoingMessages::CancelPositions),
696 Ok(65) => Ok(OutgoingMessages::VerifyRequest),
697 Ok(66) => Ok(OutgoingMessages::VerifyMessage),
698 Ok(67) => Ok(OutgoingMessages::QueryDisplayGroups),
699 Ok(68) => Ok(OutgoingMessages::SubscribeToGroupEvents),
700 Ok(69) => Ok(OutgoingMessages::UpdateDisplayGroup),
701 Ok(70) => Ok(OutgoingMessages::UnsubscribeFromGroupEvents),
702 Ok(71) => Ok(OutgoingMessages::StartApi),
703 Ok(72) => Ok(OutgoingMessages::VerifyAndAuthRequest),
704 Ok(73) => Ok(OutgoingMessages::VerifyAndAuthMessage),
705 Ok(74) => Ok(OutgoingMessages::RequestPositionsMulti),
706 Ok(75) => Ok(OutgoingMessages::CancelPositionsMulti),
707 Ok(76) => Ok(OutgoingMessages::RequestAccountUpdatesMulti),
708 Ok(77) => Ok(OutgoingMessages::CancelAccountUpdatesMulti),
709 Ok(78) => Ok(OutgoingMessages::RequestSecurityDefinitionOptionalParameters),
710 Ok(79) => Ok(OutgoingMessages::RequestSoftDollarTiers),
711 Ok(80) => Ok(OutgoingMessages::RequestFamilyCodes),
712 Ok(81) => Ok(OutgoingMessages::RequestMatchingSymbols),
713 Ok(82) => Ok(OutgoingMessages::RequestMktDepthExchanges),
714 Ok(83) => Ok(OutgoingMessages::RequestSmartComponents),
715 Ok(84) => Ok(OutgoingMessages::RequestNewsArticle),
716 Ok(85) => Ok(OutgoingMessages::RequestNewsProviders),
717 Ok(86) => Ok(OutgoingMessages::RequestHistoricalNews),
718 Ok(87) => Ok(OutgoingMessages::RequestHeadTimestamp),
719 Ok(88) => Ok(OutgoingMessages::RequestHistogramData),
720 Ok(89) => Ok(OutgoingMessages::CancelHistogramData),
721 Ok(90) => Ok(OutgoingMessages::CancelHeadTimestamp),
722 Ok(91) => Ok(OutgoingMessages::RequestMarketRule),
723 Ok(92) => Ok(OutgoingMessages::RequestPnL),
724 Ok(93) => Ok(OutgoingMessages::CancelPnL),
725 Ok(94) => Ok(OutgoingMessages::RequestPnLSingle),
726 Ok(95) => Ok(OutgoingMessages::CancelPnLSingle),
727 Ok(96) => Ok(OutgoingMessages::RequestHistoricalTicks),
728 Ok(97) => Ok(OutgoingMessages::RequestTickByTickData),
729 Ok(98) => Ok(OutgoingMessages::CancelTickByTickData),
730 Ok(99) => Ok(OutgoingMessages::RequestCompletedOrders),
731 Ok(100) => Ok(OutgoingMessages::RequestWshMetaData),
732 Ok(101) => Ok(OutgoingMessages::CancelWshMetaData),
733 Ok(102) => Ok(OutgoingMessages::RequestWshEventData),
734 Ok(103) => Ok(OutgoingMessages::CancelWshEventData),
735 Ok(104) => Ok(OutgoingMessages::RequestUserInfo),
736 Ok(105) => Ok(OutgoingMessages::RequestCurrentTimeInMillis),
737 Ok(106) => Ok(OutgoingMessages::CancelContractData),
738 Ok(107) => Ok(OutgoingMessages::CancelHistoricalTicks),
739 Ok(108) => Ok(OutgoingMessages::ReqConfig),
740 Ok(109) => Ok(OutgoingMessages::UpdateConfig),
741 Ok(n) => Err(Error::Simple(format!("Unknown outgoing message type: {}", n))),
742 Err(_) => Err(Error::Simple(format!("Invalid outgoing message type: {}", s))),
743 }
744 }
745}
746
747pub fn encode_length(message: &str) -> Vec<u8> {
749 let data = message.as_bytes();
750
751 let mut packet: Vec<u8> = Vec::with_capacity(data.len() + 4);
752
753 packet.write_u32::<BigEndian>(data.len() as u32).unwrap();
754 packet.write_all(data).unwrap();
755 packet
756}
757
758#[derive(Default, Debug, Clone)]
760pub struct RequestMessage {
761 pub(crate) fields: Vec<String>,
762}
763
764impl RequestMessage {
765 pub fn new() -> Self {
767 Self::default()
768 }
769
770 pub(crate) fn push_field<T: ToField>(&mut self, val: &T) -> &RequestMessage {
771 let field = val.to_field();
772 self.fields.push(field);
773 self
774 }
775
776 pub fn encode(&self) -> String {
778 let mut data = self.fields.join("\0");
779 data.push('\0');
780 data
781 }
782
783 #[cfg(test)]
784 pub(crate) fn len(&self) -> usize {
785 self.fields.len()
786 }
787
788 #[cfg(test)]
789 pub(crate) fn encode_simple(&self) -> String {
791 let mut data = self.fields.join("|");
792 data.push('|');
793 data
794 }
795 #[cfg(test)]
796 pub fn from(fields: &str) -> RequestMessage {
798 RequestMessage {
799 fields: fields.split_terminator('\x00').map(|x| x.to_string()).collect(),
800 }
801 }
802 #[cfg(test)]
803 pub fn from_simple(fields: &str) -> RequestMessage {
805 RequestMessage {
806 fields: fields.split_terminator('|').map(|x| x.to_string()).collect(),
807 }
808 }
809}
810
811impl Index<usize> for RequestMessage {
812 type Output = String;
813
814 fn index(&self, i: usize) -> &Self::Output {
815 &self.fields[i]
816 }
817}
818
819#[derive(Clone, Default, Debug)]
821pub struct ResponseMessage {
822 pub i: usize,
824 pub fields: Vec<String>,
826 pub server_version: i32,
828}
829
830impl ResponseMessage {
831 pub fn len(&self) -> usize {
833 self.fields.len()
834 }
835
836 pub fn is_empty(&self) -> bool {
838 self.fields.is_empty()
839 }
840
841 pub fn is_shutdown(&self) -> bool {
843 self.message_type() == IncomingMessages::Shutdown
844 }
845
846 pub fn message_type(&self) -> IncomingMessages {
848 if self.fields.is_empty() {
849 IncomingMessages::NotValid
850 } else {
851 let message_id = i32::from_str(&self.fields[0]).unwrap_or(-1);
852 IncomingMessages::from(message_id)
853 }
854 }
855
856 pub fn request_id(&self) -> Option<i32> {
858 if let Some(i) = request_id_index(self.message_type()) {
859 if let Ok(request_id) = self.peek_int(i) {
860 return Some(request_id);
861 }
862 }
863 None
864 }
865
866 pub fn order_id(&self) -> Option<i32> {
868 if let Some(i) = order_id_index(self.message_type()) {
869 if let Ok(order_id) = self.peek_int(i) {
870 return Some(order_id);
871 }
872 }
873 None
874 }
875
876 pub fn execution_id(&self) -> Option<String> {
878 match self.message_type() {
879 IncomingMessages::ExecutionData => Some(self.peek_string(14)),
880 IncomingMessages::CommissionsReport => Some(self.peek_string(2)),
881 _ => None,
882 }
883 }
884
885 pub fn peek_int(&self, i: usize) -> Result<i32, Error> {
887 if i >= self.fields.len() {
888 return Err(Error::Simple("expected int and found end of message".into()));
889 }
890
891 let field = &self.fields[i];
892 match field.parse() {
893 Ok(val) => Ok(val),
894 Err(err) => Err(Error::Parse(i, field.into(), err.to_string())),
895 }
896 }
897
898 pub fn peek_long(&self, i: usize) -> Result<i64, Error> {
900 if i >= self.fields.len() {
901 return Err(Error::Simple("expected long and found end of message".into()));
902 }
903
904 let field = &self.fields[i];
905 match field.parse() {
906 Ok(val) => Ok(val),
907 Err(err) => Err(Error::Parse(i, field.into(), err.to_string())),
908 }
909 }
910
911 pub fn peek_string(&self, i: usize) -> String {
913 self.fields[i].to_owned()
914 }
915
916 pub fn next_int(&mut self) -> Result<i32, Error> {
918 if self.i >= self.fields.len() {
919 return Err(Error::Simple("expected int and found end of message".into()));
920 }
921
922 let field = &self.fields[self.i];
923 self.i += 1;
924
925 match field.parse() {
926 Ok(val) => Ok(val),
927 Err(err) => Err(Error::Parse(self.i, field.into(), err.to_string())),
928 }
929 }
930
931 pub fn next_optional_int(&mut self) -> Result<Option<i32>, Error> {
933 if self.i >= self.fields.len() {
934 return Err(Error::Simple("expected optional int and found end of message".into()));
935 }
936
937 let field = &self.fields[self.i];
938 self.i += 1;
939
940 if field.is_empty() || field == UNSET_INTEGER {
941 return Ok(None);
942 }
943
944 match field.parse::<i32>() {
945 Ok(val) => Ok(Some(val)),
946 Err(err) => Err(Error::Parse(self.i, field.into(), err.to_string())),
947 }
948 }
949
950 pub fn next_bool(&mut self) -> Result<bool, Error> {
952 if self.i >= self.fields.len() {
953 return Err(Error::Simple("expected bool and found end of message".into()));
954 }
955
956 let field = &self.fields[self.i];
957 self.i += 1;
958
959 Ok(field == "1")
960 }
961
962 pub fn next_long(&mut self) -> Result<i64, Error> {
964 if self.i >= self.fields.len() {
965 return Err(Error::Simple("expected long and found end of message".into()));
966 }
967
968 let field = &self.fields[self.i];
969 self.i += 1;
970
971 match field.parse() {
972 Ok(val) => Ok(val),
973 Err(err) => Err(Error::Parse(self.i, field.into(), err.to_string())),
974 }
975 }
976
977 pub fn next_optional_long(&mut self) -> Result<Option<i64>, Error> {
979 if self.i >= self.fields.len() {
980 return Err(Error::Simple("expected optional long and found end of message".into()));
981 }
982
983 let field = &self.fields[self.i];
984 self.i += 1;
985
986 if field.is_empty() || field == UNSET_LONG {
987 return Ok(None);
988 }
989
990 match field.parse::<i64>() {
991 Ok(val) => Ok(Some(val)),
992 Err(err) => Err(Error::Parse(self.i, field.into(), err.to_string())),
993 }
994 }
995
996 pub fn next_date_time(&mut self) -> Result<OffsetDateTime, Error> {
998 if self.i >= self.fields.len() {
999 return Err(Error::Simple("expected datetime and found end of message".into()));
1000 }
1001
1002 let field = &self.fields[self.i];
1003 self.i += 1;
1004
1005 if field.is_empty() {
1006 return Err(Error::Simple("expected timestamp and found empty string".into()));
1007 }
1008
1009 let timestamp: i64 = field.parse()?;
1011 match OffsetDateTime::from_unix_timestamp(timestamp) {
1012 Ok(val) => Ok(val),
1013 Err(err) => Err(Error::Parse(self.i, field.into(), err.to_string())),
1014 }
1015 }
1016
1017 pub fn next_string(&mut self) -> Result<String, Error> {
1019 if self.i >= self.fields.len() {
1020 return Err(Error::Simple("expected string and found end of message".into()));
1021 }
1022
1023 let field = &self.fields[self.i];
1024 self.i += 1;
1025 Ok(String::from(field))
1026 }
1027
1028 pub fn next_double(&mut self) -> Result<f64, Error> {
1030 if self.i >= self.fields.len() {
1031 return Err(Error::Simple("expected double and found end of message".into()));
1032 }
1033
1034 let field = &self.fields[self.i];
1035 self.i += 1;
1036
1037 if field.is_empty() || field == "0" || field == "0.0" {
1038 return Ok(0.0);
1039 }
1040
1041 match field.parse() {
1042 Ok(val) => Ok(val),
1043 Err(err) => Err(Error::Parse(self.i, field.into(), err.to_string())),
1044 }
1045 }
1046
1047 pub fn next_optional_double(&mut self) -> Result<Option<f64>, Error> {
1049 if self.i >= self.fields.len() {
1050 return Err(Error::Simple("expected optional double and found end of message".into()));
1051 }
1052
1053 let field = &self.fields[self.i];
1054 self.i += 1;
1055
1056 if field.is_empty() || field == UNSET_DOUBLE {
1057 return Ok(None);
1058 }
1059
1060 if field == INFINITY_STR {
1061 return Ok(Some(f64::INFINITY));
1062 }
1063
1064 match field.parse() {
1065 Ok(val) => Ok(Some(val)),
1066 Err(err) => Err(Error::Parse(self.i, field.into(), err.to_string())),
1067 }
1068 }
1069
1070 fn error_field_offset(&self) -> usize {
1073 if self.server_version >= crate::server_versions::ERROR_TIME {
1074 0
1075 } else {
1076 1
1077 }
1078 }
1079
1080 pub fn error_request_id_index(&self) -> usize {
1082 1 + self.error_field_offset()
1083 }
1084
1085 pub fn error_code_index(&self) -> usize {
1087 2 + self.error_field_offset()
1088 }
1089
1090 pub fn error_message_index(&self) -> usize {
1092 3 + self.error_field_offset()
1093 }
1094
1095 pub fn error_request_id(&self) -> i32 {
1097 self.peek_int(self.error_request_id_index()).unwrap_or(-1)
1098 }
1099
1100 pub fn error_code(&self) -> i32 {
1102 self.peek_int(self.error_code_index()).unwrap_or(0)
1103 }
1104
1105 pub fn error_message(&self) -> String {
1107 let idx = self.error_message_index();
1108 if idx < self.fields.len() {
1109 self.peek_string(idx)
1110 } else {
1111 String::from("Unknown error")
1112 }
1113 }
1114
1115 pub fn error_time(&self) -> Option<OffsetDateTime> {
1118 if self.server_version >= crate::server_versions::ERROR_TIME {
1119 let idx = self.error_message_index() + 2;
1121 let millis = self.peek_long(idx).ok()?;
1122 OffsetDateTime::from_unix_timestamp_nanos(millis as i128 * 1_000_000).ok()
1123 } else {
1124 None
1125 }
1126 }
1127
1128 pub fn from(fields: &str) -> ResponseMessage {
1130 ResponseMessage {
1131 i: 0,
1132 fields: fields.split_terminator('\x00').map(|x| x.to_string()).collect(),
1133 server_version: 0,
1134 }
1135 }
1136 #[cfg(test)]
1137 pub fn from_simple(fields: &str) -> ResponseMessage {
1139 ResponseMessage {
1140 i: 0,
1141 fields: fields.split_terminator('|').map(|x| x.to_string()).collect(),
1142 server_version: 0,
1143 }
1144 }
1145
1146 pub fn with_server_version(mut self, server_version: i32) -> Self {
1148 self.server_version = server_version;
1149 self
1150 }
1151
1152 pub fn skip(&mut self) {
1154 self.i += 1;
1155 }
1156
1157 pub fn encode(&self) -> String {
1159 let mut data = self.fields.join("\0");
1160 data.push('\0');
1161 data
1162 }
1163
1164 #[cfg(test)]
1165 pub fn encode_simple(&self) -> String {
1167 let mut data = self.fields.join("|");
1168 data.push('|');
1169 data
1170 }
1171}
1172
1173#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
1175#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1176pub struct Notice {
1177 pub code: i32,
1179 pub message: String,
1181 pub error_time: Option<OffsetDateTime>,
1184}
1185
1186pub const ORDER_CANCELLED_CODE: i32 = 202;
1188
1189pub const WARNING_CODE_RANGE: std::ops::RangeInclusive<i32> = 2100..=2169;
1191
1192pub const SYSTEM_MESSAGE_CODES: [i32; 4] = [1100, 1101, 1102, 1300];
1198
1199impl Notice {
1200 #[allow(private_interfaces)]
1201 pub fn from(message: &ResponseMessage) -> Notice {
1203 let code = message.error_code();
1204 let error_time = message.error_time();
1205 let message = message.error_message();
1206 Notice { code, message, error_time }
1207 }
1208
1209 pub fn is_cancellation(&self) -> bool {
1214 self.code == ORDER_CANCELLED_CODE
1215 }
1216
1217 pub fn is_warning(&self) -> bool {
1219 WARNING_CODE_RANGE.contains(&self.code)
1220 }
1221
1222 pub fn is_system_message(&self) -> bool {
1230 SYSTEM_MESSAGE_CODES.contains(&self.code)
1231 }
1232
1233 pub fn is_informational(&self) -> bool {
1238 self.is_cancellation() || self.is_warning() || self.is_system_message()
1239 }
1240
1241 pub fn is_error(&self) -> bool {
1246 !self.is_informational()
1247 }
1248}
1249
1250impl Display for Notice {
1251 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1252 write!(f, "[{}] {}", self.code, self.message)
1253 }
1254}