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// -------------------------------------------------------------------------------------------------
1516//! [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 [nautilus_trader](https://pypi.org/project/nautilus_trader) Python package,
26//! or as part of a Rust only build.
27//!
28//! - `ffi`: Enables the C foreign function interface (FFI) from [cbindgen](https://github.com/mozilla/cbindgen).
29//! - `high-precision`: Enables [high-precision mode](https://nautilustrader.io/docs/nightly/getting_started/installation#precision-mode) to use 128-bit value types.
3031#![warn(rustc::all)]
32#![deny(unsafe_code)]
33#![deny(nonstandard_style)]
34#![deny(rustdoc::broken_intra_doc_links)]
35#![deny(clippy::missing_errors_doc)]
3637use pyo3::prelude::*;
3839/// We modify sys modules so that submodule can be loaded directly as
40/// import supermodule.submodule
41///
42/// Also re-exports all submodule attributes so they can be imported directly from `nautilus_pyo3`
43/// refer: https://github.com/PyO3/pyo3/issues/2644
44#[pymodule]
45fn nautilus_pyo3(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
46let sys = PyModule::import(py, "sys")?;
47let modules = sys.getattr("modules")?;
48let sys_modules: &Bound<'_, PyAny> = modules.downcast()?;
49let module_name = "nautilus_trader.core.nautilus_pyo3";
5051// Set pyo3_nautilus to be recognized as a subpackage
52sys_modules.set_item(module_name, m)?;
5354let n = "core";
55let submodule = pyo3::wrap_pymodule!(nautilus_core::python::core);
56 m.add_wrapped(submodule)?;
57 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
58 re_export_module_attributes(m, n)?;
5960let n = "common";
61let submodule = pyo3::wrap_pymodule!(nautilus_common::python::common);
62 m.add_wrapped(submodule)?;
63 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
64 re_export_module_attributes(m, n)?;
6566let n = "cryptography";
67let submodule = pyo3::wrap_pymodule!(nautilus_cryptography::python::cryptography);
68 m.add_wrapped(submodule)?;
69 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
70 re_export_module_attributes(m, n)?;
7172let n = "execution";
73let submodule = pyo3::wrap_pymodule!(nautilus_execution::python::execution);
74 m.add_wrapped(submodule)?;
75 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
76 re_export_module_attributes(m, n)?;
7778let n = "model";
79let submodule = pyo3::wrap_pymodule!(nautilus_model::python::model);
80 m.add_wrapped(submodule)?;
81 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
82 re_export_module_attributes(m, n)?;
8384let n = "indicators";
85let submodule = pyo3::wrap_pymodule!(nautilus_indicators::python::indicators);
86 m.add_wrapped(submodule)?;
87 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
88 re_export_module_attributes(m, n)?;
8990let n = "infrastructure";
91let submodule = pyo3::wrap_pymodule!(nautilus_infrastructure::python::infrastructure);
92 m.add_wrapped(submodule)?;
93 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
94 re_export_module_attributes(m, n)?;
9596let n = "network";
97let submodule = pyo3::wrap_pymodule!(nautilus_network::python::network);
98 m.add_wrapped(submodule)?;
99 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
100 re_export_module_attributes(m, n)?;
101102let n = "persistence";
103let submodule = pyo3::wrap_pymodule!(nautilus_persistence::python::persistence);
104 m.add_wrapped(submodule)?;
105 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
106 re_export_module_attributes(m, n)?;
107108let n = "serialization";
109let submodule = pyo3::wrap_pymodule!(nautilus_serialization::python::serialization);
110 m.add_wrapped(submodule)?;
111 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
112 re_export_module_attributes(m, n)?;
113114let n = "testkit";
115let submodule = pyo3::wrap_pymodule!(nautilus_testkit::python::testkit);
116 m.add_wrapped(submodule)?;
117 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
118 re_export_module_attributes(m, n)?;
119120let n = "trading";
121let submodule = pyo3::wrap_pymodule!(nautilus_trading::python::trading);
122 m.add_wrapped(submodule)?;
123 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
124 re_export_module_attributes(m, n)?;
125126// Adapters
127128let n = "coinbase_intx";
129let submodule = pyo3::wrap_pymodule!(nautilus_coinbase_intx::python::coinbase_intx);
130 m.add_wrapped(submodule)?;
131 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
132 re_export_module_attributes(m, n)?;
133134let n = "databento";
135let submodule = pyo3::wrap_pymodule!(nautilus_databento::python::databento);
136 m.add_wrapped(submodule)?;
137 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
138 re_export_module_attributes(m, n)?;
139140let n = "tardis";
141let submodule = pyo3::wrap_pymodule!(nautilus_tardis::python::tardis);
142 m.add_wrapped(submodule)?;
143 sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
144 re_export_module_attributes(m, n)?;
145146Ok(())
147}
148149fn re_export_module_attributes(
150 parent_module: &Bound<'_, PyModule>,
151 submodule_name: &str,
152) -> PyResult<()> {
153let submodule = parent_module.getattr(submodule_name)?;
154for item_name in submodule.dir()? {
155let item_name_str: &str = item_name.extract()?;
156if let Ok(attr) = submodule.getattr(item_name_str) {
157 parent_module.add(item_name_str, attr)?;
158 }
159 }
160161Ok(())
162}