nautilus_tardis/python/
mod.rs1pub mod config;
19pub mod csv;
20pub mod enums;
21pub mod factories;
22pub mod http;
23pub mod machine;
24
25use nautilus_common::factories::{ClientConfig, DataClientFactory};
26use nautilus_core::python::{enums::parse_enum, to_pyruntime_err, to_pyvalue_err};
27use nautilus_system::get_global_pyo3_registry;
28use pyo3::prelude::*;
29use ustr::Ustr;
30
31use crate::{
32 common::{
33 enums::{TardisExchange, TardisInstrumentType},
34 parse::normalize_symbol_str,
35 },
36 config::TardisDataClientConfig,
37 factories::TardisDataClientFactory,
38};
39
40#[pyfunction(name = "tardis_normalize_symbol_str")]
46#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.tardis")]
47#[pyo3(signature = (symbol, exchange, instrument_type, is_inverse=None))]
48pub fn py_tardis_normalize_symbol_str(
49 symbol: &str,
50 exchange: &str,
51 instrument_type: &str,
52 is_inverse: Option<bool>,
53) -> PyResult<String> {
54 let symbol = Ustr::from(symbol);
55 let exchange: TardisExchange = parse_enum(exchange, stringify!(exchange))?;
56 let instrument_type: TardisInstrumentType =
57 parse_enum(instrument_type, stringify!(instrument_type))?;
58
59 Ok(normalize_symbol_str(symbol, &exchange, &instrument_type, is_inverse).to_string())
60}
61
62#[expect(clippy::needless_pass_by_value)]
63fn extract_tardis_data_factory(
64 py: Python<'_>,
65 factory: Py<PyAny>,
66) -> PyResult<Box<dyn DataClientFactory>> {
67 match factory.extract::<TardisDataClientFactory>(py) {
68 Ok(f) => Ok(Box::new(f)),
69 Err(e) => Err(to_pyvalue_err(format!(
70 "Failed to extract TardisDataClientFactory: {e}"
71 ))),
72 }
73}
74
75#[expect(clippy::needless_pass_by_value)]
76fn extract_tardis_data_config(
77 py: Python<'_>,
78 config: Py<PyAny>,
79) -> PyResult<Box<dyn ClientConfig>> {
80 match config.extract::<TardisDataClientConfig>(py) {
81 Ok(c) => Ok(Box::new(c)),
82 Err(e) => Err(to_pyvalue_err(format!(
83 "Failed to extract TardisDataClientConfig: {e}"
84 ))),
85 }
86}
87
88#[pymodule]
94pub fn tardis(_: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
95 m.add_class::<super::machine::types::TardisInstrumentMiniInfo>()?;
96 m.add_class::<super::machine::types::ReplayNormalizedRequestOptions>()?;
97 m.add_class::<super::machine::types::StreamNormalizedRequestOptions>()?;
98 m.add_class::<super::machine::TardisMachineClient>()?;
99 m.add_class::<super::http::client::TardisHttpClient>()?;
100 m.add_class::<TardisDataClientConfig>()?;
101 m.add_class::<TardisDataClientFactory>()?;
102 m.add_function(wrap_pyfunction!(py_tardis_normalize_symbol_str, m)?)?;
103 m.add_function(wrap_pyfunction!(
104 enums::py_tardis_exchange_from_venue_str,
105 m
106 )?)?;
107 m.add_function(wrap_pyfunction!(enums::py_tardis_exchange_to_venue_str, m)?)?;
108 m.add_function(wrap_pyfunction!(
109 enums::py_tardis_exchange_is_option_exchange,
110 m
111 )?)?;
112 m.add_function(wrap_pyfunction!(enums::py_tardis_exchanges, m)?)?;
113 m.add_function(wrap_pyfunction!(
114 config::py_bar_spec_to_tardis_trade_bar_string,
115 m
116 )?)?;
117 m.add_function(wrap_pyfunction!(machine::py_run_tardis_machine_replay, m)?)?;
118 m.add_function(wrap_pyfunction!(csv::py_load_tardis_deltas, m)?)?;
119 m.add_function(wrap_pyfunction!(
120 csv::py_load_tardis_depth10_from_snapshot5,
121 m
122 )?)?;
123 m.add_function(wrap_pyfunction!(
124 csv::py_load_tardis_depth10_from_snapshot25,
125 m
126 )?)?;
127 m.add_function(wrap_pyfunction!(csv::py_load_tardis_quotes, m)?)?;
128 m.add_function(wrap_pyfunction!(csv::py_load_tardis_trades, m)?)?;
129 m.add_function(wrap_pyfunction!(csv::py_stream_tardis_deltas, m)?)?;
130 m.add_function(wrap_pyfunction!(csv::py_stream_tardis_batched_deltas, m)?)?;
131 m.add_function(wrap_pyfunction!(csv::py_stream_tardis_quotes, m)?)?;
132 m.add_function(wrap_pyfunction!(csv::py_stream_tardis_trades, m)?)?;
133 m.add_function(wrap_pyfunction!(
134 csv::py_stream_tardis_depth10_from_snapshot5,
135 m
136 )?)?;
137 m.add_function(wrap_pyfunction!(
138 csv::py_stream_tardis_depth10_from_snapshot25,
139 m
140 )?)?;
141 m.add_function(wrap_pyfunction!(csv::py_load_tardis_funding_rates, m)?)?;
142 m.add_function(wrap_pyfunction!(csv::py_stream_tardis_funding_rates, m)?)?;
143
144 let registry = get_global_pyo3_registry();
145
146 if let Err(e) =
147 registry.register_factory_extractor("TARDIS".to_string(), extract_tardis_data_factory)
148 {
149 return Err(to_pyruntime_err(format!(
150 "Failed to register Tardis data factory extractor: {e}"
151 )));
152 }
153
154 if let Err(e) = registry.register_config_extractor(
155 "TardisDataClientConfig".to_string(),
156 extract_tardis_data_config,
157 ) {
158 return Err(to_pyruntime_err(format!(
159 "Failed to register Tardis data config extractor: {e}"
160 )));
161 }
162
163 Ok(())
164}