1#![warn(rustc::all)]
46#![deny(unsafe_code)]
47#![deny(unsafe_op_in_unsafe_fn)]
48#![deny(nonstandard_style)]
49#![deny(missing_debug_implementations)]
50#![deny(clippy::missing_errors_doc)]
51#![deny(clippy::missing_panics_doc)]
52#![deny(rustdoc::broken_intra_doc_links)]
53
54use std::{path::Path, time::Duration};
55
56use nautilus_common::live::runtime::shutdown_runtime;
57use pyo3::{prelude::*, pyfunction};
58
59const RUNTIME_SHUTDOWN_TIMEOUT_SECS: u64 = 10;
60
61#[pyfunction]
62fn _shutdown_nautilus_runtime() -> PyResult<()> {
63 shutdown_runtime(Duration::from_secs(RUNTIME_SHUTDOWN_TIMEOUT_SECS));
64 Ok(())
65}
66
67#[pymodule] #[cfg_attr(feature = "cython-compat", pyo3(name = "nautilus_pyo3"))]
74fn _libnautilus(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
75 let sys = PyModule::import(py, "sys")?;
76 let modules = sys.getattr("modules")?;
77 let sys_modules: &Bound<'_, PyAny> = modules.cast()?;
78
79 #[cfg(feature = "cython-compat")]
80 let module_name = "nautilus_trader.core.nautilus_pyo3";
81
82 #[cfg(not(feature = "cython-compat"))]
83 let module_name = "nautilus_trader._libnautilus";
84
85 sys_modules.set_item(module_name, m)?;
87
88 let n = "analysis";
90 let submodule = pyo3::wrap_pymodule!(nautilus_analysis::python::analysis);
91 m.add_wrapped(submodule)?;
92 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
93 #[cfg(feature = "cython-compat")]
94 re_export_module_attributes(m, n)?;
95
96 let n = "core";
97 let submodule = pyo3::wrap_pymodule!(nautilus_core::python::core);
98 m.add_wrapped(submodule)?;
99 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
100 #[cfg(feature = "cython-compat")]
101 re_export_module_attributes(m, n)?;
102
103 let n = "common";
104 let submodule = pyo3::wrap_pymodule!(nautilus_common::python::common);
105 m.add_wrapped(submodule)?;
106 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
107 #[cfg(feature = "cython-compat")]
108 re_export_module_attributes(m, n)?;
109
110 let n = "cryptography";
111 let submodule = pyo3::wrap_pymodule!(nautilus_cryptography::python::cryptography);
112 m.add_wrapped(submodule)?;
113 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
114 #[cfg(feature = "cython-compat")]
115 re_export_module_attributes(m, n)?;
116
117 let n = "execution";
118 let submodule = pyo3::wrap_pymodule!(nautilus_execution::python::execution);
119 m.add_wrapped(submodule)?;
120 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
121 #[cfg(feature = "cython-compat")]
122 re_export_module_attributes(m, n)?;
123
124 let n = "indicators";
125 let submodule = pyo3::wrap_pymodule!(nautilus_indicators::python::indicators);
126 m.add_wrapped(submodule)?;
127 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
128 #[cfg(feature = "cython-compat")]
129 re_export_module_attributes(m, n)?;
130
131 let n = "infrastructure";
132 let submodule = pyo3::wrap_pymodule!(nautilus_infrastructure::python::infrastructure);
133 m.add_wrapped(submodule)?;
134 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
135 #[cfg(feature = "cython-compat")]
136 re_export_module_attributes(m, n)?;
137
138 let n = "live";
139 let submodule = pyo3::wrap_pymodule!(nautilus_live::python::live);
140 m.add_wrapped(submodule)?;
141 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
142 #[cfg(feature = "cython-compat")]
143 re_export_module_attributes(m, n)?;
144
145 let n = "model";
146 let submodule = pyo3::wrap_pymodule!(nautilus_model::python::model);
147 m.add_wrapped(submodule)?;
148 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
149 #[cfg(feature = "cython-compat")]
150 re_export_module_attributes(m, n)?;
151
152 let n = "network";
153 let submodule = pyo3::wrap_pymodule!(nautilus_network::python::network);
154 m.add_wrapped(submodule)?;
155 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
156 #[cfg(feature = "cython-compat")]
157 re_export_module_attributes(m, n)?;
158
159 let n = "persistence";
160 let submodule = pyo3::wrap_pymodule!(nautilus_persistence::python::persistence);
161 m.add_wrapped(submodule)?;
162 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
163 #[cfg(feature = "cython-compat")]
164 re_export_module_attributes(m, n)?;
165
166 let n = "serialization";
167 let submodule = pyo3::wrap_pymodule!(nautilus_serialization::python::serialization);
168 m.add_wrapped(submodule)?;
169 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
170 #[cfg(feature = "cython-compat")]
171 re_export_module_attributes(m, n)?;
172
173 let n = "testkit";
174 let submodule = pyo3::wrap_pymodule!(nautilus_testkit::python::testkit);
175 m.add_wrapped(submodule)?;
176 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
177 #[cfg(feature = "cython-compat")]
178 re_export_module_attributes(m, n)?;
179
180 let n = "trading";
181 let submodule = pyo3::wrap_pymodule!(nautilus_trading::python::trading);
182 m.add_wrapped(submodule)?;
183 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
184 #[cfg(feature = "cython-compat")]
185 re_export_module_attributes(m, n)?;
186
187 let n = "architect";
192 let submodule = pyo3::wrap_pymodule!(nautilus_architect_ax::python::architect);
193 m.add_wrapped(submodule)?;
194 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
195 #[cfg(feature = "cython-compat")]
196 re_export_module_attributes(m, n)?;
197
198 let n = "binance";
199 let submodule = pyo3::wrap_pymodule!(nautilus_binance::python::binance);
200 m.add_wrapped(submodule)?;
201 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
202 #[cfg(feature = "cython-compat")]
203 re_export_module_attributes(m, n)?;
204
205 let n = "bitmex";
206 let submodule = pyo3::wrap_pymodule!(nautilus_bitmex::python::bitmex);
207 m.add_wrapped(submodule)?;
208 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
209 #[cfg(feature = "cython-compat")]
210 re_export_module_attributes(m, n)?;
211
212 let n = "bybit";
213 let submodule = pyo3::wrap_pymodule!(nautilus_bybit::python::bybit);
214 m.add_wrapped(submodule)?;
215 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
216 #[cfg(feature = "cython-compat")]
217 re_export_module_attributes(m, n)?;
218
219 let n = "coinbase_intx";
220 let submodule = pyo3::wrap_pymodule!(nautilus_coinbase_intx::python::coinbase_intx);
221 m.add_wrapped(submodule)?;
222 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
223 #[cfg(feature = "cython-compat")]
224 re_export_module_attributes(m, n)?;
225
226 let n = "databento";
227 let submodule = pyo3::wrap_pymodule!(nautilus_databento::python::databento);
228 m.add_wrapped(submodule)?;
229 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
230 #[cfg(feature = "cython-compat")]
231 re_export_module_attributes(m, n)?;
232
233 let n = "deribit";
234 let submodule = pyo3::wrap_pymodule!(nautilus_deribit::python::deribit);
235 m.add_wrapped(submodule)?;
236 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
237 #[cfg(feature = "cython-compat")]
238 re_export_module_attributes(m, n)?;
239
240 let n = "dydx";
241 let submodule = pyo3::wrap_pymodule!(nautilus_dydx::python::dydx);
242 m.add_wrapped(submodule)?;
243 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
244 #[cfg(feature = "cython-compat")]
245 re_export_module_attributes(m, n)?;
246
247 let n = "hyperliquid";
248 let submodule = pyo3::wrap_pymodule!(nautilus_hyperliquid::python::hyperliquid);
249 m.add_wrapped(submodule)?;
250 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
251 #[cfg(feature = "cython-compat")]
252 re_export_module_attributes(m, n)?;
253
254 let n = "kraken";
255 let submodule = pyo3::wrap_pymodule!(nautilus_kraken::python::kraken);
256 m.add_wrapped(submodule)?;
257 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
258 #[cfg(feature = "cython-compat")]
259 re_export_module_attributes(m, n)?;
260
261 let n = "okx";
262 let submodule = pyo3::wrap_pymodule!(nautilus_okx::python::okx);
263 m.add_wrapped(submodule)?;
264 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
265 #[cfg(feature = "cython-compat")]
266 re_export_module_attributes(m, n)?;
267
268 let n = "tardis";
269 let submodule = pyo3::wrap_pymodule!(nautilus_tardis::python::tardis);
270 m.add_wrapped(submodule)?;
271 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
272 #[cfg(feature = "cython-compat")]
273 re_export_module_attributes(m, n)?;
274
275 #[cfg(feature = "defi")]
276 {
277 let n = "blockchain";
279 let submodule = pyo3::wrap_pymodule!(nautilus_blockchain::python::blockchain);
280 m.add_wrapped(submodule)?;
281 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
282 #[cfg(feature = "cython-compat")]
283 re_export_module_attributes(m, n)?;
284 }
285
286 m.add_function(pyo3::wrap_pyfunction!(_shutdown_nautilus_runtime, m)?)?;
289 let shutdown_callable = m.getattr("_shutdown_nautilus_runtime")?;
290 let atexit = PyModule::import(py, "atexit")?;
291 atexit.call_method1("register", (shutdown_callable,))?;
292
293 Ok(())
294}
295
296#[cfg(feature = "cython-compat")]
297fn re_export_module_attributes(
298 parent_module: &Bound<'_, PyModule>,
299 submodule_name: &str,
300) -> PyResult<()> {
301 let submodule = parent_module.getattr(submodule_name)?;
302 for item_name in submodule.dir()? {
303 let item_name_str: &str = item_name.extract()?;
304 if let Ok(attr) = submodule.getattr(item_name_str) {
305 parent_module.add(item_name_str, attr)?;
306 }
307 }
308
309 Ok(())
310}
311
312pub fn stub_info() -> pyo3_stub_gen::Result<pyo3_stub_gen::StubInfo> {
330 let workspace_root = Path::new(env!("CARGO_MANIFEST_DIR"))
331 .parent()
332 .unwrap()
333 .parent()
334 .unwrap();
335 let pyproject_path = workspace_root.join("python").join("pyproject.toml");
336
337 pyo3_stub_gen::StubInfo::from_pyproject_toml(&pyproject_path)
338}