Skip to main content

nautilus_backtest/python/
result.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 the [`BacktestResult`] type.
17
18use std::collections::{BTreeMap, HashMap};
19
20use nautilus_core::UUID4;
21
22use crate::result::BacktestResult;
23
24#[pyo3_stub_gen::derive::gen_stub_pymethods]
25#[pyo3::pymethods]
26impl BacktestResult {
27    #[getter]
28    #[pyo3(name = "trader_id")]
29    fn py_trader_id(&self) -> &str {
30        &self.trader_id
31    }
32
33    #[getter]
34    #[pyo3(name = "machine_id")]
35    fn py_machine_id(&self) -> &str {
36        &self.machine_id
37    }
38
39    #[getter]
40    #[pyo3(name = "instance_id")]
41    const fn py_instance_id(&self) -> UUID4 {
42        self.instance_id
43    }
44
45    #[getter]
46    #[pyo3(name = "run_config_id")]
47    fn py_run_config_id(&self) -> Option<&str> {
48        self.run_config_id.as_deref()
49    }
50
51    #[getter]
52    #[pyo3(name = "run_id")]
53    const fn py_run_id(&self) -> Option<UUID4> {
54        self.run_id
55    }
56
57    #[getter]
58    #[pyo3(name = "run_started")]
59    fn py_run_started(&self) -> Option<u64> {
60        self.run_started.map(|timestamp| timestamp.as_u64())
61    }
62
63    #[getter]
64    #[pyo3(name = "run_finished")]
65    fn py_run_finished(&self) -> Option<u64> {
66        self.run_finished.map(|timestamp| timestamp.as_u64())
67    }
68
69    #[getter]
70    #[pyo3(name = "backtest_start")]
71    fn py_backtest_start(&self) -> Option<u64> {
72        self.backtest_start.map(|timestamp| timestamp.as_u64())
73    }
74
75    #[getter]
76    #[pyo3(name = "backtest_end")]
77    fn py_backtest_end(&self) -> Option<u64> {
78        self.backtest_end.map(|timestamp| timestamp.as_u64())
79    }
80
81    #[getter]
82    #[pyo3(name = "elapsed_time_secs")]
83    const fn py_elapsed_time_secs(&self) -> f64 {
84        self.elapsed_time_secs
85    }
86
87    #[getter]
88    #[pyo3(name = "iterations")]
89    const fn py_iterations(&self) -> usize {
90        self.iterations
91    }
92
93    #[getter]
94    #[pyo3(name = "total_events")]
95    const fn py_total_events(&self) -> usize {
96        self.total_events
97    }
98
99    #[getter]
100    #[pyo3(name = "total_orders")]
101    const fn py_total_orders(&self) -> usize {
102        self.total_orders
103    }
104
105    #[getter]
106    #[pyo3(name = "total_positions")]
107    const fn py_total_positions(&self) -> usize {
108        self.total_positions
109    }
110
111    #[getter]
112    #[pyo3(name = "summary")]
113    fn py_summary(&self) -> HashMap<String, String> {
114        self.summary
115            .iter()
116            .map(|(key, value)| (key.clone(), value.clone()))
117            .collect()
118    }
119
120    #[getter]
121    #[pyo3(name = "stats_pnls")]
122    fn py_stats_pnls(&self) -> HashMap<String, HashMap<String, f64>> {
123        self.stats_pnls
124            .iter()
125            .map(|(k, v)| {
126                (
127                    k.clone(),
128                    v.iter().map(|(k2, v2)| (k2.clone(), *v2)).collect(),
129                )
130            })
131            .collect()
132    }
133
134    #[getter]
135    #[pyo3(name = "stats_returns")]
136    fn py_stats_returns(&self) -> HashMap<String, f64> {
137        self.stats_returns
138            .iter()
139            .map(|(k, v)| (k.clone(), *v))
140            .collect()
141    }
142
143    #[getter]
144    #[pyo3(name = "stats_general")]
145    fn py_stats_general(&self) -> HashMap<String, f64> {
146        self.stats_general
147            .iter()
148            .map(|(k, v)| (k.clone(), *v))
149            .collect()
150    }
151
152    #[getter]
153    #[pyo3(name = "returns_series")]
154    fn py_returns_series(&self) -> BTreeMap<u64, f64> {
155        self.returns_series
156            .iter()
157            .map(|(timestamp, value)| (timestamp.as_u64(), *value))
158            .collect()
159    }
160
161    fn __repr__(&self) -> String {
162        format!(
163            "BacktestResult(trader_id='{}', elapsed={:.2}s, iterations={}, orders={}, positions={})",
164            self.trader_id,
165            self.elapsed_time_secs,
166            self.iterations,
167            self.total_orders,
168            self.total_positions,
169        )
170    }
171}