Skip to main content

nautilus_tardis/python/
config.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
16use nautilus_common::python::config_error_to_pyvalue_err;
17use nautilus_core::{python::to_pyvalue_err, string::secret::SecretString};
18use nautilus_model::{data::BarSpecification, identifiers::InstrumentId};
19use pyo3::prelude::*;
20use ustr::Ustr;
21
22use crate::{
23    common::{enums::TardisExchange, parse::bar_spec_to_tardis_trade_bar_string},
24    config::TardisDataClientConfig,
25    machine::types::{
26        ReplayNormalizedRequestOptions, StreamNormalizedRequestOptions, TardisInstrumentMiniInfo,
27    },
28};
29
30#[pymethods]
31#[pyo3_stub_gen::derive::gen_stub_pymethods]
32impl TardisInstrumentMiniInfo {
33    /// Instrument definition information necessary for stream parsing.
34    #[new]
35    fn py_new(
36        instrument_id: InstrumentId,
37        raw_symbol: &str,
38        exchange: &str,
39        price_precision: u8,
40        size_precision: u8,
41    ) -> PyResult<Self> {
42        let exchange: TardisExchange = exchange.parse().map_err(to_pyvalue_err)?;
43        Ok(Self::new(
44            instrument_id,
45            Some(Ustr::from(raw_symbol)),
46            exchange,
47            price_precision,
48            size_precision,
49        ))
50    }
51
52    #[getter]
53    #[pyo3(name = "instrument_id")]
54    const fn py_instrument_id(&self) -> InstrumentId {
55        self.instrument_id
56    }
57
58    #[getter]
59    #[pyo3(name = "raw_symbol")]
60    fn py_raw_symbol(&self) -> String {
61        self.raw_symbol.to_string()
62    }
63
64    #[getter]
65    #[pyo3(name = "exchange")]
66    fn py_exchange(&self) -> String {
67        self.exchange.to_string()
68    }
69
70    #[getter]
71    #[pyo3(name = "price_precision")]
72    const fn py_price_precision(&self) -> u8 {
73        self.price_precision
74    }
75
76    #[getter]
77    #[pyo3(name = "size_precision")]
78    const fn py_size_precision(&self) -> u8 {
79        self.size_precision
80    }
81}
82
83/// Converts a Nautilus `BarSpecification` to the Tardis trade bar string convention.
84///
85/// # Errors
86///
87/// Returns an error if the bar aggregation kind is unsupported.
88#[pyfunction(name = "bar_spec_to_tardis_trade_bar_string")]
89#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.adapters.tardis")]
90pub fn py_bar_spec_to_tardis_trade_bar_string(bar_spec: &BarSpecification) -> PyResult<String> {
91    bar_spec_to_tardis_trade_bar_string(bar_spec).map_err(to_pyvalue_err)
92}
93
94#[pymethods]
95#[pyo3_stub_gen::derive::gen_stub_pymethods]
96impl TardisDataClientConfig {
97    /// Configuration for the Tardis data client.
98    #[new]
99    #[pyo3(signature = (
100        api_key = None,
101        tardis_ws_url = None,
102        proxy_url = None,
103        normalize_symbols = None,
104        options = None,
105        stream_options = None,
106        extract_bbo_as_quotes = None,
107        tardis_http_url = None,
108    ))]
109    #[expect(clippy::too_many_arguments)]
110    fn py_new(
111        api_key: Option<String>,
112        tardis_ws_url: Option<String>,
113        proxy_url: Option<String>,
114        normalize_symbols: Option<bool>,
115        options: Option<Vec<ReplayNormalizedRequestOptions>>,
116        stream_options: Option<Vec<StreamNormalizedRequestOptions>>,
117        extract_bbo_as_quotes: Option<bool>,
118        tardis_http_url: Option<String>,
119    ) -> PyResult<Self> {
120        let defaults = Self::default();
121
122        let config = Self {
123            api_key: api_key.map(SecretString::from),
124            tardis_ws_url: tardis_ws_url.map(SecretString::from),
125            tardis_http_url: tardis_http_url.map(SecretString::from),
126            proxy_url: proxy_url.map(SecretString::from),
127            normalize_symbols: normalize_symbols.unwrap_or(defaults.normalize_symbols),
128            book_snapshot_output: defaults.book_snapshot_output,
129            extract_bbo_as_quotes: extract_bbo_as_quotes.unwrap_or(defaults.extract_bbo_as_quotes),
130            options: options.unwrap_or_default(),
131            stream_options: stream_options.unwrap_or_default(),
132        };
133
134        config.validate().map_err(config_error_to_pyvalue_err)?;
135        Ok(config)
136    }
137
138    #[getter]
139    const fn has_proxy_url(&self) -> bool {
140        self.proxy_url.is_some()
141    }
142
143    fn __repr__(&self) -> String {
144        stringify!(TardisDataClientConfig).to_string()
145    }
146}