Skip to main content

nautilus_trading/python/
algorithm.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 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//! Python bindings for execution algorithm configuration.
17
18use std::collections::HashMap;
19
20use nautilus_core::python::to_pyvalue_err;
21use pyo3::{prelude::*, types::PyDict};
22
23use crate::algorithm::ImportableExecAlgorithmConfig;
24
25#[pyo3::pymethods]
26#[pyo3_stub_gen::derive::gen_stub_pymethods]
27impl ImportableExecAlgorithmConfig {
28    /// Configuration for creating execution algorithms from importable paths.
29    #[new]
30    #[allow(clippy::needless_pass_by_value)]
31    fn py_new(
32        exec_algorithm_path: String,
33        config_path: String,
34        config: Py<PyDict>,
35    ) -> PyResult<Self> {
36        let json_config = Python::attach(|py| -> PyResult<HashMap<String, serde_json::Value>> {
37            let kwargs = PyDict::new(py);
38            kwargs.set_item("default", py.eval(pyo3::ffi::c_str!("str"), None, None)?)?;
39            let json_str: String = PyModule::import(py, "json")?
40                .call_method("dumps", (config.bind(py),), Some(&kwargs))?
41                .extract()?;
42
43            let json_value: serde_json::Value =
44                serde_json::from_str(&json_str).map_err(to_pyvalue_err)?;
45
46            if let serde_json::Value::Object(map) = json_value {
47                Ok(map.into_iter().collect())
48            } else {
49                Err(to_pyvalue_err("Config must be a dictionary"))
50            }
51        })?;
52
53        Ok(Self {
54            exec_algorithm_path,
55            config_path,
56            config: json_config,
57        })
58    }
59
60    #[getter]
61    fn exec_algorithm_path(&self) -> &String {
62        &self.exec_algorithm_path
63    }
64
65    #[getter]
66    fn config_path(&self) -> &String {
67        &self.config_path
68    }
69
70    #[getter]
71    fn config(&self, py: Python<'_>) -> PyResult<Py<PyDict>> {
72        let py_dict = PyDict::new(py);
73        for (key, value) in &self.config {
74            let json_str = serde_json::to_string(value).map_err(to_pyvalue_err)?;
75            let py_value = PyModule::import(py, "json")?.call_method("loads", (json_str,), None)?;
76            py_dict.set_item(key, py_value)?;
77        }
78        Ok(py_dict.unbind())
79    }
80}