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.adapters.interactive_brokers",
29 from_py_object,
30 rename_all = "SCREAMING_SNAKE_CASE"
31 )
32)]
33#[cfg_attr(
34 feature = "python",
35 pyo3_stub_gen::derive::gen_stub_pyclass_enum(
36 module = "nautilus_trader.adapters.interactive_brokers"
37 )
38)]
39pub enum IbAction {
40 Buy,
42 Bought,
44 Sell,
46 Sold,
48 SellShort,
50 SellLong,
52}
53
54impl IbAction {
55 #[must_use]
57 pub const fn order_side(self) -> OrderSide {
58 match self {
59 Self::Buy | Self::Bought => OrderSide::Buy,
60 Self::Sell | Self::Sold | Self::SellShort | Self::SellLong => OrderSide::Sell,
61 }
62 }
63
64 #[must_use]
66 pub const fn signed_multiplier(self) -> i32 {
67 match self {
68 Self::Buy | Self::Bought => 1,
69 Self::Sell | Self::Sold | Self::SellShort | Self::SellLong => -1,
70 }
71 }
72
73 #[must_use]
75 pub const fn ibapi_action(self) -> ibapi::orders::Action {
76 match self {
77 Self::Buy | Self::Bought => ibapi::orders::Action::Buy,
78 Self::Sell | Self::Sold => ibapi::orders::Action::Sell,
79 Self::SellShort => ibapi::orders::Action::SellShort,
80 Self::SellLong => ibapi::orders::Action::SellLong,
81 }
82 }
83}
84
85impl FromStr for IbAction {
86 type Err = anyhow::Error;
87
88 fn from_str(value: &str) -> Result<Self, Self::Err> {
89 match value {
90 "BUY" => Ok(Self::Buy),
91 "BOT" => Ok(Self::Bought),
92 "SELL" => Ok(Self::Sell),
93 "SLD" => Ok(Self::Sold),
94 "SSHORT" => Ok(Self::SellShort),
95 "SLONG" => Ok(Self::SellLong),
96 _ => anyhow::bail!("Unknown IB action: {value}"),
97 }
98 }
99}
100
101impl From<ibapi::orders::Action> for IbAction {
102 fn from(value: ibapi::orders::Action) -> Self {
103 match value {
104 ibapi::orders::Action::Buy => Self::Buy,
105 ibapi::orders::Action::Sell => Self::Sell,
106 ibapi::orders::Action::SellShort => Self::SellShort,
107 ibapi::orders::Action::SellLong => Self::SellLong,
108 }
109 }
110}
111
112impl Display for IbAction {
113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 f.write_str(match self {
115 Self::Buy => "BUY",
116 Self::Bought => "BOT",
117 Self::Sell => "SELL",
118 Self::Sold => "SLD",
119 Self::SellShort => "SSHORT",
120 Self::SellLong => "SLONG",
121 })
122 }
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
127#[cfg_attr(
128 feature = "python",
129 pyo3::pyclass(
130 module = "nautilus_trader.adapters.interactive_brokers",
131 from_py_object,
132 rename_all = "SCREAMING_SNAKE_CASE"
133 )
134)]
135#[cfg_attr(
136 feature = "python",
137 pyo3_stub_gen::derive::gen_stub_pyclass_enum(
138 module = "nautilus_trader.adapters.interactive_brokers"
139 )
140)]
141pub enum IbOrderStatus {
142 ApiPending,
144 PendingSubmit,
146 PreSubmitted,
148 Submitted,
150 PendingCancel,
152 ApiCancelled,
154 Cancelled,
156 Filled,
158 Inactive,
160}
161
162impl IbOrderStatus {
163 #[must_use]
165 pub const fn nautilus_status(self) -> NautilusOrderStatus {
166 match self {
167 Self::ApiPending | Self::PendingSubmit | Self::PreSubmitted => {
168 NautilusOrderStatus::Submitted
169 }
170 Self::Submitted => NautilusOrderStatus::Accepted,
171 Self::PendingCancel => NautilusOrderStatus::PendingCancel,
172 Self::ApiCancelled | Self::Cancelled => NautilusOrderStatus::Canceled,
173 Self::Filled => NautilusOrderStatus::Filled,
174 Self::Inactive => NautilusOrderStatus::Rejected,
175 }
176 }
177
178 #[must_use]
180 pub const fn is_accepted(self) -> bool {
181 matches!(self, Self::Submitted | Self::PreSubmitted)
182 }
183
184 #[must_use]
186 pub const fn is_terminal(self) -> bool {
187 matches!(
188 self,
189 Self::Filled | Self::ApiCancelled | Self::Cancelled | Self::Inactive
190 )
191 }
192}
193
194impl FromStr for IbOrderStatus {
195 type Err = anyhow::Error;
196
197 fn from_str(value: &str) -> Result<Self, Self::Err> {
198 match value {
199 "ApiPending" => Ok(Self::ApiPending),
200 "PendingSubmit" => Ok(Self::PendingSubmit),
201 "PreSubmitted" => Ok(Self::PreSubmitted),
202 "Submitted" => Ok(Self::Submitted),
203 "PendingCancel" => Ok(Self::PendingCancel),
204 "ApiCancelled" => Ok(Self::ApiCancelled),
205 "Cancelled" => Ok(Self::Cancelled),
206 "Filled" => Ok(Self::Filled),
207 "Inactive" => Ok(Self::Inactive),
208 _ => anyhow::bail!("Unknown IB order status: {value}"),
209 }
210 }
211}
212
213impl Display for IbOrderStatus {
214 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
215 f.write_str(match self {
216 Self::ApiPending => "ApiPending",
217 Self::PendingSubmit => "PendingSubmit",
218 Self::PreSubmitted => "PreSubmitted",
219 Self::Submitted => "Submitted",
220 Self::PendingCancel => "PendingCancel",
221 Self::ApiCancelled => "ApiCancelled",
222 Self::Cancelled => "Cancelled",
223 Self::Filled => "Filled",
224 Self::Inactive => "Inactive",
225 })
226 }
227}
228
229#[derive(Debug, Clone, Copy, PartialEq, Eq)]
231#[cfg_attr(
232 feature = "python",
233 pyo3::pyclass(
234 module = "nautilus_trader.adapters.interactive_brokers",
235 from_py_object,
236 rename_all = "SCREAMING_SNAKE_CASE"
237 )
238)]
239#[cfg_attr(
240 feature = "python",
241 pyo3_stub_gen::derive::gen_stub_pyclass_enum(
242 module = "nautilus_trader.adapters.interactive_brokers"
243 )
244)]
245pub enum IbOrderType {
246 Market,
248 MarketOnClose,
250 Limit,
252 LimitOnClose,
254 Stop,
256 StopLimit,
258 TrailingStop,
260 TrailingStopLimit,
262 MarketIfTouched,
264 LimitIfTouched,
266 MarketToLimit,
268 MarketWithProtection,
270 StopWithProtection,
272 Midprice,
274 PeggedToMarket,
276 PeggedToStock,
278 PeggedToMidpoint,
280 PeggedToBenchmark,
282 PegBest,
284 Relative,
286 PassiveRelative,
288 Volatility,
290 BoxTop,
292 RelativeLimitCombo,
294 RelativeMarketCombo,
296}
297
298impl IbOrderType {
299 #[must_use]
301 pub const fn as_str(self) -> &'static str {
302 match self {
303 Self::Market => "MKT",
304 Self::MarketOnClose => "MOC",
305 Self::Limit => "LMT",
306 Self::LimitOnClose => "LOC",
307 Self::Stop => "STP",
308 Self::StopLimit => "STP LMT",
309 Self::TrailingStop => "TRAIL",
310 Self::TrailingStopLimit => "TRAIL LIMIT",
311 Self::MarketIfTouched => "MIT",
312 Self::LimitIfTouched => "LIT",
313 Self::MarketToLimit => "MTL",
314 Self::MarketWithProtection => "MKT PRT",
315 Self::StopWithProtection => "STP PRT",
316 Self::Midprice => "MIDPRICE",
317 Self::PeggedToMarket => "PEG MKT",
318 Self::PeggedToStock => "PEG STK",
319 Self::PeggedToMidpoint => "PEG MID",
320 Self::PeggedToBenchmark => "PEG BENCH",
321 Self::PegBest => "PEG BEST",
322 Self::Relative => "REL",
323 Self::PassiveRelative => "PASSV REL",
324 Self::Volatility => "VOL",
325 Self::BoxTop => "BOX TOP",
326 Self::RelativeLimitCombo => "REL + LMT",
327 Self::RelativeMarketCombo => "REL + MKT",
328 }
329 }
330
331 #[must_use]
333 pub const fn nautilus_order_type(self) -> NautilusOrderType {
334 match self {
335 Self::Market | Self::MarketOnClose => NautilusOrderType::Market,
336 Self::Limit | Self::LimitOnClose => NautilusOrderType::Limit,
337 Self::Stop => NautilusOrderType::StopMarket,
338 Self::StopLimit => NautilusOrderType::StopLimit,
339 Self::TrailingStop => NautilusOrderType::TrailingStopMarket,
340 Self::TrailingStopLimit => NautilusOrderType::TrailingStopLimit,
341 Self::MarketIfTouched => NautilusOrderType::MarketIfTouched,
342 Self::LimitIfTouched => NautilusOrderType::LimitIfTouched,
343 Self::MarketToLimit => NautilusOrderType::MarketToLimit,
344 Self::MarketWithProtection
345 | Self::Midprice
346 | Self::PeggedToMarket
347 | Self::PeggedToStock
348 | Self::PeggedToMidpoint
349 | Self::PeggedToBenchmark
350 | Self::PegBest
351 | Self::Relative
352 | Self::PassiveRelative
353 | Self::Volatility
354 | Self::BoxTop
355 | Self::RelativeMarketCombo => NautilusOrderType::Market,
356 Self::RelativeLimitCombo => NautilusOrderType::Limit,
357 Self::StopWithProtection => NautilusOrderType::StopMarket,
358 }
359 }
360
361 #[must_use]
363 pub const fn from_nautilus(
364 order_type: NautilusOrderType,
365 time_in_force: NautilusTimeInForce,
366 ) -> Self {
367 match order_type {
368 NautilusOrderType::Market => {
369 if matches!(time_in_force, NautilusTimeInForce::AtTheClose) {
370 Self::MarketOnClose
371 } else {
372 Self::Market
373 }
374 }
375 NautilusOrderType::Limit => {
376 if matches!(time_in_force, NautilusTimeInForce::AtTheClose) {
377 Self::LimitOnClose
378 } else {
379 Self::Limit
380 }
381 }
382 NautilusOrderType::StopMarket => Self::Stop,
383 NautilusOrderType::StopLimit => Self::StopLimit,
384 NautilusOrderType::MarketIfTouched => Self::MarketIfTouched,
385 NautilusOrderType::LimitIfTouched => Self::LimitIfTouched,
386 NautilusOrderType::TrailingStopMarket => Self::TrailingStop,
387 NautilusOrderType::TrailingStopLimit => Self::TrailingStopLimit,
388 NautilusOrderType::MarketToLimit => Self::MarketToLimit,
389 }
390 }
391}
392
393impl FromStr for IbOrderType {
394 type Err = anyhow::Error;
395
396 fn from_str(value: &str) -> Result<Self, Self::Err> {
397 match value {
398 "MKT" => Ok(Self::Market),
399 "MOC" => Ok(Self::MarketOnClose),
400 "LMT" => Ok(Self::Limit),
401 "LOC" => Ok(Self::LimitOnClose),
402 "STP" => Ok(Self::Stop),
403 "STP LMT" => Ok(Self::StopLimit),
404 "TRAIL" => Ok(Self::TrailingStop),
405 "TRAIL LIMIT" => Ok(Self::TrailingStopLimit),
406 "MIT" => Ok(Self::MarketIfTouched),
407 "LIT" => Ok(Self::LimitIfTouched),
408 "MTL" => Ok(Self::MarketToLimit),
409 "MKT PRT" => Ok(Self::MarketWithProtection),
410 "STP PRT" => Ok(Self::StopWithProtection),
411 "MIDPRICE" => Ok(Self::Midprice),
412 "PEG MKT" => Ok(Self::PeggedToMarket),
413 "PEG STK" => Ok(Self::PeggedToStock),
414 "PEG MID" | "PEGMID" => Ok(Self::PeggedToMidpoint),
415 "PEG BENCH" | "PEGBENCH" => Ok(Self::PeggedToBenchmark),
416 "PEG BEST" | "PEGBEST" => Ok(Self::PegBest),
417 "REL" => Ok(Self::Relative),
418 "PASSV REL" => Ok(Self::PassiveRelative),
419 "VOL" => Ok(Self::Volatility),
420 "BOX TOP" => Ok(Self::BoxTop),
421 "REL + LMT" => Ok(Self::RelativeLimitCombo),
422 "REL + MKT" => Ok(Self::RelativeMarketCombo),
423 _ => anyhow::bail!("Unknown IB order type: {value}"),
424 }
425 }
426}
427
428impl Display for IbOrderType {
429 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
430 f.write_str(self.as_str())
431 }
432}
433
434#[derive(Debug, Clone, Copy, PartialEq, Eq)]
436#[cfg_attr(
437 feature = "python",
438 pyo3::pyclass(
439 module = "nautilus_trader.adapters.interactive_brokers",
440 from_py_object,
441 rename_all = "SCREAMING_SNAKE_CASE"
442 )
443)]
444#[cfg_attr(
445 feature = "python",
446 pyo3_stub_gen::derive::gen_stub_pyclass_enum(
447 module = "nautilus_trader.adapters.interactive_brokers"
448 )
449)]
450pub enum IbTimeInForce {
451 Day,
453 GoodTilCanceled,
455 ImmediateOrCancel,
457 GoodTilDate,
459 OnOpen,
461 FillOrKill,
463 DayTilCanceled,
465 Auction,
467}
468
469impl IbTimeInForce {
470 #[must_use]
472 pub const fn nautilus_time_in_force(self) -> NautilusTimeInForce {
473 match self {
474 Self::Day | Self::DayTilCanceled | Self::Auction => NautilusTimeInForce::Day,
475 Self::GoodTilCanceled => NautilusTimeInForce::Gtc,
476 Self::ImmediateOrCancel => NautilusTimeInForce::Ioc,
477 Self::GoodTilDate => NautilusTimeInForce::Gtd,
478 Self::OnOpen => NautilusTimeInForce::AtTheOpen,
479 Self::FillOrKill => NautilusTimeInForce::Fok,
480 }
481 }
482
483 #[must_use]
485 pub const fn from_nautilus(time_in_force: NautilusTimeInForce) -> Self {
486 match time_in_force {
487 NautilusTimeInForce::Day | NautilusTimeInForce::AtTheClose => Self::Day,
488 NautilusTimeInForce::Gtc => Self::GoodTilCanceled,
489 NautilusTimeInForce::Ioc => Self::ImmediateOrCancel,
490 NautilusTimeInForce::Fok => Self::FillOrKill,
491 NautilusTimeInForce::Gtd => Self::GoodTilDate,
492 NautilusTimeInForce::AtTheOpen => Self::OnOpen,
493 }
494 }
495
496 #[must_use]
498 pub const fn ibapi_time_in_force(self) -> ibapi::orders::TimeInForce {
499 match self {
500 Self::Day => ibapi::orders::TimeInForce::Day,
501 Self::GoodTilCanceled => ibapi::orders::TimeInForce::GoodTilCanceled,
502 Self::ImmediateOrCancel => ibapi::orders::TimeInForce::ImmediateOrCancel,
503 Self::GoodTilDate => ibapi::orders::TimeInForce::GoodTilDate,
504 Self::OnOpen => ibapi::orders::TimeInForce::OnOpen,
505 Self::FillOrKill => ibapi::orders::TimeInForce::FillOrKill,
506 Self::DayTilCanceled => ibapi::orders::TimeInForce::DayTilCanceled,
507 Self::Auction => ibapi::orders::TimeInForce::Auction,
508 }
509 }
510}
511
512impl From<ibapi::orders::TimeInForce> for IbTimeInForce {
513 fn from(value: ibapi::orders::TimeInForce) -> Self {
514 match value {
515 ibapi::orders::TimeInForce::Day => Self::Day,
516 ibapi::orders::TimeInForce::GoodTilCanceled => Self::GoodTilCanceled,
517 ibapi::orders::TimeInForce::ImmediateOrCancel => Self::ImmediateOrCancel,
518 ibapi::orders::TimeInForce::GoodTilDate => Self::GoodTilDate,
519 ibapi::orders::TimeInForce::OnOpen => Self::OnOpen,
520 ibapi::orders::TimeInForce::FillOrKill => Self::FillOrKill,
521 ibapi::orders::TimeInForce::DayTilCanceled => Self::DayTilCanceled,
522 ibapi::orders::TimeInForce::Auction => Self::Auction,
523 }
524 }
525}
526
527impl FromStr for IbTimeInForce {
528 type Err = anyhow::Error;
529
530 fn from_str(value: &str) -> Result<Self, Self::Err> {
531 match value {
532 "DAY" => Ok(Self::Day),
533 "GTC" => Ok(Self::GoodTilCanceled),
534 "IOC" => Ok(Self::ImmediateOrCancel),
535 "GTD" => Ok(Self::GoodTilDate),
536 "OPG" => Ok(Self::OnOpen),
537 "FOK" => Ok(Self::FillOrKill),
538 "DTC" => Ok(Self::DayTilCanceled),
539 "AUC" => Ok(Self::Auction),
540 _ => anyhow::bail!("Unknown IB time in force: {value}"),
541 }
542 }
543}
544
545impl Display for IbTimeInForce {
546 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
547 f.write_str(match self {
548 Self::Day => "DAY",
549 Self::GoodTilCanceled => "GTC",
550 Self::ImmediateOrCancel => "IOC",
551 Self::GoodTilDate => "GTD",
552 Self::OnOpen => "OPG",
553 Self::FillOrKill => "FOK",
554 Self::DayTilCanceled => "DTC",
555 Self::Auction => "AUC",
556 })
557 }
558}
559
560#[derive(Debug, Clone, Copy, PartialEq, Eq)]
562#[cfg_attr(
563 feature = "python",
564 pyo3::pyclass(
565 module = "nautilus_trader.adapters.interactive_brokers",
566 from_py_object,
567 rename_all = "SCREAMING_SNAKE_CASE"
568 )
569)]
570#[cfg_attr(
571 feature = "python",
572 pyo3_stub_gen::derive::gen_stub_pyclass_enum(
573 module = "nautilus_trader.adapters.interactive_brokers"
574 )
575)]
576pub enum IbBuilderTimeInForce {
577 Day,
578 GoodTillCancel,
579 ImmediateOrCancel,
580 GoodTillDate,
581 FillOrKill,
582 GoodTillCrossing,
583 DayTillCanceled,
584 Auction,
585 OpeningAuction,
586}
587
588impl IbBuilderTimeInForce {
589 #[must_use]
590 pub const fn as_str(self) -> &'static str {
591 match self {
592 Self::Day => "DAY",
593 Self::GoodTillCancel => "GTC",
594 Self::ImmediateOrCancel => "IOC",
595 Self::GoodTillDate => "GTD",
596 Self::FillOrKill => "FOK",
597 Self::GoodTillCrossing => "GTX",
598 Self::DayTillCanceled => "DTC",
599 Self::Auction => "AUC",
600 Self::OpeningAuction => "OPG",
601 }
602 }
603
604 #[must_use]
605 pub fn ibapi_builder_time_in_force(
606 self,
607 good_till_date: Option<String>,
608 ) -> ibapi::orders::builder::TimeInForce {
609 match self {
610 Self::Day => ibapi::orders::builder::TimeInForce::Day,
611 Self::GoodTillCancel => ibapi::orders::builder::TimeInForce::GoodTillCancel,
612 Self::ImmediateOrCancel => ibapi::orders::builder::TimeInForce::ImmediateOrCancel,
613 Self::GoodTillDate => ibapi::orders::builder::TimeInForce::GoodTillDate {
614 date: good_till_date.unwrap_or_default(),
615 },
616 Self::FillOrKill => ibapi::orders::builder::TimeInForce::FillOrKill,
617 Self::GoodTillCrossing => ibapi::orders::builder::TimeInForce::GoodTillCrossing,
618 Self::DayTillCanceled => ibapi::orders::builder::TimeInForce::DayTillCanceled,
619 Self::Auction => ibapi::orders::builder::TimeInForce::Auction,
620 Self::OpeningAuction => ibapi::orders::builder::TimeInForce::OpeningAuction,
621 }
622 }
623}
624
625impl FromStr for IbBuilderTimeInForce {
626 type Err = anyhow::Error;
627
628 fn from_str(value: &str) -> Result<Self, Self::Err> {
629 match value {
630 "DAY" => Ok(Self::Day),
631 "GTC" => Ok(Self::GoodTillCancel),
632 "IOC" => Ok(Self::ImmediateOrCancel),
633 "GTD" => Ok(Self::GoodTillDate),
634 "FOK" => Ok(Self::FillOrKill),
635 "GTX" => Ok(Self::GoodTillCrossing),
636 "DTC" => Ok(Self::DayTillCanceled),
637 "AUC" => Ok(Self::Auction),
638 "OPG" => Ok(Self::OpeningAuction),
639 _ => anyhow::bail!("Unknown IB builder time in force: {value}"),
640 }
641 }
642}
643
644impl Display for IbBuilderTimeInForce {
645 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
646 f.write_str(self.as_str())
647 }
648}
649
650#[derive(Debug, Clone, Copy, PartialEq, Eq)]
652#[cfg_attr(
653 feature = "python",
654 pyo3::pyclass(
655 module = "nautilus_trader.adapters.interactive_brokers",
656 from_py_object,
657 rename_all = "SCREAMING_SNAKE_CASE"
658 )
659)]
660#[cfg_attr(
661 feature = "python",
662 pyo3_stub_gen::derive::gen_stub_pyclass_enum(
663 module = "nautilus_trader.adapters.interactive_brokers"
664 )
665)]
666pub enum IbComboLegOpenClose {
667 Same,
668 Open,
669 Close,
670 Unknown,
671}
672
673impl IbComboLegOpenClose {
674 #[must_use]
676 pub const fn as_i32(self) -> i32 {
677 match self {
678 Self::Same => 0,
679 Self::Open => 1,
680 Self::Close => 2,
681 Self::Unknown => 3,
682 }
683 }
684
685 #[must_use]
687 pub const fn ibapi_combo_leg_open_close(self) -> ibapi::contracts::ComboLegOpenClose {
688 match self {
689 Self::Same => ibapi::contracts::ComboLegOpenClose::Same,
690 Self::Open => ibapi::contracts::ComboLegOpenClose::Open,
691 Self::Close => ibapi::contracts::ComboLegOpenClose::Close,
692 Self::Unknown => ibapi::contracts::ComboLegOpenClose::Unknown,
693 }
694 }
695}
696
697impl From<ibapi::contracts::ComboLegOpenClose> for IbComboLegOpenClose {
698 fn from(value: ibapi::contracts::ComboLegOpenClose) -> Self {
699 match value {
700 ibapi::contracts::ComboLegOpenClose::Same => Self::Same,
701 ibapi::contracts::ComboLegOpenClose::Open => Self::Open,
702 ibapi::contracts::ComboLegOpenClose::Close => Self::Close,
703 ibapi::contracts::ComboLegOpenClose::Unknown => Self::Unknown,
704 }
705 }
706}
707
708#[derive(Debug, Clone, Copy, PartialEq, Eq)]
710#[cfg_attr(
711 feature = "python",
712 pyo3::pyclass(
713 module = "nautilus_trader.adapters.interactive_brokers",
714 from_py_object,
715 rename_all = "SCREAMING_SNAKE_CASE"
716 )
717)]
718#[cfg_attr(
719 feature = "python",
720 pyo3_stub_gen::derive::gen_stub_pyclass_enum(
721 module = "nautilus_trader.adapters.interactive_brokers"
722 )
723)]
724pub enum IbConditionKind {
725 Price,
727 Time,
729 Margin,
731 Execution,
733 Volume,
735 PercentChange,
737}
738
739impl IbConditionKind {
740 #[must_use]
742 pub const fn as_str(self) -> &'static str {
743 match self {
744 Self::Price => "price",
745 Self::Time => "time",
746 Self::Margin => "margin",
747 Self::Execution => "execution",
748 Self::Volume => "volume",
749 Self::PercentChange => "percent_change",
750 }
751 }
752}
753
754impl FromStr for IbConditionKind {
755 type Err = anyhow::Error;
756
757 fn from_str(value: &str) -> Result<Self, Self::Err> {
758 match value.to_ascii_lowercase().as_str() {
759 "price" => Ok(Self::Price),
760 "time" => Ok(Self::Time),
761 "margin" => Ok(Self::Margin),
762 "execution" => Ok(Self::Execution),
763 "volume" => Ok(Self::Volume),
764 "percent_change" | "percentchange" => Ok(Self::PercentChange),
765 _ => anyhow::bail!("Unknown IB condition kind: {value}"),
766 }
767 }
768}
769
770impl Display for IbConditionKind {
771 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
772 f.write_str(self.as_str())
773 }
774}
775
776#[derive(Debug, Clone, Copy, PartialEq, Eq)]
778#[cfg_attr(
779 feature = "python",
780 pyo3::pyclass(
781 module = "nautilus_trader.adapters.interactive_brokers",
782 from_py_object,
783 rename_all = "SCREAMING_SNAKE_CASE"
784 )
785)]
786#[cfg_attr(
787 feature = "python",
788 pyo3_stub_gen::derive::gen_stub_pyclass_enum(
789 module = "nautilus_trader.adapters.interactive_brokers"
790 )
791)]
792pub enum IbConditionConjunction {
793 And,
795 Or,
797}
798
799impl IbConditionConjunction {
800 #[must_use]
802 pub const fn as_str(self) -> &'static str {
803 match self {
804 Self::And => "and",
805 Self::Or => "or",
806 }
807 }
808
809 #[must_use]
811 pub const fn is_conjunction(self) -> bool {
812 matches!(self, Self::And)
813 }
814}
815
816impl FromStr for IbConditionConjunction {
817 type Err = anyhow::Error;
818
819 fn from_str(value: &str) -> Result<Self, Self::Err> {
820 match value.to_ascii_lowercase().as_str() {
821 "and" | "a" => Ok(Self::And),
822 "or" | "o" => Ok(Self::Or),
823 _ => anyhow::bail!("Unknown IB condition conjunction: {value}"),
824 }
825 }
826}
827
828impl Display for IbConditionConjunction {
829 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
830 f.write_str(self.as_str())
831 }
832}
833
834#[derive(Debug, Clone, Copy, PartialEq, Eq)]
836#[cfg_attr(
837 feature = "python",
838 pyo3::pyclass(
839 module = "nautilus_trader.adapters.interactive_brokers",
840 from_py_object,
841 rename_all = "SCREAMING_SNAKE_CASE"
842 )
843)]
844#[cfg_attr(
845 feature = "python",
846 pyo3_stub_gen::derive::gen_stub_pyclass_enum(
847 module = "nautilus_trader.adapters.interactive_brokers"
848 )
849)]
850pub enum IbTriggerMethod {
851 Default,
853 DoubleBidAsk,
855 Last,
857 DoubleLast,
859 BidAsk,
861 LastOrBidAsk,
863 Midpoint,
865}
866
867impl IbTriggerMethod {
868 #[must_use]
870 pub const fn as_i32(self) -> i32 {
871 match self {
872 Self::Default => 0,
873 Self::DoubleBidAsk => 1,
874 Self::Last => 2,
875 Self::DoubleLast => 3,
876 Self::BidAsk => 4,
877 Self::LastOrBidAsk => 7,
878 Self::Midpoint => 8,
879 }
880 }
881
882 #[must_use]
884 pub const fn ibapi_trigger_method(self) -> ibapi::orders::conditions::TriggerMethod {
885 match self {
886 Self::Default => ibapi::orders::conditions::TriggerMethod::Default,
887 Self::DoubleBidAsk => ibapi::orders::conditions::TriggerMethod::DoubleBidAsk,
888 Self::Last => ibapi::orders::conditions::TriggerMethod::Last,
889 Self::DoubleLast => ibapi::orders::conditions::TriggerMethod::DoubleLast,
890 Self::BidAsk => ibapi::orders::conditions::TriggerMethod::BidAsk,
891 Self::LastOrBidAsk => ibapi::orders::conditions::TriggerMethod::LastOrBidAsk,
892 Self::Midpoint => ibapi::orders::conditions::TriggerMethod::Midpoint,
893 }
894 }
895}
896
897impl From<i32> for IbTriggerMethod {
898 fn from(value: i32) -> Self {
899 match value {
900 1 => Self::DoubleBidAsk,
901 2 => Self::Last,
902 3 => Self::DoubleLast,
903 4 => Self::BidAsk,
904 7 => Self::LastOrBidAsk,
905 8 => Self::Midpoint,
906 _ => Self::Default,
907 }
908 }
909}
910
911impl From<IbTriggerMethod> for i32 {
912 fn from(value: IbTriggerMethod) -> Self {
913 value.as_i32()
914 }
915}
916
917impl From<ibapi::orders::conditions::TriggerMethod> for IbTriggerMethod {
918 fn from(value: ibapi::orders::conditions::TriggerMethod) -> Self {
919 i32::from(value).into()
920 }
921}
922
923impl Display for IbTriggerMethod {
924 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
925 write!(f, "{}", self.as_i32())
926 }
927}
928
929#[derive(Debug, Clone, Copy, PartialEq, Eq)]
931#[cfg_attr(
932 feature = "python",
933 pyo3::pyclass(
934 module = "nautilus_trader.adapters.interactive_brokers",
935 from_py_object,
936 rename_all = "SCREAMING_SNAKE_CASE"
937 )
938)]
939#[cfg_attr(
940 feature = "python",
941 pyo3_stub_gen::derive::gen_stub_pyclass_enum(
942 module = "nautilus_trader.adapters.interactive_brokers"
943 )
944)]
945pub enum IbOcaType {
946 None,
948 CancelWithBlock,
950 ReduceWithBlock,
952 ReduceWithoutBlock,
954}
955
956impl IbOcaType {
957 #[must_use]
959 pub const fn as_i32(self) -> i32 {
960 match self {
961 Self::None => 0,
962 Self::CancelWithBlock => 1,
963 Self::ReduceWithBlock => 2,
964 Self::ReduceWithoutBlock => 3,
965 }
966 }
967
968 #[must_use]
970 pub const fn ibapi_oca_type(self) -> ibapi::orders::OcaType {
971 match self {
972 Self::None => ibapi::orders::OcaType::None,
973 Self::CancelWithBlock => ibapi::orders::OcaType::CancelWithBlock,
974 Self::ReduceWithBlock => ibapi::orders::OcaType::ReduceWithBlock,
975 Self::ReduceWithoutBlock => ibapi::orders::OcaType::ReduceWithoutBlock,
976 }
977 }
978}
979
980impl From<i32> for IbOcaType {
981 fn from(value: i32) -> Self {
982 match value {
983 1 => Self::CancelWithBlock,
984 2 => Self::ReduceWithBlock,
985 3 => Self::ReduceWithoutBlock,
986 _ => Self::None,
987 }
988 }
989}
990
991impl From<IbOcaType> for i32 {
992 fn from(value: IbOcaType) -> Self {
993 value.as_i32()
994 }
995}
996
997impl From<ibapi::orders::OcaType> for IbOcaType {
998 fn from(value: ibapi::orders::OcaType) -> Self {
999 i32::from(value).into()
1000 }
1001}
1002
1003impl Display for IbOcaType {
1004 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1005 write!(f, "{}", self.as_i32())
1006 }
1007}
1008
1009#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1011#[cfg_attr(
1012 feature = "python",
1013 pyo3::pyclass(
1014 module = "nautilus_trader.adapters.interactive_brokers",
1015 from_py_object,
1016 rename_all = "SCREAMING_SNAKE_CASE"
1017 )
1018)]
1019#[cfg_attr(
1020 feature = "python",
1021 pyo3_stub_gen::derive::gen_stub_pyclass_enum(
1022 module = "nautilus_trader.adapters.interactive_brokers"
1023 )
1024)]
1025pub enum IbLiquidity {
1026 None,
1027 AddedLiquidity,
1028 RemovedLiquidity,
1029 LiquidityRoutedOut,
1030}
1031
1032impl IbLiquidity {
1033 #[must_use]
1035 pub const fn as_i32(self) -> i32 {
1036 match self {
1037 Self::None => 0,
1038 Self::AddedLiquidity => 1,
1039 Self::RemovedLiquidity => 2,
1040 Self::LiquidityRoutedOut => 3,
1041 }
1042 }
1043
1044 #[must_use]
1046 pub fn ibapi_liquidity(self) -> ibapi::orders::Liquidity {
1047 ibapi::orders::Liquidity::from(self.as_i32())
1048 }
1049}
1050
1051impl From<i32> for IbLiquidity {
1052 fn from(value: i32) -> Self {
1053 match value {
1054 1 => Self::AddedLiquidity,
1055 2 => Self::RemovedLiquidity,
1056 3 => Self::LiquidityRoutedOut,
1057 _ => Self::None,
1058 }
1059 }
1060}
1061
1062impl From<ibapi::orders::Liquidity> for IbLiquidity {
1063 fn from(value: ibapi::orders::Liquidity) -> Self {
1064 match value {
1065 ibapi::orders::Liquidity::None => Self::None,
1066 ibapi::orders::Liquidity::AddedLiquidity => Self::AddedLiquidity,
1067 ibapi::orders::Liquidity::RemovedLiquidity => Self::RemovedLiquidity,
1068 ibapi::orders::Liquidity::LiquidityRoutedOut => Self::LiquidityRoutedOut,
1069 }
1070 }
1071}
1072
1073impl Display for IbLiquidity {
1074 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1075 write!(f, "{}", self.as_i32())
1076 }
1077}