1#![warn(rustc::all)]
48#![deny(unsafe_code)]
49#![deny(unsafe_op_in_unsafe_fn)]
50#![deny(nonstandard_style)]
51#![deny(missing_debug_implementations)]
52#![deny(clippy::missing_errors_doc)]
53#![deny(clippy::missing_panics_doc)]
54#![deny(rustdoc::broken_intra_doc_links)]
55
56use std::{path::Path, time::Duration};
57
58use nautilus_common::live::runtime::shutdown_runtime;
59use pyo3::{prelude::*, pyfunction};
60
61const RUNTIME_SHUTDOWN_TIMEOUT_SECS: u64 = 10;
62
63#[pyfunction]
64fn _shutdown_nautilus_runtime() -> PyResult<()> {
65 shutdown_runtime(Duration::from_secs(RUNTIME_SHUTDOWN_TIMEOUT_SECS));
66 Ok(())
67}
68
69#[pymodule] #[cfg_attr(feature = "cython-compat", pyo3(name = "nautilus_pyo3"))]
76fn _libnautilus(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
77 let sys = PyModule::import(py, "sys")?;
78 let modules = sys.getattr("modules")?;
79 let sys_modules: &Bound<'_, PyAny> = modules.cast()?;
80
81 #[cfg(feature = "cython-compat")]
82 let module_name = "nautilus_trader.core.nautilus_pyo3";
83
84 #[cfg(not(feature = "cython-compat"))]
85 let module_name = "nautilus_trader._libnautilus";
86
87 sys_modules.set_item(module_name, m)?;
89
90 let n = "analysis";
92 let submodule = pyo3::wrap_pymodule!(nautilus_analysis::python::analysis);
93 m.add_wrapped(submodule)?;
94 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
95 #[cfg(feature = "cython-compat")]
96 re_export_module_attributes(m, n)?;
97
98 let n = "core";
99 let submodule = pyo3::wrap_pymodule!(nautilus_core::python::core);
100 m.add_wrapped(submodule)?;
101 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
102 #[cfg(feature = "cython-compat")]
103 re_export_module_attributes(m, n)?;
104
105 let n = "common";
106 let submodule = pyo3::wrap_pymodule!(nautilus_common::python::common);
107 m.add_wrapped(submodule)?;
108 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
109 #[cfg(feature = "cython-compat")]
110 re_export_module_attributes(m, n)?;
111
112 let n = "cryptography";
113 let submodule = pyo3::wrap_pymodule!(nautilus_cryptography::python::cryptography);
114 m.add_wrapped(submodule)?;
115 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
116 #[cfg(feature = "cython-compat")]
117 re_export_module_attributes(m, n)?;
118
119 let n = "execution";
120 let submodule = pyo3::wrap_pymodule!(nautilus_execution::python::execution);
121 m.add_wrapped(submodule)?;
122 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
123 #[cfg(feature = "cython-compat")]
124 re_export_module_attributes(m, n)?;
125
126 let n = "indicators";
127 let submodule = pyo3::wrap_pymodule!(nautilus_indicators::python::indicators);
128 m.add_wrapped(submodule)?;
129 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
130 #[cfg(feature = "cython-compat")]
131 re_export_module_attributes(m, n)?;
132
133 let n = "infrastructure";
134 let submodule = pyo3::wrap_pymodule!(nautilus_infrastructure::python::infrastructure);
135 m.add_wrapped(submodule)?;
136 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
137 #[cfg(feature = "cython-compat")]
138 re_export_module_attributes(m, n)?;
139
140 let n = "live";
141 let submodule = pyo3::wrap_pymodule!(nautilus_live::python::live);
142 m.add_wrapped(submodule)?;
143 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
144 #[cfg(feature = "cython-compat")]
145 re_export_module_attributes(m, n)?;
146
147 let n = "model";
148 let submodule = pyo3::wrap_pymodule!(nautilus_model::python::model);
149 m.add_wrapped(submodule)?;
150 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
151 #[cfg(feature = "cython-compat")]
152 re_export_module_attributes(m, n)?;
153
154 let n = "network";
155 let submodule = pyo3::wrap_pymodule!(nautilus_network::python::network);
156 m.add_wrapped(submodule)?;
157 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
158 #[cfg(feature = "cython-compat")]
159 re_export_module_attributes(m, n)?;
160
161 let n = "persistence";
162 let submodule = pyo3::wrap_pymodule!(nautilus_persistence::python::persistence);
163 m.add_wrapped(submodule)?;
164 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
165 #[cfg(feature = "cython-compat")]
166 re_export_module_attributes(m, n)?;
167
168 let n = "serialization";
169 let submodule = pyo3::wrap_pymodule!(nautilus_serialization::python::serialization);
170 m.add_wrapped(submodule)?;
171 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
172 #[cfg(feature = "cython-compat")]
173 re_export_module_attributes(m, n)?;
174
175 let n = "testkit";
176 let submodule = pyo3::wrap_pymodule!(nautilus_testkit::python::testkit);
177 m.add_wrapped(submodule)?;
178 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
179 #[cfg(feature = "cython-compat")]
180 re_export_module_attributes(m, n)?;
181
182 let n = "trading";
183 let submodule = pyo3::wrap_pymodule!(nautilus_trading::python::trading);
184 m.add_wrapped(submodule)?;
185 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
186 #[cfg(feature = "cython-compat")]
187 re_export_module_attributes(m, n)?;
188
189 let n = "architect";
194 let submodule = pyo3::wrap_pymodule!(nautilus_architect_ax::python::architect);
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 = "binance";
201 let submodule = pyo3::wrap_pymodule!(nautilus_binance::python::binance);
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 = "bitmex";
208 let submodule = pyo3::wrap_pymodule!(nautilus_bitmex::python::bitmex);
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 = "bybit";
215 let submodule = pyo3::wrap_pymodule!(nautilus_bybit::python::bybit);
216 m.add_wrapped(submodule)?;
217 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
218 #[cfg(feature = "cython-compat")]
219 re_export_module_attributes(m, n)?;
220
221 let n = "coinbase_intx";
222 let submodule = pyo3::wrap_pymodule!(nautilus_coinbase_intx::python::coinbase_intx);
223 m.add_wrapped(submodule)?;
224 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
225 #[cfg(feature = "cython-compat")]
226 re_export_module_attributes(m, n)?;
227
228 let n = "databento";
229 let submodule = pyo3::wrap_pymodule!(nautilus_databento::python::databento);
230 m.add_wrapped(submodule)?;
231 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
232 #[cfg(feature = "cython-compat")]
233 re_export_module_attributes(m, n)?;
234
235 let n = "deribit";
236 let submodule = pyo3::wrap_pymodule!(nautilus_deribit::python::deribit);
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 = "dydx";
243 let submodule = pyo3::wrap_pymodule!(nautilus_dydx::python::dydx);
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 = "hyperliquid";
250 let submodule = pyo3::wrap_pymodule!(nautilus_hyperliquid::python::hyperliquid);
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 = "kraken";
257 let submodule = pyo3::wrap_pymodule!(nautilus_kraken::python::kraken);
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 = "okx";
264 let submodule = pyo3::wrap_pymodule!(nautilus_okx::python::okx);
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 = "sandbox";
271 let submodule = pyo3::wrap_pymodule!(nautilus_sandbox::python::sandbox);
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 = "tardis";
278 let submodule = pyo3::wrap_pymodule!(nautilus_tardis::python::tardis);
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 #[cfg(feature = "defi")]
285 {
286 let n = "blockchain";
288 let submodule = pyo3::wrap_pymodule!(nautilus_blockchain::python::blockchain);
289 m.add_wrapped(submodule)?;
290 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
291 #[cfg(feature = "cython-compat")]
292 re_export_module_attributes(m, n)?;
293 }
294
295 m.add_function(pyo3::wrap_pyfunction!(_shutdown_nautilus_runtime, m)?)?;
298 let shutdown_callable = m.getattr("_shutdown_nautilus_runtime")?;
299 let atexit = PyModule::import(py, "atexit")?;
300 atexit.call_method1("register", (shutdown_callable,))?;
301
302 Ok(())
303}
304
305#[cfg(feature = "cython-compat")]
306fn re_export_module_attributes(
307 parent_module: &Bound<'_, PyModule>,
308 submodule_name: &str,
309) -> PyResult<()> {
310 let submodule = parent_module.getattr(submodule_name)?;
311 for item_name in submodule.dir()? {
312 let item_name_str: &str = item_name.extract()?;
313 if let Ok(attr) = submodule.getattr(item_name_str) {
314 parent_module.add(item_name_str, attr)?;
315 }
316 }
317
318 Ok(())
319}
320
321pub fn stub_info() -> pyo3_stub_gen::Result<pyo3_stub_gen::StubInfo> {
339 let workspace_root = Path::new(env!("CARGO_MANIFEST_DIR"))
340 .parent()
341 .unwrap()
342 .parent()
343 .unwrap();
344 let pyproject_path = workspace_root.join("python").join("pyproject.toml");
345
346 pyo3_stub_gen::StubInfo::from_pyproject_toml(&pyproject_path)
347}