nautilus_backtest/
result.rs1use ahash::AHashMap;
19use nautilus_core::{UUID4, UnixNanos};
20use serde::Serialize;
21
22#[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}