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 = "risk";
173 let submodule = pyo3::wrap_pymodule!(nautilus_risk::python::risk);
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 = "serialization";
180 let submodule = pyo3::wrap_pymodule!(nautilus_serialization::python::serialization);
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 = "testkit";
187 let submodule = pyo3::wrap_pymodule!(nautilus_testkit::python::testkit);
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 = "trading";
194 let submodule = pyo3::wrap_pymodule!(nautilus_trading::python::trading);
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 = "backtest";
201 let submodule = pyo3::wrap_pymodule!(nautilus_backtest::python::backtest);
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 = "architect";
212 let submodule = pyo3::wrap_pymodule!(nautilus_architect_ax::python::architect);
213 m.add_wrapped(submodule)?;
214 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
215 #[cfg(feature = "cython-compat")]
216 re_export_module_attributes(m, n)?;
217
218 let n = "binance";
219 let submodule = pyo3::wrap_pymodule!(nautilus_binance::python::binance);
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 let n = "bitmex";
226 let submodule = pyo3::wrap_pymodule!(nautilus_bitmex::python::bitmex);
227 m.add_wrapped(submodule)?;
228 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
229 #[cfg(feature = "cython-compat")]
230 re_export_module_attributes(m, n)?;
231
232 let n = "bybit";
233 let submodule = pyo3::wrap_pymodule!(nautilus_bybit::python::bybit);
234 m.add_wrapped(submodule)?;
235 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
236 #[cfg(feature = "cython-compat")]
237 re_export_module_attributes(m, n)?;
238
239 let n = "coinbase";
240 let submodule = pyo3::wrap_pymodule!(nautilus_coinbase::python::coinbase);
241 m.add_wrapped(submodule)?;
242 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
243 #[cfg(feature = "cython-compat")]
244 re_export_module_attributes(m, n)?;
245
246 let n = "databento";
247 let submodule = pyo3::wrap_pymodule!(nautilus_databento::python::databento);
248 m.add_wrapped(submodule)?;
249 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
250 #[cfg(feature = "cython-compat")]
251 re_export_module_attributes(m, n)?;
252
253 let n = "deribit";
254 let submodule = pyo3::wrap_pymodule!(nautilus_deribit::python::deribit);
255 m.add_wrapped(submodule)?;
256 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
257 #[cfg(feature = "cython-compat")]
258 re_export_module_attributes(m, n)?;
259
260 let n = "dydx";
261 let submodule = pyo3::wrap_pymodule!(nautilus_dydx::python::dydx);
262 m.add_wrapped(submodule)?;
263 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
264 #[cfg(feature = "cython-compat")]
265 re_export_module_attributes(m, n)?;
266
267 let n = "hyperliquid";
268 let submodule = pyo3::wrap_pymodule!(nautilus_hyperliquid::python::hyperliquid);
269 m.add_wrapped(submodule)?;
270 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
271 #[cfg(feature = "cython-compat")]
272 re_export_module_attributes(m, n)?;
273
274 let n = "kraken";
275 let submodule = pyo3::wrap_pymodule!(nautilus_kraken::python::kraken);
276 m.add_wrapped(submodule)?;
277 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
278 #[cfg(feature = "cython-compat")]
279 re_export_module_attributes(m, n)?;
280
281 let n = "interactive_brokers";
282 let submodule = pyo3::wrap_pymodule!(nautilus_interactive_brokers::python::interactive_brokers);
283 m.add_wrapped(submodule)?;
284 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
285 #[cfg(feature = "cython-compat")]
286 re_export_module_attributes(m, n)?;
287
288 let n = "okx";
289 let submodule = pyo3::wrap_pymodule!(nautilus_okx::python::okx);
290 m.add_wrapped(submodule)?;
291 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
292 #[cfg(feature = "cython-compat")]
293 re_export_module_attributes(m, n)?;
294
295 let n = "polymarket";
296 let submodule = pyo3::wrap_pymodule!(nautilus_polymarket::python::polymarket);
297 m.add_wrapped(submodule)?;
298 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
299 #[cfg(feature = "cython-compat")]
300 re_export_module_attributes(m, n)?;
301
302 let n = "sandbox";
303 let submodule = pyo3::wrap_pymodule!(nautilus_sandbox::python::sandbox);
304 m.add_wrapped(submodule)?;
305 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
306 #[cfg(feature = "cython-compat")]
307 re_export_module_attributes(m, n)?;
308
309 let n = "tardis";
310 let submodule = pyo3::wrap_pymodule!(nautilus_tardis::python::tardis);
311 m.add_wrapped(submodule)?;
312 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
313 #[cfg(feature = "cython-compat")]
314 re_export_module_attributes(m, n)?;
315
316 #[cfg(feature = "defi")]
317 {
318 let n = "blockchain";
320 let submodule = pyo3::wrap_pymodule!(nautilus_blockchain::python::blockchain);
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
327 m.add_function(pyo3::wrap_pyfunction!(_shutdown_nautilus_runtime, m)?)?;
330 let shutdown_callable = m.getattr("_shutdown_nautilus_runtime")?;
331 let atexit = PyModule::import(py, "atexit")?;
332 atexit.call_method1("register", (shutdown_callable,))?;
333
334 Ok(())
335}
336
337#[cfg(feature = "cython-compat")]
338fn re_export_module_attributes(
339 parent_module: &Bound<'_, PyModule>,
340 submodule_name: &str,
341) -> PyResult<()> {
342 let submodule = parent_module.getattr(submodule_name)?;
343 for item_name in submodule.dir()? {
344 let item_name_str: &str = item_name.extract()?;
345 if let Ok(attr) = submodule.getattr(item_name_str) {
346 parent_module.add(item_name_str, attr)?;
347 }
348 }
349
350 Ok(())
351}
352
353pub fn stub_info() -> pyo3_stub_gen::Result<pyo3_stub_gen::StubInfo> {
371 let workspace_root = Path::new(env!("CARGO_MANIFEST_DIR"))
372 .parent()
373 .unwrap()
374 .parent()
375 .unwrap();
376 let pyproject_path = workspace_root.join("python").join("pyproject.toml");
377
378 pyo3_stub_gen::StubInfo::from_pyproject_toml(&pyproject_path)
379}