Skip to main content

nautilus_dydx/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#![allow(clippy::missing_errors_doc)]
19
20pub mod config;
21pub mod encoder;
22pub mod factories;
23pub mod grpc;
24pub mod http;
25pub mod submitter;
26pub mod types;
27pub mod urls;
28pub mod wallet;
29pub mod websocket;
30
31use nautilus_core::python::{to_pyruntime_err, to_pyvalue_err};
32use nautilus_system::{
33    factories::{ClientConfig, DataClientFactory, ExecutionClientFactory},
34    get_global_pyo3_registry,
35};
36use pyo3::prelude::*;
37
38use crate::{
39    config::{DydxDataClientConfig, DydxExecClientConfig},
40    factories::{DydxDataClientFactory, DydxExecutionClientFactory},
41};
42
43fn extract_dydx_data_factory(
44    py: Python<'_>,
45    factory: Py<PyAny>,
46) -> PyResult<Box<dyn DataClientFactory>> {
47    match factory.extract::<DydxDataClientFactory>(py) {
48        Ok(f) => Ok(Box::new(f)),
49        Err(e) => Err(to_pyvalue_err(format!(
50            "Failed to extract DydxDataClientFactory: {e}"
51        ))),
52    }
53}
54
55fn extract_dydx_exec_factory(
56    py: Python<'_>,
57    factory: Py<PyAny>,
58) -> PyResult<Box<dyn ExecutionClientFactory>> {
59    match factory.extract::<DydxExecutionClientFactory>(py) {
60        Ok(f) => Ok(Box::new(f)),
61        Err(e) => Err(to_pyvalue_err(format!(
62            "Failed to extract DydxExecutionClientFactory: {e}"
63        ))),
64    }
65}
66
67fn extract_dydx_data_config(py: Python<'_>, config: Py<PyAny>) -> PyResult<Box<dyn ClientConfig>> {
68    match config.extract::<DydxDataClientConfig>(py) {
69        Ok(c) => Ok(Box::new(c)),
70        Err(e) => Err(to_pyvalue_err(format!(
71            "Failed to extract DydxDataClientConfig: {e}"
72        ))),
73    }
74}
75
76fn extract_dydx_exec_config(py: Python<'_>, config: Py<PyAny>) -> PyResult<Box<dyn ClientConfig>> {
77    match config.extract::<DydxExecClientConfig>(py) {
78        Ok(c) => Ok(Box::new(c)),
79        Err(e) => Err(to_pyvalue_err(format!(
80            "Failed to extract DydxExecClientConfig: {e}"
81        ))),
82    }
83}
84
85#[pymodule]
86pub fn dydx(_: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
87    m.add_class::<crate::http::client::DydxHttpClient>()?;
88    m.add_class::<crate::websocket::client::DydxWebSocketClient>()?;
89    m.add_class::<crate::common::enums::DydxNetwork>()?;
90    m.add_class::<crate::common::enums::DydxOrderSide>()?;
91    m.add_class::<crate::common::enums::DydxOrderType>()?;
92    m.add_class::<crate::types::DydxOraclePrice>()?;
93    m.add_class::<wallet::PyDydxWallet>()?;
94    m.add_class::<grpc::PyDydxGrpcClient>()?;
95    m.add_class::<submitter::PyDydxOrderSubmitter>()?;
96    m.add_class::<encoder::PyDydxClientOrderIdEncoder>()?;
97    m.add_class::<DydxDataClientConfig>()?;
98    m.add_class::<DydxExecClientConfig>()?;
99    m.add_class::<DydxDataClientFactory>()?;
100    m.add_class::<DydxExecutionClientFactory>()?;
101    m.add_function(wrap_pyfunction!(urls::py_get_dydx_grpc_urls, m)?)?;
102    m.add_function(wrap_pyfunction!(urls::py_get_dydx_grpc_url, m)?)?;
103    m.add_function(wrap_pyfunction!(urls::py_get_dydx_http_url, m)?)?;
104    m.add_function(wrap_pyfunction!(urls::py_get_dydx_ws_url, m)?)?;
105
106    let registry = get_global_pyo3_registry();
107
108    if let Err(e) =
109        registry.register_factory_extractor("DYDX".to_string(), extract_dydx_data_factory)
110    {
111        return Err(to_pyruntime_err(format!(
112            "Failed to register dYdX data factory extractor: {e}"
113        )));
114    }
115
116    if let Err(e) =
117        registry.register_exec_factory_extractor("DYDX".to_string(), extract_dydx_exec_factory)
118    {
119        return Err(to_pyruntime_err(format!(
120            "Failed to register dYdX exec factory extractor: {e}"
121        )));
122    }
123
124    if let Err(e) = registry
125        .register_config_extractor("DydxDataClientConfig".to_string(), extract_dydx_data_config)
126    {
127        return Err(to_pyruntime_err(format!(
128            "Failed to register dYdX data config extractor: {e}"
129        )));
130    }
131
132    if let Err(e) = registry
133        .register_config_extractor("DydxExecClientConfig".to_string(), extract_dydx_exec_config)
134    {
135        return Err(to_pyruntime_err(format!(
136            "Failed to register dYdX exec config extractor: {e}"
137        )));
138    }
139
140    Ok(())
141}