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