1#![warn(rustc::all)]
45#![deny(unsafe_code)]
46#![deny(unsafe_op_in_unsafe_fn)]
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
55#[cfg(feature = "mimalloc")]
56use mimalloc::MiMalloc;
57use nautilus_common::live::runtime::shutdown_runtime;
58use nautilus_system::{config::StreamingConfig, python::controller::PyController};
59use pyo3::{prelude::*, pyfunction};
60
61#[cfg(feature = "mimalloc")]
62#[global_allocator]
63static GLOBAL: MiMalloc = MiMalloc;
64
65const RUNTIME_SHUTDOWN_TIMEOUT_SECS: u64 = 10;
66
67#[pyfunction]
68fn _shutdown_nautilus_runtime() {
69 shutdown_runtime(Duration::from_secs(RUNTIME_SHUTDOWN_TIMEOUT_SECS));
70}
71
72#[pymodule] fn _libnautilus(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
77 #[cfg(feature = "mimalloc")]
78 nautilus_common::logging::headers::register_allocator_mimalloc();
79
80 let sys = PyModule::import(py, "sys")?;
81 let modules = sys.getattr("modules")?;
82 let sys_modules: &Bound<'_, PyAny> = modules.cast()?;
83
84 let module_name = "nautilus_trader._libnautilus";
85
86 sys_modules.set_item(module_name, m)?;
88
89 let n = "analysis";
91 let submodule = pyo3::wrap_pymodule!(nautilus_analysis::python::analysis);
92 m.add_wrapped(submodule)?;
93 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(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
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
105 let n = "cryptography";
106 let submodule = pyo3::wrap_pymodule!(nautilus_cryptography::python::cryptography);
107 m.add_wrapped(submodule)?;
108 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
109
110 let n = "data";
111 let submodule = pyo3::wrap_pymodule!(nautilus_data::python::data);
112 m.add_wrapped(submodule)?;
113 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
114
115 let n = "execution";
116 let submodule = pyo3::wrap_pymodule!(nautilus_execution::python::execution);
117 m.add_wrapped(submodule)?;
118 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
119
120 let n = "indicators";
121 let submodule = pyo3::wrap_pymodule!(nautilus_indicators::python::indicators);
122 m.add_wrapped(submodule)?;
123 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
124
125 let n = "infrastructure";
126 let submodule = pyo3::wrap_pymodule!(nautilus_infrastructure::python::infrastructure);
127 m.add_wrapped(submodule)?;
128 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
129
130 let n = "live";
131 let submodule = pyo3::wrap_pymodule!(nautilus_live::python::live);
132 m.add_wrapped(submodule)?;
133 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(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
140 let n = "network";
141 let submodule = pyo3::wrap_pymodule!(nautilus_network::python::network);
142 m.add_wrapped(submodule)?;
143 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
144
145 let n = "persistence";
146 let submodule = pyo3::wrap_pymodule!(nautilus_persistence::python::persistence);
147 m.add_wrapped(submodule)?;
148 m.getattr(n)?
149 .cast::<PyModule>()?
150 .add_class::<StreamingConfig>()?;
151 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
152
153 let n = "portfolio";
154 let submodule = pyo3::wrap_pymodule!(nautilus_portfolio::python::portfolio);
155 m.add_wrapped(submodule)?;
156 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
157
158 let n = "risk";
159 let submodule = pyo3::wrap_pymodule!(nautilus_risk::python::risk);
160 m.add_wrapped(submodule)?;
161 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
162
163 let n = "serialization";
164 let submodule = pyo3::wrap_pymodule!(nautilus_serialization::python::serialization);
165 m.add_wrapped(submodule)?;
166 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
167
168 let n = "testkit";
169 let submodule = pyo3::wrap_pymodule!(nautilus_testkit::python::testkit);
170 m.add_wrapped(submodule)?;
171 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
172
173 let n = "trading";
174 let submodule = pyo3::wrap_pymodule!(nautilus_trading::python::trading);
175 m.add_wrapped(submodule)?;
176
177 m.getattr(n)?
180 .cast::<PyModule>()?
181 .add_class::<PyController>()?;
182 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
183
184 let n = "backtest";
185 let submodule = pyo3::wrap_pymodule!(nautilus_backtest::python::backtest);
186 m.add_wrapped(submodule)?;
187 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
188
189 let n = "architect_ax";
194 let submodule = pyo3::wrap_pymodule!(nautilus_architect_ax::python::architect_ax);
195 m.add_wrapped(submodule)?;
196 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
197
198 #[cfg(feature = "betfair")]
199 {
200 let n = "betfair";
201 let submodule = pyo3::wrap_pymodule!(nautilus_betfair::python::betfair);
202 m.add_wrapped(submodule)?;
203 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
204 }
205
206 let n = "binance";
207 let submodule = pyo3::wrap_pymodule!(nautilus_binance::python::binance);
208 m.add_wrapped(submodule)?;
209 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
210
211 let n = "bitmex";
212 let submodule = pyo3::wrap_pymodule!(nautilus_bitmex::python::bitmex);
213 m.add_wrapped(submodule)?;
214 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
215
216 let n = "bybit";
217 let submodule = pyo3::wrap_pymodule!(nautilus_bybit::python::bybit);
218 m.add_wrapped(submodule)?;
219 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
220
221 let n = "coinbase";
222 let submodule = pyo3::wrap_pymodule!(nautilus_coinbase::python::coinbase);
223 m.add_wrapped(submodule)?;
224 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
225
226 let n = "databento";
227 let submodule = pyo3::wrap_pymodule!(nautilus_databento::python::databento);
228 m.add_wrapped(submodule)?;
229 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
230
231 let n = "deribit";
232 let submodule = pyo3::wrap_pymodule!(nautilus_deribit::python::deribit);
233 m.add_wrapped(submodule)?;
234 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
235
236 let n = "derive";
237 let submodule = pyo3::wrap_pymodule!(nautilus_derive::python::derive);
238 m.add_wrapped(submodule)?;
239 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
240
241 let n = "dydx";
242 let submodule = pyo3::wrap_pymodule!(nautilus_dydx::python::dydx);
243 m.add_wrapped(submodule)?;
244 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
245
246 let n = "hyperliquid";
247 let submodule = pyo3::wrap_pymodule!(nautilus_hyperliquid::python::hyperliquid);
248 m.add_wrapped(submodule)?;
249 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
250
251 let n = "kraken";
252 let submodule = pyo3::wrap_pymodule!(nautilus_kraken::python::kraken);
253 m.add_wrapped(submodule)?;
254 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
255
256 let n = "lighter";
257 let submodule = pyo3::wrap_pymodule!(nautilus_lighter::python::lighter);
258 m.add_wrapped(submodule)?;
259 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
260
261 let n = "interactive_brokers";
262 let submodule = pyo3::wrap_pymodule!(nautilus_interactive_brokers::python::interactive_brokers);
263 m.add_wrapped(submodule)?;
264 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
265
266 let n = "okx";
267 let submodule = pyo3::wrap_pymodule!(nautilus_okx::python::okx);
268 m.add_wrapped(submodule)?;
269 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
270
271 let n = "polymarket";
272 let submodule = pyo3::wrap_pymodule!(nautilus_polymarket::python::polymarket);
273 m.add_wrapped(submodule)?;
274 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
275
276 let n = "sandbox";
277 let submodule = pyo3::wrap_pymodule!(nautilus_sandbox::python::sandbox);
278 m.add_wrapped(submodule)?;
279 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
280
281 let n = "tardis";
282 let submodule = pyo3::wrap_pymodule!(nautilus_tardis::python::tardis);
283 m.add_wrapped(submodule)?;
284 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
285
286 #[cfg(feature = "defi")]
287 {
288 let n = "blockchain";
290 let submodule = pyo3::wrap_pymodule!(nautilus_blockchain::python::blockchain);
291 m.add_wrapped(submodule)?;
292 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(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
305pub fn stub_info() -> pyo3_stub_gen::Result<pyo3_stub_gen::StubInfo> {
323 let workspace_root = Path::new(env!("CARGO_MANIFEST_DIR"))
324 .parent()
325 .unwrap()
326 .parent()
327 .unwrap();
328 let pyproject_path = workspace_root.join("python").join("pyproject.toml");
329
330 pyo3_stub_gen::StubInfo::from_pyproject_toml(&pyproject_path)
331}