Skip to main content

nautilus_backtest/
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//! Results from completed backtest runs.
17
18use ahash::AHashMap;
19use nautilus_core::{UUID4, UnixNanos};
20use serde::Serialize;
21
22/// Results from a completed backtest run.
23#[derive(Debug, Serialize)]
24#[cfg_attr(
25    feature = "python",
26    pyo3::pyclass(
27        module = "nautilus_trader.core.nautilus_pyo3.backtest",
28        skip_from_py_object
29    )
30)]
31#[cfg_attr(
32    feature = "python",
33    pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.backtest")
34)]
35pub struct BacktestResult {
36    pub trader_id: String,
37    pub machine_id: String,
38    pub instance_id: UUID4,
39    pub run_config_id: Option<String>,
40    pub run_id: Option<UUID4>,
41    pub run_started: Option<UnixNanos>,
42    pub run_finished: Option<UnixNanos>,
43    pub backtest_start: Option<UnixNanos>,
44    pub backtest_end: Option<UnixNanos>,
45    pub elapsed_time_secs: f64,
46    pub iterations: usize,
47    pub total_events: usize,
48    pub total_orders: usize,
49    pub total_positions: usize,
50    pub summary: AHashMap<String, String>,
51    pub stats_pnls: AHashMap<String, AHashMap<String, f64>>,
52    pub stats_returns: AHashMap<String, f64>,
53    pub stats_general: AHashMap<String, f64>,
54}
55
56#[cfg(test)]
57mod tests {
58    use ahash::AHashMap;
59    use rstest::rstest;
60    use serde_json::json;
61
62    use super::*;
63
64    #[rstest]
65    fn test_backtest_result_serializes_to_json() {
66        let instance_id = UUID4::from("11111111-1111-4111-8111-111111111111");
67        let run_id = UUID4::from("22222222-2222-4222-8222-222222222222");
68        let mut summary = AHashMap::new();
69        summary.insert("PnL (total)".to_string(), "10.00 USD".to_string());
70        let mut usd_pnls = AHashMap::new();
71        usd_pnls.insert("Returns Volatility (252 days)".to_string(), 1.25);
72        let mut stats_pnls = AHashMap::new();
73        stats_pnls.insert("USD".to_string(), usd_pnls);
74        let mut stats_returns = AHashMap::new();
75        stats_returns.insert("Sharpe Ratio (252 days)".to_string(), 0.75);
76        let mut stats_general = AHashMap::new();
77        stats_general.insert("Long Ratio".to_string(), 1.0);
78
79        let result = BacktestResult {
80            trader_id: "TRADER-001".to_string(),
81            machine_id: "machine-1".to_string(),
82            instance_id,
83            run_config_id: Some("config-1".to_string()),
84            run_id: Some(run_id),
85            run_started: Some(UnixNanos::new(1)),
86            run_finished: Some(UnixNanos::new(2)),
87            backtest_start: Some(UnixNanos::new(3)),
88            backtest_end: Some(UnixNanos::new(4)),
89            elapsed_time_secs: 1.5,
90            iterations: 10,
91            total_events: 20,
92            total_orders: 2,
93            total_positions: 1,
94            summary,
95            stats_pnls,
96            stats_returns,
97            stats_general,
98        };
99
100        let value = serde_json::to_value(&result).unwrap();
101
102        assert_eq!(value["trader_id"], json!("TRADER-001"));
103        assert_eq!(value["machine_id"], json!("machine-1"));
104        assert_eq!(value["instance_id"], json!(instance_id.to_string()));
105        assert_eq!(value["run_id"], json!(run_id.to_string()));
106        assert_eq!(value["run_started"], json!(1));
107        assert_eq!(value["backtest_end"], json!(4));
108        assert_eq!(value["elapsed_time_secs"], json!(1.5));
109        assert_eq!(value["iterations"], json!(10));
110        assert_eq!(value["summary"]["PnL (total)"], json!("10.00 USD"));
111        assert_eq!(
112            value["stats_pnls"]["USD"]["Returns Volatility (252 days)"],
113            json!(1.25)
114        );
115        assert_eq!(
116            value["stats_returns"]["Sharpe Ratio (252 days)"],
117            json!(0.75)
118        );
119        assert_eq!(value["stats_general"]["Long Ratio"], json!(1.0));
120    }
121}