nautilus_tardis/python/
http.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 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
16use std::str::FromStr;
17
18use nautilus_core::python::{to_pyruntime_err, to_pyvalue_err};
19use nautilus_model::python::instruments::instrument_any_to_pyobject;
20use pyo3::prelude::*;
21
22use crate::{
23    enums::Exchange,
24    http::{query::InstrumentFilterBuilder, TardisHttpClient},
25};
26
27#[pymethods]
28impl TardisHttpClient {
29    #[new]
30    #[pyo3(signature = (api_key=None, base_url=None, timeout_secs=None, normalize_symbols=true))]
31    fn py_new(
32        api_key: Option<&str>,
33        base_url: Option<&str>,
34        timeout_secs: Option<u64>,
35        normalize_symbols: bool,
36    ) -> PyResult<Self> {
37        Self::new(api_key, base_url, timeout_secs, normalize_symbols).map_err(to_pyruntime_err)
38    }
39
40    #[pyo3(name = "instrument")]
41    #[pyo3(signature = (exchange, symbol, start=None, end=None, ts_init=None))]
42    fn py_instrument<'py>(
43        &self,
44        exchange: &str,
45        symbol: &str,
46        start: Option<u64>,
47        end: Option<u64>,
48        ts_init: Option<u64>,
49        py: Python<'py>,
50    ) -> PyResult<Bound<'py, PyAny>> {
51        let exchange = Exchange::from_str(exchange).map_err(to_pyvalue_err)?;
52        let symbol = symbol.to_owned();
53        let self_clone = self.clone();
54
55        pyo3_async_runtimes::tokio::future_into_py(py, async move {
56            let instruments = self_clone
57                .instrument(exchange, &symbol, start, end, ts_init)
58                .await
59                .map_err(to_pyruntime_err)?;
60
61            Python::with_gil(|py| {
62                let mut py_instruments = Vec::new();
63                for inst in instruments {
64                    py_instruments.push(instrument_any_to_pyobject(py, inst)?);
65                }
66                Ok(py_instruments.into_py(py))
67            })
68        })
69    }
70
71    #[pyo3(name = "instruments")]
72    #[pyo3(signature = (exchange, start=None, end=None, base_currency=None, quote_currency=None, instrument_type=None, contract_type=None, active=None, ts_init=None))]
73    #[allow(clippy::too_many_arguments)]
74    fn py_instruments<'py>(
75        &self,
76        exchange: &str,
77        start: Option<u64>,
78        end: Option<u64>,
79        base_currency: Option<Vec<String>>,
80        quote_currency: Option<Vec<String>>,
81        instrument_type: Option<Vec<String>>,
82        contract_type: Option<Vec<String>>,
83        active: Option<bool>,
84        ts_init: Option<u64>,
85        py: Python<'py>,
86    ) -> PyResult<Bound<'py, PyAny>> {
87        let exchange = Exchange::from_str(exchange).map_err(to_pyvalue_err)?;
88        let filter = InstrumentFilterBuilder::default()
89            .base_currency(base_currency)
90            .quote_currency(quote_currency)
91            .instrument_type(instrument_type)
92            .contract_type(contract_type)
93            .active(active)
94            .build()
95            .unwrap(); // SAFETY: Safe since all fields are Option
96
97        let self_clone = self.clone();
98
99        pyo3_async_runtimes::tokio::future_into_py(py, async move {
100            let instruments = self_clone
101                .instruments(exchange, start, end, ts_init, Some(&filter))
102                .await
103                .map_err(to_pyruntime_err)?;
104
105            Python::with_gil(|py| {
106                let mut py_instruments = Vec::new();
107                for inst in instruments {
108                    py_instruments.push(instrument_any_to_pyobject(py, inst)?);
109                }
110                Ok(py_instruments.into_py(py))
111            })
112        })
113    }
114}