nautilus_interactive_brokers/python/
mod.rs1use nautilus_common::factories::{ClientConfig, DataClientFactory, ExecutionClientFactory};
19use nautilus_core::python::{to_pyruntime_err, to_pyvalue_err};
20use nautilus_model::data::ensure_rust_extractor_registered;
21use nautilus_system::get_global_pyo3_registry;
22use pyo3::prelude::*;
23
24#[cfg(feature = "gateway")]
25use crate::gateway::dockerized::{ContainerStatus, DockerizedIBGateway};
26use crate::{
27 common::{consts::IB, enums::*},
28 config::{
29 DockerizedIBGatewayConfig, InteractiveBrokersDataClientConfig,
30 InteractiveBrokersExecutionClientConfig, InteractiveBrokersInstrumentProviderConfig,
31 MarketDataType, SymbologyMethod, TradingMode,
32 },
33 data_types::{InteractiveBrokersSubscriptionIdle, register_ib_custom_data},
34 factories::{InteractiveBrokersDataClientFactory, InteractiveBrokersExecutionClientFactory},
35 historical::HistoricalInteractiveBrokersClient,
36 providers::instruments::InteractiveBrokersInstrumentProvider,
37};
38
39pub mod config;
40pub mod conversion;
41pub mod enums;
42pub mod factories;
43pub mod historical;
44pub mod providers;
45
46#[cfg(feature = "gateway")]
47pub mod gateway;
48
49#[expect(clippy::needless_pass_by_value)]
50fn extract_interactive_brokers_data_factory(
51 py: Python<'_>,
52 factory: Py<PyAny>,
53) -> PyResult<Box<dyn DataClientFactory>> {
54 factory
55 .extract::<InteractiveBrokersDataClientFactory>(py)
56 .map(|factory| Box::new(factory) as Box<dyn DataClientFactory>)
57 .map_err(|e| {
58 to_pyvalue_err(format!(
59 "Failed to extract InteractiveBrokersDataClientFactory: {e}"
60 ))
61 })
62}
63
64#[expect(clippy::needless_pass_by_value)]
65fn extract_interactive_brokers_exec_factory(
66 py: Python<'_>,
67 factory: Py<PyAny>,
68) -> PyResult<Box<dyn ExecutionClientFactory>> {
69 factory
70 .extract::<InteractiveBrokersExecutionClientFactory>(py)
71 .map(|factory| Box::new(factory) as Box<dyn ExecutionClientFactory>)
72 .map_err(|e| {
73 to_pyvalue_err(format!(
74 "Failed to extract InteractiveBrokersExecutionClientFactory: {e}"
75 ))
76 })
77}
78
79#[expect(clippy::needless_pass_by_value)]
80fn extract_interactive_brokers_data_config(
81 py: Python<'_>,
82 config: Py<PyAny>,
83) -> PyResult<Box<dyn ClientConfig>> {
84 config
85 .extract::<InteractiveBrokersDataClientConfig>(py)
86 .map(|config| Box::new(config) as Box<dyn ClientConfig>)
87 .map_err(|e| {
88 to_pyvalue_err(format!(
89 "Failed to extract InteractiveBrokersDataClientConfig: {e}"
90 ))
91 })
92}
93
94#[expect(clippy::needless_pass_by_value)]
95fn extract_interactive_brokers_exec_config(
96 py: Python<'_>,
97 config: Py<PyAny>,
98) -> PyResult<Box<dyn ClientConfig>> {
99 config
100 .extract::<InteractiveBrokersExecutionClientConfig>(py)
101 .map(|config| Box::new(config) as Box<dyn ClientConfig>)
102 .map_err(|e| {
103 to_pyvalue_err(format!(
104 "Failed to extract InteractiveBrokersExecutionClientConfig: {e}"
105 ))
106 })
107}
108
109#[pymodule]
115pub fn interactive_brokers(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
116 m.add_class::<MarketDataType>()?;
117 m.add_class::<IbAction>()?;
118 m.add_class::<IbArticleType>()?;
119 m.add_class::<IbAuctionStrategy>()?;
120 m.add_class::<IbAuctionType>()?;
121 m.add_class::<IbBondIdentifierKind>()?;
122 m.add_class::<IbBuilderTimeInForce>()?;
123 m.add_class::<IbComboLegOpenClose>()?;
124 m.add_class::<IbConditionConjunction>()?;
125 m.add_class::<IbConditionKind>()?;
126 m.add_class::<IbExerciseAction>()?;
127 m.add_class::<IbFundAssetType>()?;
128 m.add_class::<IbFundDistributionPolicyIndicator>()?;
129 m.add_class::<IbHistoricalBarSize>()?;
130 m.add_class::<IbHistoricalTickType>()?;
131 m.add_class::<IbHistoricalWhatToShow>()?;
132 m.add_class::<IbLegAction>()?;
133 m.add_class::<IbLiquidity>()?;
134 m.add_class::<IbOcaType>()?;
135 m.add_class::<IbOrderOpenClose>()?;
136 m.add_class::<IbOrderOrigin>()?;
137 m.add_class::<IbOptionRight>()?;
138 m.add_class::<IbOrderStatus>()?;
139 m.add_class::<IbOrderType>()?;
140 m.add_class::<IbRealtimeBarSize>()?;
141 m.add_class::<IbRealtimeWhatToShow>()?;
142 m.add_class::<IbReferencePriceType>()?;
143 m.add_class::<IbRiskAversion>()?;
144 m.add_class::<IbRule80A>()?;
145 m.add_class::<IbSecurityType>()?;
146 m.add_class::<IbShortSaleSlot>()?;
147 m.add_class::<IbTickType>()?;
148 m.add_class::<IbTimeInForce>()?;
149 m.add_class::<IbTradingHours>()?;
150 m.add_class::<IbTriggerMethod>()?;
151 m.add_class::<IbTwapStrategyType>()?;
152 m.add_class::<IbVolatilityType>()?;
153 m.add_class::<SymbologyMethod>()?;
154 m.add_class::<InteractiveBrokersSubscriptionIdle>()?;
155 register_ib_custom_data();
156 let _ = ensure_rust_extractor_registered::<InteractiveBrokersSubscriptionIdle>();
157 m.add_class::<InteractiveBrokersDataClientConfig>()?;
158 m.add_class::<InteractiveBrokersExecutionClientConfig>()?;
159 m.add_class::<InteractiveBrokersInstrumentProviderConfig>()?;
160 m.add_class::<DockerizedIBGatewayConfig>()?;
161 m.add_class::<TradingMode>()?;
162 m.add_class::<InteractiveBrokersDataClientFactory>()?;
163 m.add_class::<InteractiveBrokersExecutionClientFactory>()?;
164 m.add_class::<HistoricalInteractiveBrokersClient>()?;
165 m.add_class::<InteractiveBrokersInstrumentProvider>()?;
166
167 #[cfg(feature = "gateway")]
168 {
169 m.add_class::<ContainerStatus>()?;
170 m.add_class::<DockerizedIBGateway>()?;
171 }
172
173 let registry = get_global_pyo3_registry();
174
175 if let Err(e) = registry
176 .register_factory_extractor(IB.to_string(), extract_interactive_brokers_data_factory)
177 {
178 return Err(to_pyruntime_err(format!(
179 "Failed to register Interactive Brokers data factory extractor: {e}"
180 )));
181 }
182
183 if let Err(e) = registry
184 .register_exec_factory_extractor(IB.to_string(), extract_interactive_brokers_exec_factory)
185 {
186 return Err(to_pyruntime_err(format!(
187 "Failed to register Interactive Brokers exec factory extractor: {e}"
188 )));
189 }
190
191 if let Err(e) = registry.register_config_extractor(
192 "InteractiveBrokersDataClientConfig".to_string(),
193 extract_interactive_brokers_data_config,
194 ) {
195 return Err(to_pyruntime_err(format!(
196 "Failed to register Interactive Brokers data config extractor: {e}"
197 )));
198 }
199
200 if let Err(e) = registry.register_config_extractor(
201 "InteractiveBrokersExecutionClientConfig".to_string(),
202 extract_interactive_brokers_exec_config,
203 ) {
204 return Err(to_pyruntime_err(format!(
205 "Failed to register Interactive Brokers exec config extractor: {e}"
206 )));
207 }
208
209 Ok(())
210}