1#![warn(rustc::all)]
49#![deny(unsafe_code)]
50#![deny(unsafe_op_in_unsafe_fn)]
51#![deny(nonstandard_style)]
52#![deny(missing_debug_implementations)]
53#![deny(clippy::missing_errors_doc)]
54#![deny(clippy::missing_panics_doc)]
55#![deny(rustdoc::broken_intra_doc_links)]
56
57use std::{path::Path, time::Duration};
58
59#[cfg(feature = "mimalloc")]
60use mimalloc::MiMalloc;
61use nautilus_common::live::runtime::shutdown_runtime;
62use nautilus_system::python::controller::PyController;
63use pyo3::{prelude::*, pyfunction};
64
65#[cfg(feature = "mimalloc")]
66#[global_allocator]
67static GLOBAL: MiMalloc = MiMalloc;
68
69const RUNTIME_SHUTDOWN_TIMEOUT_SECS: u64 = 10;
70
71#[pyfunction]
72fn _shutdown_nautilus_runtime() {
73 shutdown_runtime(Duration::from_secs(RUNTIME_SHUTDOWN_TIMEOUT_SECS));
74}
75
76#[pymodule] fn _libnautilus(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
81 #[cfg(feature = "mimalloc")]
82 nautilus_common::logging::headers::register_allocator_mimalloc();
83
84 let sys = PyModule::import(py, "sys")?;
85 let modules = sys.getattr("modules")?;
86 let sys_modules: &Bound<'_, PyAny> = modules.cast()?;
87
88 let module_name = "nautilus_trader._libnautilus";
89
90 sys_modules.set_item(module_name, m)?;
92
93 let n = "analysis";
95 let submodule = pyo3::wrap_pymodule!(nautilus_analysis::python::analysis);
96 m.add_wrapped(submodule)?;
97 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
98
99 let n = "core";
100 let submodule = pyo3::wrap_pymodule!(nautilus_core::python::core);
101 m.add_wrapped(submodule)?;
102 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
103
104 let n = "common";
105 let submodule = pyo3::wrap_pymodule!(nautilus_common::python::common);
106 m.add_wrapped(submodule)?;
107 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(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
114 let n = "data";
115 let submodule = pyo3::wrap_pymodule!(nautilus_data::python::data);
116 m.add_wrapped(submodule)?;
117 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(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
124 let n = "indicators";
125 let submodule = pyo3::wrap_pymodule!(nautilus_indicators::python::indicators);
126 m.add_wrapped(submodule)?;
127 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
128
129 let n = "infrastructure";
130 let submodule = pyo3::wrap_pymodule!(nautilus_infrastructure::python::infrastructure);
131 m.add_wrapped(submodule)?;
132 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
133
134 let n = "live";
135 let submodule = pyo3::wrap_pymodule!(nautilus_live::python::live);
136 m.add_wrapped(submodule)?;
137 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
138
139 let n = "model";
140 let submodule = pyo3::wrap_pymodule!(nautilus_model::python::model);
141 m.add_wrapped(submodule)?;
142 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
143
144 let n = "network";
145 let submodule = pyo3::wrap_pymodule!(nautilus_network::python::network);
146 m.add_wrapped(submodule)?;
147 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(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
154 let n = "portfolio";
155 let submodule = pyo3::wrap_pymodule!(nautilus_portfolio::python::portfolio);
156 m.add_wrapped(submodule)?;
157 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
158
159 let n = "risk";
160 let submodule = pyo3::wrap_pymodule!(nautilus_risk::python::risk);
161 m.add_wrapped(submodule)?;
162 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
163
164 let n = "serialization";
165 let submodule = pyo3::wrap_pymodule!(nautilus_serialization::python::serialization);
166 m.add_wrapped(submodule)?;
167 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
168
169 let n = "testkit";
170 let submodule = pyo3::wrap_pymodule!(nautilus_testkit::python::testkit);
171 m.add_wrapped(submodule)?;
172 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
173
174 let n = "trading";
175 let submodule = pyo3::wrap_pymodule!(nautilus_trading::python::trading);
176 m.add_wrapped(submodule)?;
177
178 m.getattr(n)?
181 .cast::<PyModule>()?
182 .add_class::<PyController>()?;
183 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
184
185 let n = "backtest";
186 let submodule = pyo3::wrap_pymodule!(nautilus_backtest::python::backtest);
187 m.add_wrapped(submodule)?;
188 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
189
190 let n = "architect_ax";
195 let submodule = pyo3::wrap_pymodule!(nautilus_architect_ax::python::architect_ax);
196 m.add_wrapped(submodule)?;
197 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
198
199 #[cfg(feature = "betfair")]
200 {
201 let n = "betfair";
202 let submodule = pyo3::wrap_pymodule!(nautilus_betfair::python::betfair);
203 m.add_wrapped(submodule)?;
204 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
205 }
206
207 let n = "binance";
208 let submodule = pyo3::wrap_pymodule!(nautilus_binance::python::binance);
209 m.add_wrapped(submodule)?;
210 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
211
212 let n = "bitmex";
213 let submodule = pyo3::wrap_pymodule!(nautilus_bitmex::python::bitmex);
214 m.add_wrapped(submodule)?;
215 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
216
217 let n = "bybit";
218 let submodule = pyo3::wrap_pymodule!(nautilus_bybit::python::bybit);
219 m.add_wrapped(submodule)?;
220 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
221
222 let n = "coinbase";
223 let submodule = pyo3::wrap_pymodule!(nautilus_coinbase::python::coinbase);
224 m.add_wrapped(submodule)?;
225 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
226
227 let n = "databento";
228 let submodule = pyo3::wrap_pymodule!(nautilus_databento::python::databento);
229 m.add_wrapped(submodule)?;
230 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
231
232 let n = "deribit";
233 let submodule = pyo3::wrap_pymodule!(nautilus_deribit::python::deribit);
234 m.add_wrapped(submodule)?;
235 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
236
237 let n = "derive";
238 let submodule = pyo3::wrap_pymodule!(nautilus_derive::python::derive);
239 m.add_wrapped(submodule)?;
240 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(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
247 let n = "hyperliquid";
248 let submodule = pyo3::wrap_pymodule!(nautilus_hyperliquid::python::hyperliquid);
249 m.add_wrapped(submodule)?;
250 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
251
252 let n = "kraken";
253 let submodule = pyo3::wrap_pymodule!(nautilus_kraken::python::kraken);
254 m.add_wrapped(submodule)?;
255 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
256
257 let n = "lighter";
258 let submodule = pyo3::wrap_pymodule!(nautilus_lighter::python::lighter);
259 m.add_wrapped(submodule)?;
260 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
261
262 let n = "interactive_brokers";
263 let submodule = pyo3::wrap_pymodule!(nautilus_interactive_brokers::python::interactive_brokers);
264 m.add_wrapped(submodule)?;
265 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
266
267 let n = "okx";
268 let submodule = pyo3::wrap_pymodule!(nautilus_okx::python::okx);
269 m.add_wrapped(submodule)?;
270 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
271
272 let n = "polymarket";
273 let submodule = pyo3::wrap_pymodule!(nautilus_polymarket::python::polymarket);
274 m.add_wrapped(submodule)?;
275 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
276
277 let n = "sandbox";
278 let submodule = pyo3::wrap_pymodule!(nautilus_sandbox::python::sandbox);
279 m.add_wrapped(submodule)?;
280 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
281
282 let n = "tardis";
283 let submodule = pyo3::wrap_pymodule!(nautilus_tardis::python::tardis);
284 m.add_wrapped(submodule)?;
285 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
286
287 #[cfg(feature = "defi")]
288 {
289 let n = "blockchain";
291 let submodule = pyo3::wrap_pymodule!(nautilus_blockchain::python::blockchain);
292 m.add_wrapped(submodule)?;
293 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
294 }
295
296 m.add_function(pyo3::wrap_pyfunction!(_shutdown_nautilus_runtime, m)?)?;
299 let shutdown_callable = m.getattr("_shutdown_nautilus_runtime")?;
300 let atexit = PyModule::import(py, "atexit")?;
301 atexit.call_method1("register", (shutdown_callable,))?;
302
303 Ok(())
304}
305
306pub fn stub_info() -> pyo3_stub_gen::Result<pyo3_stub_gen::StubInfo> {
324 let workspace_root = Path::new(env!("CARGO_MANIFEST_DIR"))
325 .parent()
326 .unwrap()
327 .parent()
328 .unwrap();
329 let pyproject_path = workspace_root.join("python").join("pyproject.toml");
330
331 pyo3_stub_gen::StubInfo::from_pyproject_toml(&pyproject_path)
332}