nautilus_pyo3/
lib.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! [NautilusTrader](http://nautilustrader.io) is an open-source, high-performance, production-grade
17//! algorithmic trading platform, providing quantitative traders with the ability to backtest
18//! portfolios of automated trading strategies on historical data with an event-driven engine,
19//! and also deploy those same strategies live, with no code changes.
20//!
21//! # Feature flags
22//!
23//! This crate provides feature flags to control source code inclusion during compilation,
24//! depending on the intended use case, i.e. whether to provide Python bindings
25//! for the main `nautilus_trader` Python package, or as part of a Rust only build.
26//!
27//! - `ffi`: Enables the C foreign function interface (FFI) from `cbindgen`.
28
29#![warn(rustc::all)]
30#![deny(unsafe_code)]
31#![deny(nonstandard_style)]
32#![deny(rustdoc::broken_intra_doc_links)]
33#![deny(clippy::missing_errors_doc)]
34
35use pyo3::prelude::*;
36
37/// We modify sys modules so that submodule can be loaded directly as
38/// import supermodule.submodule
39///
40/// Also re-exports all submodule attributes so they can be imported directly from `nautilus_pyo3`
41/// refer: https://github.com/PyO3/pyo3/issues/2644
42#[pymodule]
43fn nautilus_pyo3(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
44    let sys = PyModule::import(py, "sys")?;
45    let modules = sys.getattr("modules")?;
46    let sys_modules: &Bound<'_, PyAny> = modules.downcast()?;
47    let module_name = "nautilus_trader.core.nautilus_pyo3";
48
49    // Set pyo3_nautilus to be recognized as a subpackage
50    sys_modules.set_item(module_name, m)?;
51
52    let n = "core";
53    let submodule = pyo3::wrap_pymodule!(nautilus_core::python::core);
54    m.add_wrapped(submodule)?;
55    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
56    re_export_module_attributes(m, n)?;
57
58    let n = "common";
59    let submodule = pyo3::wrap_pymodule!(nautilus_common::python::common);
60    m.add_wrapped(submodule)?;
61    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
62    re_export_module_attributes(m, n)?;
63
64    let n = "cryptography";
65    let submodule = pyo3::wrap_pymodule!(nautilus_cryptography::python::cryptography);
66    m.add_wrapped(submodule)?;
67    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
68    re_export_module_attributes(m, n)?;
69
70    let n = "execution";
71    let submodule = pyo3::wrap_pymodule!(nautilus_execution::python::execution);
72    m.add_wrapped(submodule)?;
73    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
74    re_export_module_attributes(m, n)?;
75
76    let n = "model";
77    let submodule = pyo3::wrap_pymodule!(nautilus_model::python::model);
78    m.add_wrapped(submodule)?;
79    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
80    re_export_module_attributes(m, n)?;
81
82    let n = "indicators";
83    let submodule = pyo3::wrap_pymodule!(nautilus_indicators::python::indicators);
84    m.add_wrapped(submodule)?;
85    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
86    re_export_module_attributes(m, n)?;
87
88    let n = "infrastructure";
89    let submodule = pyo3::wrap_pymodule!(nautilus_infrastructure::python::infrastructure);
90    m.add_wrapped(submodule)?;
91    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
92    re_export_module_attributes(m, n)?;
93
94    let n = "network";
95    let submodule = pyo3::wrap_pymodule!(nautilus_network::python::network);
96    m.add_wrapped(submodule)?;
97    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
98    re_export_module_attributes(m, n)?;
99
100    let n = "persistence";
101    let submodule = pyo3::wrap_pymodule!(nautilus_persistence::python::persistence);
102    m.add_wrapped(submodule)?;
103    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
104    re_export_module_attributes(m, n)?;
105
106    let n = "serialization";
107    let submodule = pyo3::wrap_pymodule!(nautilus_serialization::python::serialization);
108    m.add_wrapped(submodule)?;
109    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
110    re_export_module_attributes(m, n)?;
111
112    let n = "test_kit";
113    let submodule = pyo3::wrap_pymodule!(nautilus_test_kit::python::test_kit);
114    m.add_wrapped(submodule)?;
115    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
116    re_export_module_attributes(m, n)?;
117
118    let n = "databento";
119    let submodule = pyo3::wrap_pymodule!(nautilus_databento::python::databento);
120    m.add_wrapped(submodule)?;
121    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
122    re_export_module_attributes(m, n)?;
123
124    let n = "tardis";
125    let submodule = pyo3::wrap_pymodule!(nautilus_tardis::python::tardis);
126    m.add_wrapped(submodule)?;
127    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
128    re_export_module_attributes(m, n)?;
129
130    let n = "trading";
131    let submodule = pyo3::wrap_pymodule!(nautilus_trading::python::trading);
132    m.add_wrapped(submodule)?;
133    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
134    re_export_module_attributes(m, n)?;
135
136    Ok(())
137}
138
139fn re_export_module_attributes(
140    parent_module: &Bound<'_, PyModule>,
141    submodule_name: &str,
142) -> PyResult<()> {
143    let submodule = parent_module.getattr(submodule_name)?;
144    for item_name in submodule.dir()? {
145        let item_name_str: &str = item_name.extract()?;
146        if let Ok(attr) = submodule.getattr(item_name_str) {
147            parent_module.add(item_name_str, attr)?;
148        }
149    }
150
151    Ok(())
152}