1#![warn(rustc::all)]
51#![deny(unsafe_code)]
52#![deny(unsafe_op_in_unsafe_fn)]
53#![deny(nonstandard_style)]
54#![deny(missing_debug_implementations)]
55#![deny(clippy::missing_errors_doc)]
56#![deny(clippy::missing_panics_doc)]
57#![deny(rustdoc::broken_intra_doc_links)]
58
59use std::{path::Path, time::Duration};
60
61#[cfg(feature = "mimalloc")]
62use mimalloc::MiMalloc;
63use nautilus_common::live::runtime::shutdown_runtime;
64use nautilus_system::python::controller::PyController;
65use pyo3::{prelude::*, pyfunction};
66
67#[cfg(feature = "mimalloc")]
68#[global_allocator]
69static GLOBAL: MiMalloc = MiMalloc;
70
71const RUNTIME_SHUTDOWN_TIMEOUT_SECS: u64 = 10;
72
73#[pyfunction]
74fn _shutdown_nautilus_runtime() {
75 shutdown_runtime(Duration::from_secs(RUNTIME_SHUTDOWN_TIMEOUT_SECS));
76}
77
78pub fn register_embedded_module() {
90 pyo3::append_to_inittab!(_libnautilus);
91}
92
93#[pymodule] fn _libnautilus(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
98 #[cfg(feature = "mimalloc")]
99 nautilus_common::logging::headers::register_allocator_mimalloc();
100
101 let sys = PyModule::import(py, "sys")?;
102 let modules = sys.getattr("modules")?;
103 let sys_modules: &Bound<'_, PyAny> = modules.cast()?;
104
105 let module_name = "nautilus_trader._libnautilus";
106
107 sys_modules.set_item(module_name, m)?;
109
110 let n = "analysis";
112 let submodule = pyo3::wrap_pymodule!(nautilus_analysis::python::analysis);
113 m.add_wrapped(submodule)?;
114 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
115
116 let n = "core";
117 let submodule = pyo3::wrap_pymodule!(nautilus_core::python::core);
118 m.add_wrapped(submodule)?;
119 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
120
121 let n = "common";
122 let submodule = pyo3::wrap_pymodule!(nautilus_common::python::common);
123 m.add_wrapped(submodule)?;
124 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
125
126 let n = "cryptography";
127 let submodule = pyo3::wrap_pymodule!(nautilus_cryptography::python::cryptography);
128 m.add_wrapped(submodule)?;
129 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
130
131 let n = "data";
132 let submodule = pyo3::wrap_pymodule!(nautilus_data::python::data);
133 m.add_wrapped(submodule)?;
134 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
135
136 let n = "execution";
137 let submodule = pyo3::wrap_pymodule!(nautilus_execution::python::execution);
138 m.add_wrapped(submodule)?;
139 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
140
141 let n = "indicators";
142 let submodule = pyo3::wrap_pymodule!(nautilus_indicators::python::indicators);
143 m.add_wrapped(submodule)?;
144 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
145
146 let n = "infrastructure";
147 let submodule = pyo3::wrap_pymodule!(nautilus_infrastructure::python::infrastructure);
148 m.add_wrapped(submodule)?;
149 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
150
151 let n = "live";
152 let submodule = pyo3::wrap_pymodule!(nautilus_live::python::live);
153 m.add_wrapped(submodule)?;
154 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
155
156 let n = "model";
157 let submodule = pyo3::wrap_pymodule!(nautilus_model::python::model);
158 m.add_wrapped(submodule)?;
159 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
160
161 let n = "network";
162 let submodule = pyo3::wrap_pymodule!(nautilus_network::python::network);
163 m.add_wrapped(submodule)?;
164 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
165
166 let n = "persistence";
167 let submodule = pyo3::wrap_pymodule!(nautilus_persistence::python::persistence);
168 m.add_wrapped(submodule)?;
169 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
170
171 let n = "portfolio";
172 let submodule = pyo3::wrap_pymodule!(nautilus_portfolio::python::portfolio);
173 m.add_wrapped(submodule)?;
174 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
175
176 let n = "risk";
177 let submodule = pyo3::wrap_pymodule!(nautilus_risk::python::risk);
178 m.add_wrapped(submodule)?;
179 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
180
181 let n = "serialization";
182 let submodule = pyo3::wrap_pymodule!(nautilus_serialization::python::serialization);
183 m.add_wrapped(submodule)?;
184 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(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
191 let n = "trading";
192 let submodule = pyo3::wrap_pymodule!(nautilus_trading::python::trading);
193 m.add_wrapped(submodule)?;
194
195 m.getattr(n)?
198 .cast::<PyModule>()?
199 .add_class::<PyController>()?;
200 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
201
202 let n = "backtest";
203 let submodule = pyo3::wrap_pymodule!(nautilus_backtest::python::backtest);
204 m.add_wrapped(submodule)?;
205 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
206
207 #[cfg(feature = "adapters")]
212 {
213 let n = "architect_ax";
214 let submodule = pyo3::wrap_pymodule!(nautilus_architect_ax::python::architect_ax);
215 m.add_wrapped(submodule)?;
216 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
217 }
218
219 #[cfg(feature = "betfair")]
220 {
221 let n = "betfair";
222 let submodule = pyo3::wrap_pymodule!(nautilus_betfair::python::betfair);
223 m.add_wrapped(submodule)?;
224 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
225 }
226
227 #[cfg(feature = "adapters")]
228 {
229 let n = "binance";
230 let submodule = pyo3::wrap_pymodule!(nautilus_binance::python::binance);
231 m.add_wrapped(submodule)?;
232 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
233 }
234
235 #[cfg(feature = "adapters")]
236 {
237 let n = "bybit";
238 let submodule = pyo3::wrap_pymodule!(nautilus_bybit::python::bybit);
239 m.add_wrapped(submodule)?;
240 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
241 }
242
243 #[cfg(feature = "coinapi")]
244 {
245 let n = "coinapi";
246 let submodule = pyo3::wrap_pymodule!(nautilus_coinapi::python::coinapi);
247 m.add_wrapped(submodule)?;
248 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
249 }
250
251 #[cfg(feature = "adapters")]
252 {
253 let n = "coinbase";
254 let submodule = pyo3::wrap_pymodule!(nautilus_coinbase::python::coinbase);
255 m.add_wrapped(submodule)?;
256 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
257 }
258
259 #[cfg(feature = "adapters")]
260 {
261 let n = "databento";
262 let submodule = pyo3::wrap_pymodule!(nautilus_databento::python::databento);
263 m.add_wrapped(submodule)?;
264 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
265 }
266
267 #[cfg(feature = "adapters")]
268 {
269 let n = "deribit";
270 let submodule = pyo3::wrap_pymodule!(nautilus_deribit::python::deribit);
271 m.add_wrapped(submodule)?;
272 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
273 }
274
275 #[cfg(feature = "adapters")]
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 }
282
283 #[cfg(feature = "adapters")]
284 {
285 let n = "dydx";
286 let submodule = pyo3::wrap_pymodule!(nautilus_dydx::python::dydx);
287 m.add_wrapped(submodule)?;
288 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
289 }
290
291 #[cfg(feature = "adapters")]
292 {
293 let n = "hyperliquid";
294 let submodule = pyo3::wrap_pymodule!(nautilus_hyperliquid::python::hyperliquid);
295 m.add_wrapped(submodule)?;
296 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
297 }
298
299 #[cfg(feature = "adapters")]
300 {
301 let n = "kraken";
302 let submodule = pyo3::wrap_pymodule!(nautilus_kraken::python::kraken);
303 m.add_wrapped(submodule)?;
304 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
305 }
306
307 #[cfg(feature = "adapters")]
308 {
309 let n = "lighter";
310 let submodule = pyo3::wrap_pymodule!(nautilus_lighter::python::lighter);
311 m.add_wrapped(submodule)?;
312 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
313 }
314
315 #[cfg(feature = "adapters")]
316 {
317 let n = "interactive_brokers";
318 let submodule =
319 pyo3::wrap_pymodule!(nautilus_interactive_brokers::python::interactive_brokers);
320 m.add_wrapped(submodule)?;
321 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
322 }
323
324 #[cfg(feature = "adapters")]
325 {
326 let n = "okx";
327 let submodule = pyo3::wrap_pymodule!(nautilus_okx::python::okx);
328 m.add_wrapped(submodule)?;
329 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
330 }
331
332 #[cfg(feature = "adapters")]
333 {
334 let n = "polymarket";
335 let submodule = pyo3::wrap_pymodule!(nautilus_polymarket::python::polymarket);
336 m.add_wrapped(submodule)?;
337 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
338 }
339
340 #[cfg(feature = "adapters")]
341 {
342 let n = "sandbox";
343 let submodule = pyo3::wrap_pymodule!(nautilus_sandbox::python::sandbox);
344 m.add_wrapped(submodule)?;
345 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
346 }
347
348 #[cfg(feature = "adapters")]
349 {
350 let n = "tardis";
351 let submodule = pyo3::wrap_pymodule!(nautilus_tardis::python::tardis);
352 m.add_wrapped(submodule)?;
353 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
354 }
355
356 #[cfg(feature = "defi")]
357 {
358 let n = "blockchain";
360 let submodule = pyo3::wrap_pymodule!(nautilus_blockchain::python::blockchain);
361 m.add_wrapped(submodule)?;
362 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
363 }
364
365 m.add_function(pyo3::wrap_pyfunction!(_shutdown_nautilus_runtime, m)?)?;
368 let shutdown_callable = m.getattr("_shutdown_nautilus_runtime")?;
369 let atexit = PyModule::import(py, "atexit")?;
370 atexit.call_method1("register", (shutdown_callable,))?;
371
372 Ok(())
373}
374
375pub fn stub_info() -> pyo3_stub_gen::Result<pyo3_stub_gen::StubInfo> {
393 let workspace_root = Path::new(env!("CARGO_MANIFEST_DIR"))
394 .parent()
395 .unwrap()
396 .parent()
397 .unwrap();
398 let pyproject_path = workspace_root.join("python").join("pyproject.toml");
399
400 pyo3_stub_gen::StubInfo::from_pyproject_toml(&pyproject_path)
401}