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