nautilus_architect_ax/python/
http.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 for the Ax HTTP client.
17
18use nautilus_core::python::to_pyvalue_err;
19use nautilus_model::identifiers::AccountId;
20use pyo3::{IntoPyObjectExt, prelude::*, types::PyList};
21
22use crate::http::{client::AxHttpClient, error::AxHttpError};
23
24#[pymethods]
25impl AxHttpClient {
26    #[new]
27    #[pyo3(signature = (
28        base_url=None,
29        orders_base_url=None,
30        timeout_secs=None,
31        max_retries=None,
32        retry_delay_ms=None,
33        retry_delay_max_ms=None,
34        proxy_url=None,
35    ))]
36    #[allow(clippy::too_many_arguments)]
37    fn py_new(
38        base_url: Option<String>,
39        orders_base_url: Option<String>,
40        timeout_secs: Option<u64>,
41        max_retries: Option<u32>,
42        retry_delay_ms: Option<u64>,
43        retry_delay_max_ms: Option<u64>,
44        proxy_url: Option<String>,
45    ) -> PyResult<Self> {
46        Self::new(
47            base_url,
48            orders_base_url,
49            timeout_secs,
50            max_retries,
51            retry_delay_ms,
52            retry_delay_max_ms,
53            proxy_url,
54        )
55        .map_err(to_pyvalue_err)
56    }
57
58    #[staticmethod]
59    #[pyo3(name = "with_credentials")]
60    #[pyo3(signature = (
61        api_key,
62        api_secret,
63        base_url=None,
64        orders_base_url=None,
65        timeout_secs=None,
66        max_retries=None,
67        retry_delay_ms=None,
68        retry_delay_max_ms=None,
69        proxy_url=None,
70    ))]
71    #[allow(clippy::too_many_arguments)]
72    fn py_with_credentials(
73        api_key: String,
74        api_secret: String,
75        base_url: Option<String>,
76        orders_base_url: Option<String>,
77        timeout_secs: Option<u64>,
78        max_retries: Option<u32>,
79        retry_delay_ms: Option<u64>,
80        retry_delay_max_ms: Option<u64>,
81        proxy_url: Option<String>,
82    ) -> PyResult<Self> {
83        Self::with_credentials(
84            api_key,
85            api_secret,
86            base_url,
87            orders_base_url,
88            timeout_secs,
89            max_retries,
90            retry_delay_ms,
91            retry_delay_max_ms,
92            proxy_url,
93        )
94        .map_err(to_pyvalue_err)
95    }
96
97    #[getter]
98    #[pyo3(name = "base_url")]
99    #[must_use]
100    pub fn py_base_url(&self) -> &str {
101        self.base_url()
102    }
103
104    #[pyo3(name = "cancel_all_requests")]
105    pub fn py_cancel_all_requests(&self) {
106        self.cancel_all_requests();
107    }
108
109    /// Request order status reports from Ax.
110    ///
111    /// Returns a list of `OrderStatusReport` for all open orders.
112    #[pyo3(name = "request_order_status_reports")]
113    fn py_request_order_status_reports<'py>(
114        &self,
115        py: Python<'py>,
116        account_id: AccountId,
117    ) -> PyResult<Bound<'py, PyAny>> {
118        let client = self.clone();
119
120        pyo3_async_runtimes::tokio::future_into_py(py, async move {
121            let reports = client
122                .request_order_status_reports(account_id)
123                .await
124                .map_err(to_pyvalue_err)?;
125
126            Python::attach(|py| {
127                let py_reports: PyResult<Vec<_>> = reports
128                    .into_iter()
129                    .map(|report| report.into_py_any(py))
130                    .collect();
131                let pylist = PyList::new(py, py_reports?).unwrap().into_any().unbind();
132                Ok(pylist)
133            })
134        })
135    }
136
137    /// Request fill reports from Ax.
138    ///
139    /// Returns a list of `FillReport` for recent fills.
140    #[pyo3(name = "request_fill_reports")]
141    fn py_request_fill_reports<'py>(
142        &self,
143        py: Python<'py>,
144        account_id: AccountId,
145    ) -> PyResult<Bound<'py, PyAny>> {
146        let client = self.clone();
147
148        pyo3_async_runtimes::tokio::future_into_py(py, async move {
149            let reports = client
150                .request_fill_reports(account_id)
151                .await
152                .map_err(to_pyvalue_err)?;
153
154            Python::attach(|py| {
155                let py_reports: PyResult<Vec<_>> = reports
156                    .into_iter()
157                    .map(|report| report.into_py_any(py))
158                    .collect();
159                let pylist = PyList::new(py, py_reports?).unwrap().into_any().unbind();
160                Ok(pylist)
161            })
162        })
163    }
164
165    /// Request position reports from Ax.
166    ///
167    /// Returns a list of `PositionStatusReport` for current positions.
168    #[pyo3(name = "request_position_reports")]
169    fn py_request_position_reports<'py>(
170        &self,
171        py: Python<'py>,
172        account_id: AccountId,
173    ) -> PyResult<Bound<'py, PyAny>> {
174        let client = self.clone();
175
176        pyo3_async_runtimes::tokio::future_into_py(py, async move {
177            let reports = client
178                .request_position_reports(account_id)
179                .await
180                .map_err(to_pyvalue_err)?;
181
182            Python::attach(|py| {
183                let py_reports: PyResult<Vec<_>> = reports
184                    .into_iter()
185                    .map(|report| report.into_py_any(py))
186                    .collect();
187                let pylist = PyList::new(py, py_reports?).unwrap().into_any().unbind();
188                Ok(pylist)
189            })
190        })
191    }
192}
193
194impl From<AxHttpError> for PyErr {
195    fn from(error: AxHttpError) -> Self {
196        to_pyvalue_err(error)
197    }
198}