1use crate::strategy_engine::StrategyEngine;
2use plotly::{Scatter, Plot};
3use plotly::layout::Layout;
4
5pub struct Simulator {
6 engine: StrategyEngine,
7}
8
9impl Simulator {
10 pub fn new(engine: StrategyEngine) -> Self {
11 Self { engine }
12 }
13
14 pub fn simulate(&self, prices: Vec<f64>) {
15 let results = self.engine.backtest(prices.clone());
16 let indicators = self.engine.calculate_indicators(prices.clone());
17
18 let mut plot = Plot::new();
20
21 let layout = Layout::new()
23 .title("Strategy Performance")
24 .x_axis(plotly::layout::Axis::new().title("Time"))
25 .y_axis(plotly::layout::Axis::new().title("Return"));
26 plot.set_layout(layout);
27
28 for (i, result) in results.iter().enumerate() {
30 let trace = Scatter::new((0..prices.len()).collect(), vec![*result; prices.len()])
31 .name(&format!("Strategy {}", i + 1));
32 plot.add_trace(trace);
33 }
34
35 plot.write_html("output/strategy_performance.html");
37
38 for (i, indicator) in indicators.iter().enumerate() {
40 println!("Strategy {}: Indicator = {}", i + 1, indicator);
41 }
42 }
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48 use crate::strategy_engine::StrategyEngine;
49 use crate::trend_following::TrendFollowing;
50 use crate::moving_average_cross::MovingAverageCross;
51 use crate::bollinger_bands::BollingerBands;
52 use crate::mean_reversion::MeanReversion;
53 use crate::momentum::Momentum;
54 use crate::arbitrage::Arbitrage;
55
56 #[test]
57 fn test_simulator_with_multiple_strategies() {
58 let mut engine = StrategyEngine::new();
59
60 let mut trend_following = TrendFollowing::new(3, 6);
61 let mut moving_average_cross = MovingAverageCross::new(3, 6);
62 let mut bollinger_bands = BollingerBands::new(10);
63 let mut mean_reversion = MeanReversion::new(5);
64 let mut momentum = Momentum::new(3);
65 let arbitrage = Arbitrage::new();
66
67 engine.add_strategy(Box::new(trend_following.clone()));
68 engine.add_strategy(Box::new(moving_average_cross.clone()));
69 engine.add_strategy(Box::new(bollinger_bands.clone()));
70 engine.add_strategy(Box::new(mean_reversion.clone()));
71 engine.add_strategy(Box::new(momentum.clone()));
72 engine.add_strategy(Box::new(arbitrage.clone()));
73
74 let prices = vec![10.0, 12.0, 15.0, 14.0, 13.0, 12.0];
75
76 for price in &prices {
77 trend_following.update_price(*price);
78 moving_average_cross.update_price(*price);
79 bollinger_bands.update_price(*price);
80 mean_reversion.update_price(*price);
81 momentum.update_price(*price);
82 }
83
84 let simulator = Simulator::new(engine);
85 simulator.simulate(prices.clone());
86 }
87
88 #[test]
89 fn test_simulator_with_empty_strategies() {
90 let engine = StrategyEngine::new();
91 let simulator = Simulator::new(engine);
92
93 let prices = vec![10.0, 12.0, 15.0, 14.0, 13.0, 12.0];
94
95 simulator.simulate(prices);
96 }
97
98 #[test]
99 fn test_simulator_with_single_strategy() {
100 let mut engine = StrategyEngine::new();
101 let mut trend_following = TrendFollowing::new(3, 6);
102
103 engine.add_strategy(Box::new(trend_following.clone()));
104
105 let prices = vec![10.0, 12.0, 15.0, 14.0, 13.0, 12.0];
106
107 for price in &prices {
108 trend_following.update_price(*price);
109 }
110
111 let simulator = Simulator::new(engine);
112 simulator.simulate(prices.clone());
113 }
114}