1use std::{fmt::Display, str::FromStr};
17
18use nautilus_model::enums::{
19 OrderSide, OrderStatus as NautilusOrderStatus, OrderType as NautilusOrderType,
20 TimeInForce as NautilusTimeInForce,
21};
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25#[cfg_attr(
26 feature = "python",
27 pyo3::pyclass(
28 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
29 from_py_object
30 )
31)]
32pub enum IbAction {
33 Buy,
35 Bought,
37 Sell,
39 Sold,
41 SellShort,
43 SellLong,
45}
46
47impl IbAction {
48 #[must_use]
50 pub const fn order_side(self) -> OrderSide {
51 match self {
52 Self::Buy | Self::Bought => OrderSide::Buy,
53 Self::Sell | Self::Sold | Self::SellShort | Self::SellLong => OrderSide::Sell,
54 }
55 }
56
57 #[must_use]
59 pub const fn signed_multiplier(self) -> i32 {
60 match self {
61 Self::Buy | Self::Bought => 1,
62 Self::Sell | Self::Sold | Self::SellShort | Self::SellLong => -1,
63 }
64 }
65
66 #[must_use]
68 pub const fn ibapi_action(self) -> ibapi::orders::Action {
69 match self {
70 Self::Buy | Self::Bought => ibapi::orders::Action::Buy,
71 Self::Sell | Self::Sold => ibapi::orders::Action::Sell,
72 Self::SellShort => ibapi::orders::Action::SellShort,
73 Self::SellLong => ibapi::orders::Action::SellLong,
74 }
75 }
76}
77
78impl FromStr for IbAction {
79 type Err = anyhow::Error;
80
81 fn from_str(value: &str) -> Result<Self, Self::Err> {
82 match value {
83 "BUY" => Ok(Self::Buy),
84 "BOT" => Ok(Self::Bought),
85 "SELL" => Ok(Self::Sell),
86 "SLD" => Ok(Self::Sold),
87 "SSHORT" => Ok(Self::SellShort),
88 "SLONG" => Ok(Self::SellLong),
89 _ => anyhow::bail!("Unknown IB action: {value}"),
90 }
91 }
92}
93
94impl From<ibapi::orders::Action> for IbAction {
95 fn from(value: ibapi::orders::Action) -> Self {
96 match value {
97 ibapi::orders::Action::Buy => Self::Buy,
98 ibapi::orders::Action::Sell => Self::Sell,
99 ibapi::orders::Action::SellShort => Self::SellShort,
100 ibapi::orders::Action::SellLong => Self::SellLong,
101 }
102 }
103}
104
105impl Display for IbAction {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 f.write_str(match self {
108 Self::Buy => "BUY",
109 Self::Bought => "BOT",
110 Self::Sell => "SELL",
111 Self::Sold => "SLD",
112 Self::SellShort => "SSHORT",
113 Self::SellLong => "SLONG",
114 })
115 }
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120#[cfg_attr(
121 feature = "python",
122 pyo3::pyclass(
123 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
124 from_py_object
125 )
126)]
127pub enum IbOrderStatus {
128 ApiPending,
130 PendingSubmit,
132 PreSubmitted,
134 Submitted,
136 PendingCancel,
138 ApiCancelled,
140 Cancelled,
142 Filled,
144 Inactive,
146}
147
148impl IbOrderStatus {
149 #[must_use]
151 pub const fn nautilus_status(self) -> NautilusOrderStatus {
152 match self {
153 Self::ApiPending | Self::PendingSubmit | Self::PreSubmitted => {
154 NautilusOrderStatus::Submitted
155 }
156 Self::Submitted => NautilusOrderStatus::Accepted,
157 Self::PendingCancel => NautilusOrderStatus::PendingCancel,
158 Self::ApiCancelled | Self::Cancelled => NautilusOrderStatus::Canceled,
159 Self::Filled => NautilusOrderStatus::Filled,
160 Self::Inactive => NautilusOrderStatus::Rejected,
161 }
162 }
163
164 #[must_use]
166 pub const fn is_accepted(self) -> bool {
167 matches!(self, Self::Submitted | Self::PreSubmitted)
168 }
169
170 #[must_use]
172 pub const fn is_terminal(self) -> bool {
173 matches!(
174 self,
175 Self::Filled | Self::ApiCancelled | Self::Cancelled | Self::Inactive
176 )
177 }
178}
179
180impl FromStr for IbOrderStatus {
181 type Err = anyhow::Error;
182
183 fn from_str(value: &str) -> Result<Self, Self::Err> {
184 match value {
185 "ApiPending" => Ok(Self::ApiPending),
186 "PendingSubmit" => Ok(Self::PendingSubmit),
187 "PreSubmitted" => Ok(Self::PreSubmitted),
188 "Submitted" => Ok(Self::Submitted),
189 "PendingCancel" => Ok(Self::PendingCancel),
190 "ApiCancelled" => Ok(Self::ApiCancelled),
191 "Cancelled" => Ok(Self::Cancelled),
192 "Filled" => Ok(Self::Filled),
193 "Inactive" => Ok(Self::Inactive),
194 _ => anyhow::bail!("Unknown IB order status: {value}"),
195 }
196 }
197}
198
199impl Display for IbOrderStatus {
200 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201 f.write_str(match self {
202 Self::ApiPending => "ApiPending",
203 Self::PendingSubmit => "PendingSubmit",
204 Self::PreSubmitted => "PreSubmitted",
205 Self::Submitted => "Submitted",
206 Self::PendingCancel => "PendingCancel",
207 Self::ApiCancelled => "ApiCancelled",
208 Self::Cancelled => "Cancelled",
209 Self::Filled => "Filled",
210 Self::Inactive => "Inactive",
211 })
212 }
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq)]
217#[cfg_attr(
218 feature = "python",
219 pyo3::pyclass(
220 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
221 from_py_object
222 )
223)]
224pub enum IbOrderType {
225 Market,
227 MarketOnClose,
229 Limit,
231 LimitOnClose,
233 Stop,
235 StopLimit,
237 TrailingStop,
239 TrailingStopLimit,
241 MarketIfTouched,
243 LimitIfTouched,
245 MarketToLimit,
247 MarketWithProtection,
249 StopWithProtection,
251 Midprice,
253 PeggedToMarket,
255 PeggedToStock,
257 PeggedToMidpoint,
259 PeggedToBenchmark,
261 PegBest,
263 Relative,
265 PassiveRelative,
267 Volatility,
269 BoxTop,
271 RelativeLimitCombo,
273 RelativeMarketCombo,
275}
276
277impl IbOrderType {
278 #[must_use]
280 pub const fn as_str(self) -> &'static str {
281 match self {
282 Self::Market => "MKT",
283 Self::MarketOnClose => "MOC",
284 Self::Limit => "LMT",
285 Self::LimitOnClose => "LOC",
286 Self::Stop => "STP",
287 Self::StopLimit => "STP LMT",
288 Self::TrailingStop => "TRAIL",
289 Self::TrailingStopLimit => "TRAIL LIMIT",
290 Self::MarketIfTouched => "MIT",
291 Self::LimitIfTouched => "LIT",
292 Self::MarketToLimit => "MTL",
293 Self::MarketWithProtection => "MKT PRT",
294 Self::StopWithProtection => "STP PRT",
295 Self::Midprice => "MIDPRICE",
296 Self::PeggedToMarket => "PEG MKT",
297 Self::PeggedToStock => "PEG STK",
298 Self::PeggedToMidpoint => "PEG MID",
299 Self::PeggedToBenchmark => "PEG BENCH",
300 Self::PegBest => "PEG BEST",
301 Self::Relative => "REL",
302 Self::PassiveRelative => "PASSV REL",
303 Self::Volatility => "VOL",
304 Self::BoxTop => "BOX TOP",
305 Self::RelativeLimitCombo => "REL + LMT",
306 Self::RelativeMarketCombo => "REL + MKT",
307 }
308 }
309
310 #[must_use]
312 pub const fn nautilus_order_type(self) -> NautilusOrderType {
313 match self {
314 Self::Market | Self::MarketOnClose => NautilusOrderType::Market,
315 Self::Limit | Self::LimitOnClose => NautilusOrderType::Limit,
316 Self::Stop => NautilusOrderType::StopMarket,
317 Self::StopLimit => NautilusOrderType::StopLimit,
318 Self::TrailingStop => NautilusOrderType::TrailingStopMarket,
319 Self::TrailingStopLimit => NautilusOrderType::TrailingStopLimit,
320 Self::MarketIfTouched => NautilusOrderType::MarketIfTouched,
321 Self::LimitIfTouched => NautilusOrderType::LimitIfTouched,
322 Self::MarketToLimit => NautilusOrderType::MarketToLimit,
323 Self::MarketWithProtection
324 | Self::Midprice
325 | Self::PeggedToMarket
326 | Self::PeggedToStock
327 | Self::PeggedToMidpoint
328 | Self::PeggedToBenchmark
329 | Self::PegBest
330 | Self::Relative
331 | Self::PassiveRelative
332 | Self::Volatility
333 | Self::BoxTop
334 | Self::RelativeMarketCombo => NautilusOrderType::Market,
335 Self::RelativeLimitCombo => NautilusOrderType::Limit,
336 Self::StopWithProtection => NautilusOrderType::StopMarket,
337 }
338 }
339
340 #[must_use]
342 pub const fn from_nautilus(
343 order_type: NautilusOrderType,
344 time_in_force: NautilusTimeInForce,
345 ) -> Self {
346 match order_type {
347 NautilusOrderType::Market => {
348 if matches!(time_in_force, NautilusTimeInForce::AtTheClose) {
349 Self::MarketOnClose
350 } else {
351 Self::Market
352 }
353 }
354 NautilusOrderType::Limit => {
355 if matches!(time_in_force, NautilusTimeInForce::AtTheClose) {
356 Self::LimitOnClose
357 } else {
358 Self::Limit
359 }
360 }
361 NautilusOrderType::StopMarket => Self::Stop,
362 NautilusOrderType::StopLimit => Self::StopLimit,
363 NautilusOrderType::MarketIfTouched => Self::MarketIfTouched,
364 NautilusOrderType::LimitIfTouched => Self::LimitIfTouched,
365 NautilusOrderType::TrailingStopMarket => Self::TrailingStop,
366 NautilusOrderType::TrailingStopLimit => Self::TrailingStopLimit,
367 NautilusOrderType::MarketToLimit => Self::MarketToLimit,
368 }
369 }
370}
371
372impl FromStr for IbOrderType {
373 type Err = anyhow::Error;
374
375 fn from_str(value: &str) -> Result<Self, Self::Err> {
376 match value {
377 "MKT" => Ok(Self::Market),
378 "MOC" => Ok(Self::MarketOnClose),
379 "LMT" => Ok(Self::Limit),
380 "LOC" => Ok(Self::LimitOnClose),
381 "STP" => Ok(Self::Stop),
382 "STP LMT" => Ok(Self::StopLimit),
383 "TRAIL" => Ok(Self::TrailingStop),
384 "TRAIL LIMIT" => Ok(Self::TrailingStopLimit),
385 "MIT" => Ok(Self::MarketIfTouched),
386 "LIT" => Ok(Self::LimitIfTouched),
387 "MTL" => Ok(Self::MarketToLimit),
388 "MKT PRT" => Ok(Self::MarketWithProtection),
389 "STP PRT" => Ok(Self::StopWithProtection),
390 "MIDPRICE" => Ok(Self::Midprice),
391 "PEG MKT" => Ok(Self::PeggedToMarket),
392 "PEG STK" => Ok(Self::PeggedToStock),
393 "PEG MID" | "PEGMID" => Ok(Self::PeggedToMidpoint),
394 "PEG BENCH" | "PEGBENCH" => Ok(Self::PeggedToBenchmark),
395 "PEG BEST" | "PEGBEST" => Ok(Self::PegBest),
396 "REL" => Ok(Self::Relative),
397 "PASSV REL" => Ok(Self::PassiveRelative),
398 "VOL" => Ok(Self::Volatility),
399 "BOX TOP" => Ok(Self::BoxTop),
400 "REL + LMT" => Ok(Self::RelativeLimitCombo),
401 "REL + MKT" => Ok(Self::RelativeMarketCombo),
402 _ => anyhow::bail!("Unknown IB order type: {value}"),
403 }
404 }
405}
406
407impl Display for IbOrderType {
408 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
409 f.write_str(self.as_str())
410 }
411}
412
413#[derive(Debug, Clone, Copy, PartialEq, Eq)]
415#[cfg_attr(
416 feature = "python",
417 pyo3::pyclass(
418 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
419 from_py_object
420 )
421)]
422pub enum IbTimeInForce {
423 Day,
425 GoodTilCanceled,
427 ImmediateOrCancel,
429 GoodTilDate,
431 OnOpen,
433 FillOrKill,
435 DayTilCanceled,
437 Auction,
439}
440
441impl IbTimeInForce {
442 #[must_use]
444 pub const fn nautilus_time_in_force(self) -> NautilusTimeInForce {
445 match self {
446 Self::Day | Self::DayTilCanceled | Self::Auction => NautilusTimeInForce::Day,
447 Self::GoodTilCanceled => NautilusTimeInForce::Gtc,
448 Self::ImmediateOrCancel => NautilusTimeInForce::Ioc,
449 Self::GoodTilDate => NautilusTimeInForce::Gtd,
450 Self::OnOpen => NautilusTimeInForce::AtTheOpen,
451 Self::FillOrKill => NautilusTimeInForce::Fok,
452 }
453 }
454
455 #[must_use]
457 pub const fn from_nautilus(time_in_force: NautilusTimeInForce) -> Self {
458 match time_in_force {
459 NautilusTimeInForce::Day | NautilusTimeInForce::AtTheClose => Self::Day,
460 NautilusTimeInForce::Gtc => Self::GoodTilCanceled,
461 NautilusTimeInForce::Ioc => Self::ImmediateOrCancel,
462 NautilusTimeInForce::Fok => Self::FillOrKill,
463 NautilusTimeInForce::Gtd => Self::GoodTilDate,
464 NautilusTimeInForce::AtTheOpen => Self::OnOpen,
465 }
466 }
467
468 #[must_use]
470 pub const fn ibapi_time_in_force(self) -> ibapi::orders::TimeInForce {
471 match self {
472 Self::Day => ibapi::orders::TimeInForce::Day,
473 Self::GoodTilCanceled => ibapi::orders::TimeInForce::GoodTilCanceled,
474 Self::ImmediateOrCancel => ibapi::orders::TimeInForce::ImmediateOrCancel,
475 Self::GoodTilDate => ibapi::orders::TimeInForce::GoodTilDate,
476 Self::OnOpen => ibapi::orders::TimeInForce::OnOpen,
477 Self::FillOrKill => ibapi::orders::TimeInForce::FillOrKill,
478 Self::DayTilCanceled => ibapi::orders::TimeInForce::DayTilCanceled,
479 Self::Auction => ibapi::orders::TimeInForce::Auction,
480 }
481 }
482}
483
484impl From<ibapi::orders::TimeInForce> for IbTimeInForce {
485 fn from(value: ibapi::orders::TimeInForce) -> Self {
486 match value {
487 ibapi::orders::TimeInForce::Day => Self::Day,
488 ibapi::orders::TimeInForce::GoodTilCanceled => Self::GoodTilCanceled,
489 ibapi::orders::TimeInForce::ImmediateOrCancel => Self::ImmediateOrCancel,
490 ibapi::orders::TimeInForce::GoodTilDate => Self::GoodTilDate,
491 ibapi::orders::TimeInForce::OnOpen => Self::OnOpen,
492 ibapi::orders::TimeInForce::FillOrKill => Self::FillOrKill,
493 ibapi::orders::TimeInForce::DayTilCanceled => Self::DayTilCanceled,
494 ibapi::orders::TimeInForce::Auction => Self::Auction,
495 }
496 }
497}
498
499impl FromStr for IbTimeInForce {
500 type Err = anyhow::Error;
501
502 fn from_str(value: &str) -> Result<Self, Self::Err> {
503 match value {
504 "DAY" => Ok(Self::Day),
505 "GTC" => Ok(Self::GoodTilCanceled),
506 "IOC" => Ok(Self::ImmediateOrCancel),
507 "GTD" => Ok(Self::GoodTilDate),
508 "OPG" => Ok(Self::OnOpen),
509 "FOK" => Ok(Self::FillOrKill),
510 "DTC" => Ok(Self::DayTilCanceled),
511 "AUC" => Ok(Self::Auction),
512 _ => anyhow::bail!("Unknown IB time in force: {value}"),
513 }
514 }
515}
516
517impl Display for IbTimeInForce {
518 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
519 f.write_str(match self {
520 Self::Day => "DAY",
521 Self::GoodTilCanceled => "GTC",
522 Self::ImmediateOrCancel => "IOC",
523 Self::GoodTilDate => "GTD",
524 Self::OnOpen => "OPG",
525 Self::FillOrKill => "FOK",
526 Self::DayTilCanceled => "DTC",
527 Self::Auction => "AUC",
528 })
529 }
530}
531
532#[derive(Debug, Clone, Copy, PartialEq, Eq)]
534#[cfg_attr(
535 feature = "python",
536 pyo3::pyclass(
537 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
538 from_py_object
539 )
540)]
541pub enum IbBuilderTimeInForce {
542 Day,
543 GoodTillCancel,
544 ImmediateOrCancel,
545 GoodTillDate,
546 FillOrKill,
547 GoodTillCrossing,
548 DayTillCanceled,
549 Auction,
550 OpeningAuction,
551}
552
553impl IbBuilderTimeInForce {
554 #[must_use]
555 pub const fn as_str(self) -> &'static str {
556 match self {
557 Self::Day => "DAY",
558 Self::GoodTillCancel => "GTC",
559 Self::ImmediateOrCancel => "IOC",
560 Self::GoodTillDate => "GTD",
561 Self::FillOrKill => "FOK",
562 Self::GoodTillCrossing => "GTX",
563 Self::DayTillCanceled => "DTC",
564 Self::Auction => "AUC",
565 Self::OpeningAuction => "OPG",
566 }
567 }
568
569 #[must_use]
570 pub fn ibapi_builder_time_in_force(
571 self,
572 good_till_date: Option<String>,
573 ) -> ibapi::orders::builder::TimeInForce {
574 match self {
575 Self::Day => ibapi::orders::builder::TimeInForce::Day,
576 Self::GoodTillCancel => ibapi::orders::builder::TimeInForce::GoodTillCancel,
577 Self::ImmediateOrCancel => ibapi::orders::builder::TimeInForce::ImmediateOrCancel,
578 Self::GoodTillDate => ibapi::orders::builder::TimeInForce::GoodTillDate {
579 date: good_till_date.unwrap_or_default(),
580 },
581 Self::FillOrKill => ibapi::orders::builder::TimeInForce::FillOrKill,
582 Self::GoodTillCrossing => ibapi::orders::builder::TimeInForce::GoodTillCrossing,
583 Self::DayTillCanceled => ibapi::orders::builder::TimeInForce::DayTillCanceled,
584 Self::Auction => ibapi::orders::builder::TimeInForce::Auction,
585 Self::OpeningAuction => ibapi::orders::builder::TimeInForce::OpeningAuction,
586 }
587 }
588}
589
590impl FromStr for IbBuilderTimeInForce {
591 type Err = anyhow::Error;
592
593 fn from_str(value: &str) -> Result<Self, Self::Err> {
594 match value {
595 "DAY" => Ok(Self::Day),
596 "GTC" => Ok(Self::GoodTillCancel),
597 "IOC" => Ok(Self::ImmediateOrCancel),
598 "GTD" => Ok(Self::GoodTillDate),
599 "FOK" => Ok(Self::FillOrKill),
600 "GTX" => Ok(Self::GoodTillCrossing),
601 "DTC" => Ok(Self::DayTillCanceled),
602 "AUC" => Ok(Self::Auction),
603 "OPG" => Ok(Self::OpeningAuction),
604 _ => anyhow::bail!("Unknown IB builder time in force: {value}"),
605 }
606 }
607}
608
609impl Display for IbBuilderTimeInForce {
610 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
611 f.write_str(self.as_str())
612 }
613}
614
615#[derive(Debug, Clone, Copy, PartialEq, Eq)]
617#[cfg_attr(
618 feature = "python",
619 pyo3::pyclass(
620 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
621 from_py_object
622 )
623)]
624pub enum IbComboLegOpenClose {
625 Same,
626 Open,
627 Close,
628 Unknown,
629}
630
631impl IbComboLegOpenClose {
632 #[must_use]
634 pub const fn as_i32(self) -> i32 {
635 match self {
636 Self::Same => 0,
637 Self::Open => 1,
638 Self::Close => 2,
639 Self::Unknown => 3,
640 }
641 }
642
643 #[must_use]
645 pub const fn ibapi_combo_leg_open_close(self) -> ibapi::contracts::ComboLegOpenClose {
646 match self {
647 Self::Same => ibapi::contracts::ComboLegOpenClose::Same,
648 Self::Open => ibapi::contracts::ComboLegOpenClose::Open,
649 Self::Close => ibapi::contracts::ComboLegOpenClose::Close,
650 Self::Unknown => ibapi::contracts::ComboLegOpenClose::Unknown,
651 }
652 }
653}
654
655impl From<ibapi::contracts::ComboLegOpenClose> for IbComboLegOpenClose {
656 fn from(value: ibapi::contracts::ComboLegOpenClose) -> Self {
657 match value {
658 ibapi::contracts::ComboLegOpenClose::Same => Self::Same,
659 ibapi::contracts::ComboLegOpenClose::Open => Self::Open,
660 ibapi::contracts::ComboLegOpenClose::Close => Self::Close,
661 ibapi::contracts::ComboLegOpenClose::Unknown => Self::Unknown,
662 }
663 }
664}
665
666#[derive(Debug, Clone, Copy, PartialEq, Eq)]
668#[cfg_attr(
669 feature = "python",
670 pyo3::pyclass(
671 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
672 from_py_object
673 )
674)]
675pub enum IbConditionKind {
676 Price,
678 Time,
680 Margin,
682 Execution,
684 Volume,
686 PercentChange,
688}
689
690impl IbConditionKind {
691 #[must_use]
693 pub const fn as_str(self) -> &'static str {
694 match self {
695 Self::Price => "price",
696 Self::Time => "time",
697 Self::Margin => "margin",
698 Self::Execution => "execution",
699 Self::Volume => "volume",
700 Self::PercentChange => "percent_change",
701 }
702 }
703}
704
705impl FromStr for IbConditionKind {
706 type Err = anyhow::Error;
707
708 fn from_str(value: &str) -> Result<Self, Self::Err> {
709 match value.to_ascii_lowercase().as_str() {
710 "price" => Ok(Self::Price),
711 "time" => Ok(Self::Time),
712 "margin" => Ok(Self::Margin),
713 "execution" => Ok(Self::Execution),
714 "volume" => Ok(Self::Volume),
715 "percent_change" | "percentchange" => Ok(Self::PercentChange),
716 _ => anyhow::bail!("Unknown IB condition kind: {value}"),
717 }
718 }
719}
720
721impl Display for IbConditionKind {
722 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
723 f.write_str(self.as_str())
724 }
725}
726
727#[derive(Debug, Clone, Copy, PartialEq, Eq)]
729#[cfg_attr(
730 feature = "python",
731 pyo3::pyclass(
732 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
733 from_py_object
734 )
735)]
736pub enum IbConditionConjunction {
737 And,
739 Or,
741}
742
743impl IbConditionConjunction {
744 #[must_use]
746 pub const fn as_str(self) -> &'static str {
747 match self {
748 Self::And => "and",
749 Self::Or => "or",
750 }
751 }
752
753 #[must_use]
755 pub const fn is_conjunction(self) -> bool {
756 matches!(self, Self::And)
757 }
758}
759
760impl FromStr for IbConditionConjunction {
761 type Err = anyhow::Error;
762
763 fn from_str(value: &str) -> Result<Self, Self::Err> {
764 match value.to_ascii_lowercase().as_str() {
765 "and" | "a" => Ok(Self::And),
766 "or" | "o" => Ok(Self::Or),
767 _ => anyhow::bail!("Unknown IB condition conjunction: {value}"),
768 }
769 }
770}
771
772impl Display for IbConditionConjunction {
773 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
774 f.write_str(self.as_str())
775 }
776}
777
778#[derive(Debug, Clone, Copy, PartialEq, Eq)]
780#[cfg_attr(
781 feature = "python",
782 pyo3::pyclass(
783 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
784 from_py_object
785 )
786)]
787pub enum IbTriggerMethod {
788 Default,
790 DoubleBidAsk,
792 Last,
794 DoubleLast,
796 BidAsk,
798 LastOrBidAsk,
800 Midpoint,
802}
803
804impl IbTriggerMethod {
805 #[must_use]
807 pub const fn as_i32(self) -> i32 {
808 match self {
809 Self::Default => 0,
810 Self::DoubleBidAsk => 1,
811 Self::Last => 2,
812 Self::DoubleLast => 3,
813 Self::BidAsk => 4,
814 Self::LastOrBidAsk => 7,
815 Self::Midpoint => 8,
816 }
817 }
818
819 #[must_use]
821 pub const fn ibapi_trigger_method(self) -> ibapi::orders::conditions::TriggerMethod {
822 match self {
823 Self::Default => ibapi::orders::conditions::TriggerMethod::Default,
824 Self::DoubleBidAsk => ibapi::orders::conditions::TriggerMethod::DoubleBidAsk,
825 Self::Last => ibapi::orders::conditions::TriggerMethod::Last,
826 Self::DoubleLast => ibapi::orders::conditions::TriggerMethod::DoubleLast,
827 Self::BidAsk => ibapi::orders::conditions::TriggerMethod::BidAsk,
828 Self::LastOrBidAsk => ibapi::orders::conditions::TriggerMethod::LastOrBidAsk,
829 Self::Midpoint => ibapi::orders::conditions::TriggerMethod::Midpoint,
830 }
831 }
832}
833
834impl From<i32> for IbTriggerMethod {
835 fn from(value: i32) -> Self {
836 match value {
837 1 => Self::DoubleBidAsk,
838 2 => Self::Last,
839 3 => Self::DoubleLast,
840 4 => Self::BidAsk,
841 7 => Self::LastOrBidAsk,
842 8 => Self::Midpoint,
843 _ => Self::Default,
844 }
845 }
846}
847
848impl From<IbTriggerMethod> for i32 {
849 fn from(value: IbTriggerMethod) -> Self {
850 value.as_i32()
851 }
852}
853
854impl From<ibapi::orders::conditions::TriggerMethod> for IbTriggerMethod {
855 fn from(value: ibapi::orders::conditions::TriggerMethod) -> Self {
856 i32::from(value).into()
857 }
858}
859
860impl Display for IbTriggerMethod {
861 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
862 write!(f, "{}", self.as_i32())
863 }
864}
865
866#[derive(Debug, Clone, Copy, PartialEq, Eq)]
868#[cfg_attr(
869 feature = "python",
870 pyo3::pyclass(
871 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
872 from_py_object
873 )
874)]
875pub enum IbOcaType {
876 None,
878 CancelWithBlock,
880 ReduceWithBlock,
882 ReduceWithoutBlock,
884}
885
886impl IbOcaType {
887 #[must_use]
889 pub const fn as_i32(self) -> i32 {
890 match self {
891 Self::None => 0,
892 Self::CancelWithBlock => 1,
893 Self::ReduceWithBlock => 2,
894 Self::ReduceWithoutBlock => 3,
895 }
896 }
897
898 #[must_use]
900 pub const fn ibapi_oca_type(self) -> ibapi::orders::OcaType {
901 match self {
902 Self::None => ibapi::orders::OcaType::None,
903 Self::CancelWithBlock => ibapi::orders::OcaType::CancelWithBlock,
904 Self::ReduceWithBlock => ibapi::orders::OcaType::ReduceWithBlock,
905 Self::ReduceWithoutBlock => ibapi::orders::OcaType::ReduceWithoutBlock,
906 }
907 }
908}
909
910impl From<i32> for IbOcaType {
911 fn from(value: i32) -> Self {
912 match value {
913 1 => Self::CancelWithBlock,
914 2 => Self::ReduceWithBlock,
915 3 => Self::ReduceWithoutBlock,
916 _ => Self::None,
917 }
918 }
919}
920
921impl From<IbOcaType> for i32 {
922 fn from(value: IbOcaType) -> Self {
923 value.as_i32()
924 }
925}
926
927impl From<ibapi::orders::OcaType> for IbOcaType {
928 fn from(value: ibapi::orders::OcaType) -> Self {
929 i32::from(value).into()
930 }
931}
932
933impl Display for IbOcaType {
934 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
935 write!(f, "{}", self.as_i32())
936 }
937}
938
939#[derive(Debug, Clone, Copy, PartialEq, Eq)]
941#[cfg_attr(
942 feature = "python",
943 pyo3::pyclass(
944 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
945 from_py_object
946 )
947)]
948pub enum IbLiquidity {
949 None,
950 AddedLiquidity,
951 RemovedLiquidity,
952 LiquidityRoutedOut,
953}
954
955impl IbLiquidity {
956 #[must_use]
958 pub const fn as_i32(self) -> i32 {
959 match self {
960 Self::None => 0,
961 Self::AddedLiquidity => 1,
962 Self::RemovedLiquidity => 2,
963 Self::LiquidityRoutedOut => 3,
964 }
965 }
966
967 #[must_use]
969 pub fn ibapi_liquidity(self) -> ibapi::orders::Liquidity {
970 ibapi::orders::Liquidity::from(self.as_i32())
971 }
972}
973
974impl From<i32> for IbLiquidity {
975 fn from(value: i32) -> Self {
976 match value {
977 1 => Self::AddedLiquidity,
978 2 => Self::RemovedLiquidity,
979 3 => Self::LiquidityRoutedOut,
980 _ => Self::None,
981 }
982 }
983}
984
985impl From<ibapi::orders::Liquidity> for IbLiquidity {
986 fn from(value: ibapi::orders::Liquidity) -> Self {
987 match value {
988 ibapi::orders::Liquidity::None => Self::None,
989 ibapi::orders::Liquidity::AddedLiquidity => Self::AddedLiquidity,
990 ibapi::orders::Liquidity::RemovedLiquidity => Self::RemovedLiquidity,
991 ibapi::orders::Liquidity::LiquidityRoutedOut => Self::LiquidityRoutedOut,
992 }
993 }
994}
995
996impl Display for IbLiquidity {
997 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
998 write!(f, "{}", self.as_i32())
999 }
1000}