nautilus_architect_ax/python/
mod.rs1#![expect(
19 clippy::missing_errors_doc,
20 reason = "errors documented on underlying Rust methods"
21)]
22
23pub mod config;
24pub mod factories;
25pub mod http;
26
27use std::str::FromStr;
28
29use nautilus_common::factories::{ClientConfig, DataClientFactory, ExecutionClientFactory};
30use nautilus_core::python::{to_pyruntime_err, to_pyvalue_err};
31use nautilus_system::get_global_pyo3_registry;
32use pyo3::{prelude::*, types::PyType};
33
34use crate::{
35 common::{
36 consts::{AX, AX_CLIENT_ID, AX_VENUE},
37 enums::{AxEnvironment, AxMarketDataLevel},
38 },
39 config::{AxDataClientConfig, AxExecutionClientConfig},
40 factories::{AxDataClientFactory, AxExecutionClientFactory},
41 http::client::AxHttpClient,
42};
43
44#[expect(clippy::needless_pass_by_value)]
45fn extract_ax_data_factory(
46 py: Python<'_>,
47 factory: Py<PyAny>,
48) -> PyResult<Box<dyn DataClientFactory>> {
49 match factory.extract::<AxDataClientFactory>(py) {
50 Ok(f) => Ok(Box::new(f)),
51 Err(e) => Err(to_pyvalue_err(format!(
52 "Failed to extract AxDataClientFactory: {e}"
53 ))),
54 }
55}
56
57#[expect(clippy::needless_pass_by_value)]
58fn extract_ax_exec_factory(
59 py: Python<'_>,
60 factory: Py<PyAny>,
61) -> PyResult<Box<dyn ExecutionClientFactory>> {
62 match factory.extract::<AxExecutionClientFactory>(py) {
63 Ok(f) => Ok(Box::new(f)),
64 Err(e) => Err(to_pyvalue_err(format!(
65 "Failed to extract AxExecutionClientFactory: {e}"
66 ))),
67 }
68}
69
70#[expect(clippy::needless_pass_by_value)]
71fn extract_ax_data_config(py: Python<'_>, config: Py<PyAny>) -> PyResult<Box<dyn ClientConfig>> {
72 match config.extract::<AxDataClientConfig>(py) {
73 Ok(c) => Ok(Box::new(c)),
74 Err(e) => Err(to_pyvalue_err(format!(
75 "Failed to extract AxDataClientConfig: {e}"
76 ))),
77 }
78}
79
80#[expect(clippy::needless_pass_by_value)]
81fn extract_ax_exec_config(py: Python<'_>, config: Py<PyAny>) -> PyResult<Box<dyn ClientConfig>> {
82 match config.extract::<AxExecutionClientConfig>(py) {
83 Ok(c) => Ok(Box::new(c)),
84 Err(e) => Err(to_pyvalue_err(format!(
85 "Failed to extract AxExecutionClientConfig: {e}"
86 ))),
87 }
88}
89
90#[pymethods]
91#[pyo3_stub_gen::derive::gen_stub_pymethods]
92impl AxEnvironment {
93 fn __repr__(&self) -> String {
94 format!(
95 "<{}.{}: '{}'>",
96 stringify!(AxEnvironment),
97 self.name(),
98 self.value(),
99 )
100 }
101
102 fn __str__(&self) -> String {
103 self.to_string()
104 }
105
106 #[getter]
107 #[must_use]
108 pub fn name(&self) -> String {
109 self.to_string()
110 }
111
112 #[getter]
113 #[must_use]
114 pub fn value(&self) -> u8 {
115 *self as u8
116 }
117
118 #[classmethod]
119 #[pyo3(name = "from_str")]
120 fn py_from_str(_: &Bound<'_, PyType>, data: &Bound<'_, PyAny>) -> PyResult<Self> {
121 let data_str: &str = data.extract()?;
122 let tokenized = data_str.to_uppercase();
123 Self::from_str(&tokenized).map_err(to_pyvalue_err)
124 }
125}
126
127#[pymethods]
128#[pyo3_stub_gen::derive::gen_stub_pymethods]
129impl AxMarketDataLevel {
130 fn __repr__(&self) -> String {
131 format!(
132 "<{}.{}: '{}'>",
133 stringify!(AxMarketDataLevel),
134 self.name(),
135 self.value(),
136 )
137 }
138
139 fn __str__(&self) -> String {
140 self.to_string()
141 }
142
143 #[getter]
144 #[must_use]
145 pub fn name(&self) -> String {
146 self.to_string()
147 }
148
149 #[getter]
150 #[must_use]
151 pub fn value(&self) -> u8 {
152 *self as u8
153 }
154
155 #[classmethod]
156 #[pyo3(name = "from_str")]
157 fn py_from_str(_: &Bound<'_, PyType>, data: &Bound<'_, PyAny>) -> PyResult<Self> {
158 let data_str: &str = data.extract()?;
159 let tokenized = data_str.to_uppercase();
160 Self::from_str(&tokenized).map_err(to_pyvalue_err)
161 }
162}
163
164#[pymodule]
170pub fn architect_ax(_: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
171 m.add(stringify!(AX), AX)?;
172 m.add(stringify!(AX_CLIENT_ID), *AX_CLIENT_ID)?;
173 m.add(stringify!(AX_VENUE), *AX_VENUE)?;
174 m.add_class::<AxEnvironment>()?;
175 m.add_class::<AxMarketDataLevel>()?;
176 m.add_class::<AxDataClientConfig>()?;
177 m.add_class::<AxDataClientFactory>()?;
178 m.add_class::<AxExecutionClientConfig>()?;
179 m.add_class::<AxExecutionClientFactory>()?;
180 m.add_class::<AxHttpClient>()?;
181
182 let registry = get_global_pyo3_registry();
183
184 if let Err(e) = registry.register_factory_extractor(AX.to_string(), extract_ax_data_factory) {
185 return Err(to_pyruntime_err(format!(
186 "Failed to register Ax data factory extractor: {e}"
187 )));
188 }
189
190 if let Err(e) =
191 registry.register_exec_factory_extractor(AX.to_string(), extract_ax_exec_factory)
192 {
193 return Err(to_pyruntime_err(format!(
194 "Failed to register Ax exec factory extractor: {e}"
195 )));
196 }
197
198 if let Err(e) =
199 registry.register_config_extractor("AxDataClientConfig".to_string(), extract_ax_data_config)
200 {
201 return Err(to_pyruntime_err(format!(
202 "Failed to register Ax data config extractor: {e}"
203 )));
204 }
205
206 if let Err(e) = registry.register_config_extractor(
207 "AxExecutionClientConfig".to_string(),
208 extract_ax_exec_config,
209 ) {
210 return Err(to_pyruntime_err(format!(
211 "Failed to register Ax exec config extractor: {e}"
212 )));
213 }
214
215 Ok(())
216}