fulid/
simulator.rs

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        // 创建绘图
19        let mut plot = Plot::new();
20
21        // 设置布局
22        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        // 添加每个策略的回测结果
29        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        // 将图表保存为 HTML 文件
36        plot.write_html("output/strategy_performance.html");
37
38        // 打印指标
39        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}