File size: 5,523 Bytes
59da845
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
use eframe::egui;
use rfd::FileDialog;
use std::path::PathBuf;
use crate::engine::backtester::BacktestConfig;

pub struct BacktestPanel {
    pub initial_deposit_str: String,
    pub leverage_str: String,
    pub spread_modifier_str: String,
    pub selected_symbols: Vec<String>,
    pub new_symbol_input: String,
    pub loaded_mql5_path: Option<PathBuf>,
    pub compiler_log: String,
    pub is_running: bool,
}

impl BacktestPanel {
    pub fn new() -> Self {
        Self {
            initial_deposit_str: "10000.0".to_string(),
            leverage_str: "100.0".to_string(),
            spread_modifier_str: "0".to_string(),
            selected_symbols: vec!["EURUSD".to_string()],
            new_symbol_input: "".to_string(),
            loaded_mql5_path: None,
            compiler_log: "Ready.".to_string(),
            is_running: false,
        }
    }

    pub fn draw(&mut self, ui: &mut egui::Ui) -> Option<BacktestConfig> {
        ui.heading("⚙️ Backtest Configuration");
        ui.separator();

        // Account Settings
        ui.group(|ui| {
            ui.label("Account Settings");
            egui::Grid::new("config_grid").num_columns(2).spacing([10.0, 5.0]).show(ui, |ui| {
                ui.label("Initial Deposit ($):");
                ui.text_edit_singleline(&mut self.initial_deposit_str);
                ui.end_row();

                ui.label("Leverage (1:X):");
                ui.text_edit_singleline(&mut self.leverage_str);
                ui.end_row();

                ui.label("Spread Modifier (points):");
                ui.text_edit_singleline(&mut self.spread_modifier_str);
                ui.end_row();
            });
        });

        ui.add_space(10.0);

        // Symbol Selection
        ui.group(|ui| {
            ui.label("Symbols for Backtest");
            ui.horizontal(|ui| {
                ui.text_edit_singleline(&mut self.new_symbol_input);
                if ui.button("Add").clicked() {
                    if !self.new_symbol_input.is_empty() && !self.selected_symbols.contains(&self.new_symbol_input) {
                        self.selected_symbols.push(self.new_symbol_input.clone());
                        self.new_symbol_input.clear();
                    }
                }
            });
            
            ui.horizontal_wrapped(|ui| {
                let mut to_remove = None;
                for (i, sym) in self.selected_symbols.iter().enumerate() {
                    ui.group(|ui| {
                        ui.horizontal(|ui| {
                            ui.label(sym);
                            if ui.small_button("x").clicked() {
                                to_remove = Some(i);
                            }
                        });
                    });
                }
                if let Some(i) = to_remove {
                    self.selected_symbols.remove(i);
                }
            });
        });

        ui.add_space(10.0);

        // MQL5 File Loading
        ui.group(|ui| {
            ui.label("MQL5 Strategy Code");
            ui.horizontal(|ui| {
                if ui.button("📂 Load .mq5 File").clicked() {
                    if let Some(path) = FileDialog::new()
                        .add_filter("MQL5 Source", &["mq5"])
                        .pick_file() 
                    {
                        self.loaded_mql5_path = Some(path);
                        self.compiler_log = "File loaded. Ready to compile.".to_string();
                    }
                }
                if let Some(p) = &self.loaded_mql5_path {
                    ui.label(p.display().to_string());
                } else {
                    ui.label("No file selected.");
                }
            });
        });

        ui.add_space(10.0);

        // Start button
        ui.horizontal(|ui| {
            if self.is_running {
                ui.add_enabled(false, egui::Button::new("Running Backtest..."));
            } else {
                if ui.button("🚀 Compile & Run Backtest").clicked() {
                    if self.loaded_mql5_path.is_none() {
                        self.compiler_log = "Error: Please load an .mq5 file first.".to_string();
                        return None;
                    }
                    if self.selected_symbols.is_empty() {
                        self.compiler_log = "Error: Please add at least one symbol.".to_string();
                        return None;
                    }

                    if let (Ok(dep), Ok(lev), Ok(spr)) = (
                        self.initial_deposit_str.parse::<f64>(),
                        self.leverage_str.parse::<f64>(),
                        self.spread_modifier_str.parse::<u32>(),
                    ) {
                        self.compiler_log = "Starting compilation...".to_string();
                        self.is_running = true;
                        
                        return Some(BacktestConfig {
                            initial_deposit: dep,
                            leverage: lev,
                            spread_modifier: spr,
                        });
                    } else {
                        self.compiler_log = "Error: Invalid numeric configuration fields.".to_string();
                    }
                }
            }
        });

        ui.add_space(5.0);
        
        // Logs
        ui.group(|ui| {
            ui.set_min_height(60.0);
            ui.label(&self.compiler_log);
        });

        None
    }
}