nautilus_architect_ax/python/
websocket.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 Ax WebSocket clients.
17
18use nautilus_core::python::to_pyruntime_err;
19use pyo3::prelude::*;
20
21use crate::{common::enums::AxMarketDataLevel, websocket::data::AxMdWebSocketClient};
22
23#[pymethods]
24impl AxMdWebSocketClient {
25    #[new]
26    #[pyo3(signature = (url, auth_token, heartbeat=None))]
27    fn py_new(url: String, auth_token: String, heartbeat: Option<u64>) -> Self {
28        Self::new(url, auth_token, heartbeat)
29    }
30
31    #[getter]
32    #[pyo3(name = "url")]
33    #[must_use]
34    pub fn py_url(&self) -> &str {
35        self.url()
36    }
37
38    #[pyo3(name = "is_active")]
39    #[must_use]
40    pub fn py_is_active(&self) -> bool {
41        self.is_active()
42    }
43
44    #[pyo3(name = "is_closed")]
45    #[must_use]
46    pub fn py_is_closed(&self) -> bool {
47        self.is_closed()
48    }
49
50    #[pyo3(name = "subscription_count")]
51    #[must_use]
52    pub fn py_subscription_count(&self) -> usize {
53        self.subscription_count()
54    }
55
56    #[pyo3(name = "connect")]
57    fn py_connect<'py>(&mut self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
58        let mut client = self.clone();
59
60        pyo3_async_runtimes::tokio::future_into_py(py, async move {
61            client.connect().await.map_err(to_pyruntime_err)
62        })
63    }
64
65    #[pyo3(name = "subscribe")]
66    fn py_subscribe<'py>(
67        &self,
68        py: Python<'py>,
69        symbol: String,
70        level: AxMarketDataLevel,
71    ) -> PyResult<Bound<'py, PyAny>> {
72        let client = self.clone();
73
74        pyo3_async_runtimes::tokio::future_into_py(py, async move {
75            client
76                .subscribe(&symbol, level)
77                .await
78                .map_err(to_pyruntime_err)
79        })
80    }
81
82    #[pyo3(name = "unsubscribe")]
83    fn py_unsubscribe<'py>(&self, py: Python<'py>, symbol: String) -> PyResult<Bound<'py, PyAny>> {
84        let client = self.clone();
85
86        pyo3_async_runtimes::tokio::future_into_py(py, async move {
87            client.unsubscribe(&symbol).await.map_err(to_pyruntime_err)
88        })
89    }
90
91    #[pyo3(name = "disconnect")]
92    fn py_disconnect<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
93        let client = self.clone();
94
95        pyo3_async_runtimes::tokio::future_into_py(py, async move {
96            client.disconnect().await;
97            Ok(())
98        })
99    }
100
101    #[pyo3(name = "close")]
102    fn py_close<'py>(&mut self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
103        let mut client = self.clone();
104
105        pyo3_async_runtimes::tokio::future_into_py(py, async move {
106            client.close().await;
107            Ok(())
108        })
109    }
110}