Skip to main content

nautilus_deribit/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
18#![expect(
19    clippy::missing_errors_doc,
20    reason = "errors documented on underlying Rust methods"
21)]
22
23pub mod config;
24pub mod enums;
25pub mod factories;
26pub mod http;
27pub mod urls;
28pub mod websocket;
29
30use nautilus_common::factories::{ClientConfig, DataClientFactory, ExecutionClientFactory};
31use nautilus_core::python::{to_pyruntime_err, to_pyvalue_err};
32use nautilus_model::data::ensure_rust_extractor_registered;
33use nautilus_system::get_global_pyo3_registry;
34use pyo3::prelude::*;
35
36use crate::{
37    common::consts::DERIBIT,
38    config::{DeribitDataClientConfig, DeribitExecClientConfig},
39    data_types::{DeribitVolatilityIndex, register_deribit_custom_data},
40    factories::{DeribitDataClientFactory, DeribitExecutionClientFactory},
41};
42
43#[expect(clippy::needless_pass_by_value)]
44fn extract_deribit_data_factory(
45    py: Python<'_>,
46    factory: Py<PyAny>,
47) -> PyResult<Box<dyn DataClientFactory>> {
48    match factory.extract::<DeribitDataClientFactory>(py) {
49        Ok(f) => Ok(Box::new(f)),
50        Err(e) => Err(to_pyvalue_err(format!(
51            "Failed to extract DeribitDataClientFactory: {e}"
52        ))),
53    }
54}
55
56#[expect(clippy::needless_pass_by_value)]
57fn extract_deribit_exec_factory(
58    py: Python<'_>,
59    factory: Py<PyAny>,
60) -> PyResult<Box<dyn ExecutionClientFactory>> {
61    match factory.extract::<DeribitExecutionClientFactory>(py) {
62        Ok(f) => Ok(Box::new(f)),
63        Err(e) => Err(to_pyvalue_err(format!(
64            "Failed to extract DeribitExecutionClientFactory: {e}"
65        ))),
66    }
67}
68
69#[expect(clippy::needless_pass_by_value)]
70fn extract_deribit_data_config(
71    py: Python<'_>,
72    config: Py<PyAny>,
73) -> PyResult<Box<dyn ClientConfig>> {
74    match config.extract::<DeribitDataClientConfig>(py) {
75        Ok(c) => Ok(Box::new(c)),
76        Err(e) => Err(to_pyvalue_err(format!(
77            "Failed to extract DeribitDataClientConfig: {e}"
78        ))),
79    }
80}
81
82#[expect(clippy::needless_pass_by_value)]
83fn extract_deribit_exec_config(
84    py: Python<'_>,
85    config: Py<PyAny>,
86) -> PyResult<Box<dyn ClientConfig>> {
87    match config.extract::<DeribitExecClientConfig>(py) {
88        Ok(c) => Ok(Box::new(c)),
89        Err(e) => Err(to_pyvalue_err(format!(
90            "Failed to extract DeribitExecClientConfig: {e}"
91        ))),
92    }
93}
94
95/// Loaded as `nautilus_pyo3.deribit`.
96///
97/// # Errors
98///
99/// Returns an error if any bindings fail to register with the Python module.
100#[pymodule]
101pub fn deribit(_: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
102    m.add_class::<super::http::client::DeribitHttpClient>()?;
103    m.add_class::<super::websocket::client::DeribitWebSocketClient>()?;
104    m.add_class::<crate::common::enums::DeribitCurrency>()?;
105    m.add_class::<crate::common::enums::DeribitProductType>()?;
106    m.add_class::<crate::common::enums::DeribitEnvironment>()?;
107    m.add_class::<crate::websocket::enums::DeribitUpdateInterval>()?;
108    m.add_class::<DeribitVolatilityIndex>()?;
109    m.add_class::<DeribitDataClientConfig>()?;
110    m.add_class::<DeribitExecClientConfig>()?;
111    m.add_class::<DeribitDataClientFactory>()?;
112    m.add_class::<DeribitExecutionClientFactory>()?;
113    m.add_function(wrap_pyfunction!(urls::py_get_deribit_http_base_url, m)?)?;
114    m.add_function(wrap_pyfunction!(urls::py_get_deribit_ws_url, m)?)?;
115
116    let registry = get_global_pyo3_registry();
117
118    if let Err(e) =
119        registry.register_factory_extractor(DERIBIT.to_string(), extract_deribit_data_factory)
120    {
121        return Err(to_pyruntime_err(format!(
122            "Failed to register Deribit data factory extractor: {e}"
123        )));
124    }
125
126    if let Err(e) =
127        registry.register_exec_factory_extractor(DERIBIT.to_string(), extract_deribit_exec_factory)
128    {
129        return Err(to_pyruntime_err(format!(
130            "Failed to register Deribit exec factory extractor: {e}"
131        )));
132    }
133
134    if let Err(e) = registry.register_config_extractor(
135        "DeribitDataClientConfig".to_string(),
136        extract_deribit_data_config,
137    ) {
138        return Err(to_pyruntime_err(format!(
139            "Failed to register Deribit data config extractor: {e}"
140        )));
141    }
142
143    if let Err(e) = registry.register_config_extractor(
144        "DeribitExecClientConfig".to_string(),
145        extract_deribit_exec_config,
146    ) {
147        return Err(to_pyruntime_err(format!(
148            "Failed to register Deribit exec config extractor: {e}"
149        )));
150    }
151
152    register_deribit_custom_data();
153    let _result = ensure_rust_extractor_registered::<DeribitVolatilityIndex>();
154
155    Ok(())
156}