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() {
63 shutdown_runtime(Duration::from_secs(RUNTIME_SHUTDOWN_TIMEOUT_SECS));
64}
65
66#[pymodule] #[cfg_attr(feature = "cython-compat", pyo3(name = "nautilus_pyo3"))]
73fn _libnautilus(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
74 let sys = PyModule::import(py, "sys")?;
75 let modules = sys.getattr("modules")?;
76 let sys_modules: &Bound<'_, PyAny> = modules.cast()?;
77
78 #[cfg(feature = "cython-compat")]
79 let module_name = "nautilus_trader.core.nautilus_pyo3";
80
81 #[cfg(not(feature = "cython-compat"))]
82 let module_name = "nautilus_trader._libnautilus";
83
84 sys_modules.set_item(module_name, m)?;
86
87 let n = "analysis";
89 let submodule = pyo3::wrap_pymodule!(nautilus_analysis::python::analysis);
90 m.add_wrapped(submodule)?;
91 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
92 #[cfg(feature = "cython-compat")]
93 re_export_module_attributes(m, n)?;
94
95 let n = "core";
96 let submodule = pyo3::wrap_pymodule!(nautilus_core::python::core);
97 m.add_wrapped(submodule)?;
98 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
99 #[cfg(feature = "cython-compat")]
100 re_export_module_attributes(m, n)?;
101
102 let n = "common";
103 let submodule = pyo3::wrap_pymodule!(nautilus_common::python::common);
104 m.add_wrapped(submodule)?;
105 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
106 #[cfg(feature = "cython-compat")]
107 re_export_module_attributes(m, n)?;
108
109 let n = "cryptography";
110 let submodule = pyo3::wrap_pymodule!(nautilus_cryptography::python::cryptography);
111 m.add_wrapped(submodule)?;
112 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
113 #[cfg(feature = "cython-compat")]
114 re_export_module_attributes(m, n)?;
115
116 let n = "data";
117 let submodule = pyo3::wrap_pymodule!(nautilus_data::python::data);
118 m.add_wrapped(submodule)?;
119 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
120 #[cfg(feature = "cython-compat")]
121 re_export_module_attributes(m, n)?;
122
123 let n = "execution";
124 let submodule = pyo3::wrap_pymodule!(nautilus_execution::python::execution);
125 m.add_wrapped(submodule)?;
126 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
127 #[cfg(feature = "cython-compat")]
128 re_export_module_attributes(m, n)?;
129
130 let n = "indicators";
131 let submodule = pyo3::wrap_pymodule!(nautilus_indicators::python::indicators);
132 m.add_wrapped(submodule)?;
133 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
134 #[cfg(feature = "cython-compat")]
135 re_export_module_attributes(m, n)?;
136
137 let n = "infrastructure";
138 let submodule = pyo3::wrap_pymodule!(nautilus_infrastructure::python::infrastructure);
139 m.add_wrapped(submodule)?;
140 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
141 #[cfg(feature = "cython-compat")]
142 re_export_module_attributes(m, n)?;
143
144 let n = "live";
145 let submodule = pyo3::wrap_pymodule!(nautilus_live::python::live);
146 m.add_wrapped(submodule)?;
147 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
148 #[cfg(feature = "cython-compat")]
149 re_export_module_attributes(m, n)?;
150
151 let n = "model";
152 let submodule = pyo3::wrap_pymodule!(nautilus_model::python::model);
153 m.add_wrapped(submodule)?;
154 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
155 #[cfg(feature = "cython-compat")]
156 re_export_module_attributes(m, n)?;
157
158 let n = "network";
159 let submodule = pyo3::wrap_pymodule!(nautilus_network::python::network);
160 m.add_wrapped(submodule)?;
161 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
162 #[cfg(feature = "cython-compat")]
163 re_export_module_attributes(m, n)?;
164
165 let n = "persistence";
166 let submodule = pyo3::wrap_pymodule!(nautilus_persistence::python::persistence);
167 m.add_wrapped(submodule)?;
168 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
169 #[cfg(feature = "cython-compat")]
170 re_export_module_attributes(m, n)?;
171
172 let n = "portfolio";
173 let submodule = pyo3::wrap_pymodule!(nautilus_portfolio::python::portfolio);
174 m.add_wrapped(submodule)?;
175 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
176 #[cfg(feature = "cython-compat")]
177 re_export_module_attributes(m, n)?;
178
179 let n = "risk";
180 let submodule = pyo3::wrap_pymodule!(nautilus_risk::python::risk);
181 m.add_wrapped(submodule)?;
182 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
183 #[cfg(feature = "cython-compat")]
184 re_export_module_attributes(m, n)?;
185
186 let n = "serialization";
187 let submodule = pyo3::wrap_pymodule!(nautilus_serialization::python::serialization);
188 m.add_wrapped(submodule)?;
189 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
190 #[cfg(feature = "cython-compat")]
191 re_export_module_attributes(m, n)?;
192
193 let n = "testkit";
194 let submodule = pyo3::wrap_pymodule!(nautilus_testkit::python::testkit);
195 m.add_wrapped(submodule)?;
196 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
197 #[cfg(feature = "cython-compat")]
198 re_export_module_attributes(m, n)?;
199
200 let n = "trading";
201 let submodule = pyo3::wrap_pymodule!(nautilus_trading::python::trading);
202 m.add_wrapped(submodule)?;
203 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
204 #[cfg(feature = "cython-compat")]
205 re_export_module_attributes(m, n)?;
206
207 let n = "backtest";
208 let submodule = pyo3::wrap_pymodule!(nautilus_backtest::python::backtest);
209 m.add_wrapped(submodule)?;
210 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
211 #[cfg(feature = "cython-compat")]
212 re_export_module_attributes(m, n)?;
213
214 let n = "architect_ax";
219 let submodule = pyo3::wrap_pymodule!(nautilus_architect_ax::python::architect_ax);
220 m.add_wrapped(submodule)?;
221 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
222 #[cfg(feature = "cython-compat")]
223 re_export_module_attributes(m, n)?;
224
225 #[cfg(feature = "betfair")]
226 {
227 let n = "betfair";
228 let submodule = pyo3::wrap_pymodule!(nautilus_betfair::python::betfair);
229 m.add_wrapped(submodule)?;
230 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
231 #[cfg(feature = "cython-compat")]
232 re_export_module_attributes(m, n)?;
233 }
234
235 let n = "binance";
236 let submodule = pyo3::wrap_pymodule!(nautilus_binance::python::binance);
237 m.add_wrapped(submodule)?;
238 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
239 #[cfg(feature = "cython-compat")]
240 re_export_module_attributes(m, n)?;
241
242 let n = "bitmex";
243 let submodule = pyo3::wrap_pymodule!(nautilus_bitmex::python::bitmex);
244 m.add_wrapped(submodule)?;
245 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
246 #[cfg(feature = "cython-compat")]
247 re_export_module_attributes(m, n)?;
248
249 let n = "bybit";
250 let submodule = pyo3::wrap_pymodule!(nautilus_bybit::python::bybit);
251 m.add_wrapped(submodule)?;
252 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
253 #[cfg(feature = "cython-compat")]
254 re_export_module_attributes(m, n)?;
255
256 let n = "coinbase";
257 let submodule = pyo3::wrap_pymodule!(nautilus_coinbase::python::coinbase);
258 m.add_wrapped(submodule)?;
259 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
260 #[cfg(feature = "cython-compat")]
261 re_export_module_attributes(m, n)?;
262
263 let n = "databento";
264 let submodule = pyo3::wrap_pymodule!(nautilus_databento::python::databento);
265 m.add_wrapped(submodule)?;
266 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
267 #[cfg(feature = "cython-compat")]
268 re_export_module_attributes(m, n)?;
269
270 let n = "deribit";
271 let submodule = pyo3::wrap_pymodule!(nautilus_deribit::python::deribit);
272 m.add_wrapped(submodule)?;
273 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
274 #[cfg(feature = "cython-compat")]
275 re_export_module_attributes(m, n)?;
276
277 let n = "derive";
278 let submodule = pyo3::wrap_pymodule!(nautilus_derive::python::derive);
279 m.add_wrapped(submodule)?;
280 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
281 #[cfg(feature = "cython-compat")]
282 re_export_module_attributes(m, n)?;
283
284 let n = "dydx";
285 let submodule = pyo3::wrap_pymodule!(nautilus_dydx::python::dydx);
286 m.add_wrapped(submodule)?;
287 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
288 #[cfg(feature = "cython-compat")]
289 re_export_module_attributes(m, n)?;
290
291 let n = "hyperliquid";
292 let submodule = pyo3::wrap_pymodule!(nautilus_hyperliquid::python::hyperliquid);
293 m.add_wrapped(submodule)?;
294 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
295 #[cfg(feature = "cython-compat")]
296 re_export_module_attributes(m, n)?;
297
298 let n = "kraken";
299 let submodule = pyo3::wrap_pymodule!(nautilus_kraken::python::kraken);
300 m.add_wrapped(submodule)?;
301 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
302 #[cfg(feature = "cython-compat")]
303 re_export_module_attributes(m, n)?;
304
305 let n = "lighter";
306 let submodule = pyo3::wrap_pymodule!(nautilus_lighter::python::lighter);
307 m.add_wrapped(submodule)?;
308 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
309 #[cfg(feature = "cython-compat")]
310 re_export_module_attributes(m, n)?;
311
312 let n = "interactive_brokers";
313 let submodule = pyo3::wrap_pymodule!(nautilus_interactive_brokers::python::interactive_brokers);
314 m.add_wrapped(submodule)?;
315 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
316 #[cfg(feature = "cython-compat")]
317 re_export_module_attributes(m, n)?;
318
319 let n = "okx";
320 let submodule = pyo3::wrap_pymodule!(nautilus_okx::python::okx);
321 m.add_wrapped(submodule)?;
322 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
323 #[cfg(feature = "cython-compat")]
324 re_export_module_attributes(m, n)?;
325
326 let n = "polymarket";
327 let submodule = pyo3::wrap_pymodule!(nautilus_polymarket::python::polymarket);
328 m.add_wrapped(submodule)?;
329 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
330 #[cfg(feature = "cython-compat")]
331 re_export_module_attributes(m, n)?;
332
333 let n = "sandbox";
334 let submodule = pyo3::wrap_pymodule!(nautilus_sandbox::python::sandbox);
335 m.add_wrapped(submodule)?;
336 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
337 #[cfg(feature = "cython-compat")]
338 re_export_module_attributes(m, n)?;
339
340 let n = "tardis";
341 let submodule = pyo3::wrap_pymodule!(nautilus_tardis::python::tardis);
342 m.add_wrapped(submodule)?;
343 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
344 #[cfg(feature = "cython-compat")]
345 re_export_module_attributes(m, n)?;
346
347 #[cfg(feature = "defi")]
348 {
349 let n = "blockchain";
351 let submodule = pyo3::wrap_pymodule!(nautilus_blockchain::python::blockchain);
352 m.add_wrapped(submodule)?;
353 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
354 #[cfg(feature = "cython-compat")]
355 re_export_module_attributes(m, n)?;
356 }
357
358 m.add_function(pyo3::wrap_pyfunction!(_shutdown_nautilus_runtime, m)?)?;
361 let shutdown_callable = m.getattr("_shutdown_nautilus_runtime")?;
362 let atexit = PyModule::import(py, "atexit")?;
363 atexit.call_method1("register", (shutdown_callable,))?;
364
365 Ok(())
366}
367
368#[cfg(feature = "cython-compat")]
369fn re_export_module_attributes(
370 parent_module: &Bound<'_, PyModule>,
371 submodule_name: &str,
372) -> PyResult<()> {
373 let submodule = parent_module.getattr(submodule_name)?;
374 for item_name in submodule.dir()? {
375 let item_name_str: &str = item_name.extract()?;
376 if let Ok(attr) = submodule.getattr(item_name_str) {
377 parent_module.add(item_name_str, attr)?;
378 }
379 }
380
381 Ok(())
382}
383
384pub fn stub_info() -> pyo3_stub_gen::Result<pyo3_stub_gen::StubInfo> {
402 let workspace_root = Path::new(env!("CARGO_MANIFEST_DIR"))
403 .parent()
404 .unwrap()
405 .parent()
406 .unwrap();
407 let pyproject_path = workspace_root.join("python").join("pyproject.toml");
408
409 pyo3_stub_gen::StubInfo::from_pyproject_toml(&pyproject_path)
410}