Skip to main content

nautilus_interactive_brokers/python/
mod.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Python bindings from `pyo3`.
17
18use nautilus_common::factories::{ClientConfig, DataClientFactory, ExecutionClientFactory};
19use nautilus_core::python::{to_pyruntime_err, to_pyvalue_err};
20use nautilus_system::get_global_pyo3_registry;
21use pyo3::prelude::*;
22
23use crate::{
24    common::consts::IB,
25    config::{InteractiveBrokersDataClientConfig, InteractiveBrokersExecutionClientConfig},
26    factories::{InteractiveBrokersDataClientFactory, InteractiveBrokersExecutionClientFactory},
27};
28
29pub mod config;
30pub mod conversion;
31pub mod enums;
32pub mod factories;
33pub mod historical;
34pub mod providers;
35
36#[cfg(feature = "gateway")]
37pub mod gateway;
38
39#[expect(clippy::needless_pass_by_value)]
40fn extract_interactive_brokers_data_factory(
41    py: Python<'_>,
42    factory: Py<PyAny>,
43) -> PyResult<Box<dyn DataClientFactory>> {
44    match factory.extract::<InteractiveBrokersDataClientFactory>(py) {
45        Ok(f) => Ok(Box::new(f)),
46        Err(e) => Err(to_pyvalue_err(format!(
47            "Failed to extract InteractiveBrokersDataClientFactory: {e}"
48        ))),
49    }
50}
51
52#[expect(clippy::needless_pass_by_value)]
53fn extract_interactive_brokers_exec_factory(
54    py: Python<'_>,
55    factory: Py<PyAny>,
56) -> PyResult<Box<dyn ExecutionClientFactory>> {
57    match factory.extract::<InteractiveBrokersExecutionClientFactory>(py) {
58        Ok(f) => Ok(Box::new(f)),
59        Err(e) => Err(to_pyvalue_err(format!(
60            "Failed to extract InteractiveBrokersExecutionClientFactory: {e}"
61        ))),
62    }
63}
64
65#[expect(clippy::needless_pass_by_value)]
66fn extract_interactive_brokers_data_config(
67    py: Python<'_>,
68    config: Py<PyAny>,
69) -> PyResult<Box<dyn ClientConfig>> {
70    match config.extract::<InteractiveBrokersDataClientConfig>(py) {
71        Ok(c) => Ok(Box::new(c)),
72        Err(e) => Err(to_pyvalue_err(format!(
73            "Failed to extract InteractiveBrokersDataClientConfig: {e}"
74        ))),
75    }
76}
77
78#[expect(clippy::needless_pass_by_value)]
79fn extract_interactive_brokers_exec_config(
80    py: Python<'_>,
81    config: Py<PyAny>,
82) -> PyResult<Box<dyn ClientConfig>> {
83    match config.extract::<InteractiveBrokersExecutionClientConfig>(py) {
84        Ok(c) => Ok(Box::new(c)),
85        Err(e) => Err(to_pyvalue_err(format!(
86            "Failed to extract InteractiveBrokersExecutionClientConfig: {e}"
87        ))),
88    }
89}
90
91/// Exposed through `nautilus_trader.adapters.interactive_brokers`.
92///
93/// # Errors
94///
95/// Returns an error if any bindings fail to register with the Python module.
96#[pymodule]
97pub fn interactive_brokers(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
98    m.add_class::<crate::config::MarketDataType>()?;
99    m.add_class::<crate::common::enums::IbAction>()?;
100    m.add_class::<crate::common::enums::IbArticleType>()?;
101    m.add_class::<crate::common::enums::IbAuctionStrategy>()?;
102    m.add_class::<crate::common::enums::IbAuctionType>()?;
103    m.add_class::<crate::common::enums::IbBondIdentifierKind>()?;
104    m.add_class::<crate::common::enums::IbBuilderTimeInForce>()?;
105    m.add_class::<crate::common::enums::IbComboLegOpenClose>()?;
106    m.add_class::<crate::common::enums::IbConditionConjunction>()?;
107    m.add_class::<crate::common::enums::IbConditionKind>()?;
108    m.add_class::<crate::common::enums::IbExerciseAction>()?;
109    m.add_class::<crate::common::enums::IbFundAssetType>()?;
110    m.add_class::<crate::common::enums::IbFundDistributionPolicyIndicator>()?;
111    m.add_class::<crate::common::enums::IbHistoricalBarSize>()?;
112    m.add_class::<crate::common::enums::IbHistoricalTickType>()?;
113    m.add_class::<crate::common::enums::IbHistoricalWhatToShow>()?;
114    m.add_class::<crate::common::enums::IbLegAction>()?;
115    m.add_class::<crate::common::enums::IbLiquidity>()?;
116    m.add_class::<crate::common::enums::IbOcaType>()?;
117    m.add_class::<crate::common::enums::IbOrderOpenClose>()?;
118    m.add_class::<crate::common::enums::IbOrderOrigin>()?;
119    m.add_class::<crate::common::enums::IbOptionRight>()?;
120    m.add_class::<crate::common::enums::IbOrderStatus>()?;
121    m.add_class::<crate::common::enums::IbOrderType>()?;
122    m.add_class::<crate::common::enums::IbRealtimeBarSize>()?;
123    m.add_class::<crate::common::enums::IbRealtimeWhatToShow>()?;
124    m.add_class::<crate::common::enums::IbReferencePriceType>()?;
125    m.add_class::<crate::common::enums::IbRiskAversion>()?;
126    m.add_class::<crate::common::enums::IbRule80A>()?;
127    m.add_class::<crate::common::enums::IbSecurityType>()?;
128    m.add_class::<crate::common::enums::IbShortSaleSlot>()?;
129    m.add_class::<crate::common::enums::IbTickType>()?;
130    m.add_class::<crate::common::enums::IbTimeInForce>()?;
131    m.add_class::<crate::common::enums::IbTradingHours>()?;
132    m.add_class::<crate::common::enums::IbTriggerMethod>()?;
133    m.add_class::<crate::common::enums::IbTwapStrategyType>()?;
134    m.add_class::<crate::common::enums::IbVolatilityType>()?;
135    m.add_class::<crate::config::SymbologyMethod>()?;
136    m.add_class::<crate::config::InteractiveBrokersDataClientConfig>()?;
137    m.add_class::<crate::config::InteractiveBrokersExecutionClientConfig>()?;
138    m.add_class::<crate::config::InteractiveBrokersInstrumentProviderConfig>()?;
139    m.add_class::<crate::config::DockerizedIBGatewayConfig>()?;
140    m.add_class::<crate::config::TradingMode>()?;
141    m.add_class::<crate::error::ErrorCategory>()?;
142    m.add_class::<crate::error::InteractiveBrokersErrorKind>()?;
143    m.add_class::<crate::factories::InteractiveBrokersDataClientFactory>()?;
144    m.add_class::<crate::factories::InteractiveBrokersExecutionClientFactory>()?;
145    m.add_class::<crate::historical::HistoricalInteractiveBrokersClient>()?;
146    m.add_class::<crate::providers::instruments::InteractiveBrokersInstrumentProvider>()?;
147
148    #[cfg(feature = "gateway")]
149    {
150        m.add_class::<crate::gateway::dockerized::ContainerStatus>()?;
151        m.add_class::<crate::gateway::dockerized::DockerizedIBGateway>()?;
152    }
153
154    let registry = get_global_pyo3_registry();
155
156    if let Err(e) = registry
157        .register_factory_extractor(IB.to_string(), extract_interactive_brokers_data_factory)
158    {
159        return Err(to_pyruntime_err(format!(
160            "Failed to register Interactive Brokers data factory extractor: {e}"
161        )));
162    }
163
164    if let Err(e) = registry
165        .register_exec_factory_extractor(IB.to_string(), extract_interactive_brokers_exec_factory)
166    {
167        return Err(to_pyruntime_err(format!(
168            "Failed to register Interactive Brokers exec factory extractor: {e}"
169        )));
170    }
171
172    if let Err(e) = registry.register_config_extractor(
173        "InteractiveBrokersDataClientConfig".to_string(),
174        extract_interactive_brokers_data_config,
175    ) {
176        return Err(to_pyruntime_err(format!(
177            "Failed to register Interactive Brokers data config extractor: {e}"
178        )));
179    }
180
181    if let Err(e) = registry.register_config_extractor(
182        "InteractiveBrokersExecutionClientConfig".to_string(),
183        extract_interactive_brokers_exec_config,
184    ) {
185        return Err(to_pyruntime_err(format!(
186            "Failed to register Interactive Brokers exec config extractor: {e}"
187        )));
188    }
189
190    Ok(())
191}