Skip to main content

nautilus_bitmex/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
18pub mod canceller;
19pub mod config;
20pub mod enums;
21pub mod factories;
22pub mod http;
23pub mod submitter;
24pub mod urls;
25pub mod websocket;
26
27use nautilus_core::python::{to_pyruntime_err, to_pyvalue_err};
28use nautilus_system::{
29    factories::{ClientConfig, DataClientFactory, ExecutionClientFactory},
30    get_global_pyo3_registry,
31};
32use pyo3::prelude::*;
33
34use crate::{
35    config::{BitmexDataClientConfig, BitmexExecClientConfig},
36    factories::{BitmexDataClientFactory, BitmexExecFactoryConfig, BitmexExecutionClientFactory},
37};
38
39fn extract_bitmex_data_factory(
40    py: Python<'_>,
41    factory: Py<PyAny>,
42) -> PyResult<Box<dyn DataClientFactory>> {
43    match factory.extract::<BitmexDataClientFactory>(py) {
44        Ok(f) => Ok(Box::new(f)),
45        Err(e) => Err(to_pyvalue_err(format!(
46            "Failed to extract BitmexDataClientFactory: {e}"
47        ))),
48    }
49}
50
51fn extract_bitmex_exec_factory(
52    py: Python<'_>,
53    factory: Py<PyAny>,
54) -> PyResult<Box<dyn ExecutionClientFactory>> {
55    match factory.extract::<BitmexExecutionClientFactory>(py) {
56        Ok(f) => Ok(Box::new(f)),
57        Err(e) => Err(to_pyvalue_err(format!(
58            "Failed to extract BitmexExecutionClientFactory: {e}"
59        ))),
60    }
61}
62
63fn extract_bitmex_data_config(
64    py: Python<'_>,
65    config: Py<PyAny>,
66) -> PyResult<Box<dyn ClientConfig>> {
67    match config.extract::<BitmexDataClientConfig>(py) {
68        Ok(c) => Ok(Box::new(c)),
69        Err(e) => Err(to_pyvalue_err(format!(
70            "Failed to extract BitmexDataClientConfig: {e}"
71        ))),
72    }
73}
74
75fn extract_bitmex_exec_config(
76    py: Python<'_>,
77    config: Py<PyAny>,
78) -> PyResult<Box<dyn ClientConfig>> {
79    match config.extract::<BitmexExecFactoryConfig>(py) {
80        Ok(c) => Ok(Box::new(c)),
81        Err(e) => Err(to_pyvalue_err(format!(
82            "Failed to extract BitmexExecFactoryConfig: {e}"
83        ))),
84    }
85}
86
87/// Loaded as `nautilus_pyo3.bitmex`.
88///
89/// # Errors
90///
91/// Returns an error if the module registration fails or if adding functions/classes fails.
92#[pymodule]
93pub fn bitmex(_: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
94    m.add("BITMEX_HTTP_URL", crate::common::consts::BITMEX_HTTP_URL)?;
95    m.add("BITMEX_WS_URL", crate::common::consts::BITMEX_WS_URL)?;
96    m.add_class::<crate::http::client::BitmexHttpClient>()?;
97    m.add_class::<crate::websocket::BitmexWebSocketClient>()?;
98    m.add_class::<crate::broadcast::canceller::CancelBroadcaster>()?;
99    m.add_class::<crate::broadcast::submitter::SubmitBroadcaster>()?;
100    m.add_class::<BitmexDataClientConfig>()?;
101    m.add_class::<BitmexExecClientConfig>()?;
102    m.add_class::<BitmexExecFactoryConfig>()?;
103    m.add_class::<BitmexDataClientFactory>()?;
104    m.add_class::<BitmexExecutionClientFactory>()?;
105    m.add_function(wrap_pyfunction!(urls::get_bitmex_http_base_url, m)?)?;
106    m.add_function(wrap_pyfunction!(urls::get_bitmex_ws_url, m)?)?;
107
108    let registry = get_global_pyo3_registry();
109
110    if let Err(e) =
111        registry.register_factory_extractor("BITMEX".to_string(), extract_bitmex_data_factory)
112    {
113        return Err(to_pyruntime_err(format!(
114            "Failed to register BitMEX data factory extractor: {e}"
115        )));
116    }
117
118    if let Err(e) =
119        registry.register_exec_factory_extractor("BITMEX".to_string(), extract_bitmex_exec_factory)
120    {
121        return Err(to_pyruntime_err(format!(
122            "Failed to register BitMEX exec factory extractor: {e}"
123        )));
124    }
125
126    if let Err(e) = registry.register_config_extractor(
127        "BitmexDataClientConfig".to_string(),
128        extract_bitmex_data_config,
129    ) {
130        return Err(to_pyruntime_err(format!(
131            "Failed to register BitMEX data config extractor: {e}"
132        )));
133    }
134
135    if let Err(e) = registry.register_config_extractor(
136        "BitmexExecFactoryConfig".to_string(),
137        extract_bitmex_exec_config,
138    ) {
139        return Err(to_pyruntime_err(format!(
140            "Failed to register BitMEX exec config extractor: {e}"
141        )));
142    }
143
144    Ok(())
145}