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::<csv::TardisBatchedDeltasStreamIterator>()?;
97 m.add_class::<csv::TardisDeltaStreamIterator>()?;
98 m.add_class::<csv::TardisDepth10StreamIterator>()?;
99 m.add_class::<csv::TardisFundingRateStreamIterator>()?;
100 m.add_class::<csv::TardisOptionsChainStreamIterator>()?;
101 m.add_class::<csv::TardisQuoteStreamIterator>()?;
102 m.add_class::<csv::TardisTradeStreamIterator>()?;
103 m.add_class::<super::machine::types::TardisInstrumentMiniInfo>()?;
104 m.add_class::<super::machine::types::ReplayNormalizedRequestOptions>()?;
105 m.add_class::<super::machine::types::StreamNormalizedRequestOptions>()?;
106 m.add_class::<super::machine::TardisMachineClient>()?;
107 m.add_class::<super::http::client::TardisHttpClient>()?;
108 m.add_class::<TardisDataClientConfig>()?;
109 m.add_class::<TardisDataClientFactory>()?;
110 m.add_function(wrap_pyfunction!(py_tardis_normalize_symbol_str, m)?)?;
111 m.add_function(wrap_pyfunction!(
112 enums::py_tardis_exchange_from_venue_str,
113 m
114 )?)?;
115 m.add_function(wrap_pyfunction!(enums::py_tardis_exchange_to_venue_str, m)?)?;
116 m.add_function(wrap_pyfunction!(
117 enums::py_tardis_exchange_is_option_exchange,
118 m
119 )?)?;
120 m.add_function(wrap_pyfunction!(enums::py_tardis_exchanges, m)?)?;
121 m.add_function(wrap_pyfunction!(
122 config::py_bar_spec_to_tardis_trade_bar_string,
123 m
124 )?)?;
125 m.add_function(wrap_pyfunction!(machine::py_run_tardis_machine_replay, m)?)?;
126 m.add_function(wrap_pyfunction!(csv::py_load_tardis_deltas, m)?)?;
127 m.add_function(wrap_pyfunction!(
128 csv::py_load_tardis_depth10_from_snapshot5,
129 m
130 )?)?;
131 m.add_function(wrap_pyfunction!(
132 csv::py_load_tardis_depth10_from_snapshot25,
133 m
134 )?)?;
135 m.add_function(wrap_pyfunction!(csv::py_load_tardis_quotes, m)?)?;
136 m.add_function(wrap_pyfunction!(csv::py_load_tardis_trades, m)?)?;
137 m.add_function(wrap_pyfunction!(csv::py_load_tardis_options_chain, m)?)?;
138 m.add_function(wrap_pyfunction!(
139 csv::py_convert_tardis_options_chain_csv,
140 m
141 )?)?;
142 m.add_function(wrap_pyfunction!(csv::py_stream_tardis_deltas, m)?)?;
143 m.add_function(wrap_pyfunction!(csv::py_stream_tardis_batched_deltas, m)?)?;
144 m.add_function(wrap_pyfunction!(csv::py_stream_tardis_quotes, m)?)?;
145 m.add_function(wrap_pyfunction!(csv::py_stream_tardis_options_chain, m)?)?;
146 m.add_function(wrap_pyfunction!(csv::py_stream_tardis_trades, m)?)?;
147 m.add_function(wrap_pyfunction!(
148 csv::py_stream_tardis_depth10_from_snapshot5,
149 m
150 )?)?;
151 m.add_function(wrap_pyfunction!(
152 csv::py_stream_tardis_depth10_from_snapshot25,
153 m
154 )?)?;
155 m.add_function(wrap_pyfunction!(csv::py_load_tardis_funding_rates, m)?)?;
156 m.add_function(wrap_pyfunction!(csv::py_stream_tardis_funding_rates, m)?)?;
157
158 let registry = get_global_pyo3_registry();
159
160 if let Err(e) =
161 registry.register_factory_extractor(TARDIS.to_string(), extract_tardis_data_factory)
162 {
163 return Err(to_pyruntime_err(format!(
164 "Failed to register Tardis data factory extractor: {e}"
165 )));
166 }
167
168 if let Err(e) = registry.register_config_extractor(
169 "TardisDataClientConfig".to_string(),
170 extract_tardis_data_config,
171 ) {
172 return Err(to_pyruntime_err(format!(
173 "Failed to register Tardis data config extractor: {e}"
174 )));
175 }
176
177 Ok(())
178}