from PyQt6.QtWidgets import ( QMainWindow, QDockWidget, QStatusBar, QMessageBox, QWidget ) from PyQt6.QtCore import Qt from src.ui.control_panel import ControlPanel from src.ui.chart_widget import ChartWidget from src.core.data_worker import DataWorker class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Python Trading Terminal (MT5 + Gap-Filled Profile)") self.resize(1200, 800) self.init_ui() self.worker = None def init_ui(self): # Status Bar self.status_bar = QStatusBar() self.setStatusBar(self.status_bar) # Dock: Control Panel self.dock_controls = QDockWidget("Controls", self) self.control_panel = ControlPanel() self.dock_controls.setWidget(self.control_panel) self.dock_controls.setAllowedAreas(Qt.DockWidgetArea.LeftDockWidgetArea | Qt.DockWidgetArea.RightDockWidgetArea) self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.dock_controls) # Central: Chart self.chart_widget = ChartWidget() self.setCentralWidget(self.chart_widget) # Connections self.control_panel.start_signal.connect(self.start_worker) self.control_panel.stop_signal.connect(self.stop_worker) def start_worker(self, symbol, date, multiplier): if self.worker is not None and self.worker.isRunning(): return self.chart_widget.clear() self.chart_widget.price_plot.setTitle(f"{symbol} - {date} (Multiplier: {multiplier}x)") self.worker = DataWorker(symbol, date, multiplier=multiplier) self.worker.status_signal.connect(self.status_bar.showMessage) self.worker.data_signal.connect(self.handle_data) self.worker.levels_signal.connect(self.handle_levels) self.worker.finished.connect(self.on_worker_finished) self.worker.start() def stop_worker(self): if self.worker: self.worker.stop() self.worker = None self.status_bar.showMessage("Stream stopped.") def handle_data(self, ticks_df, profile_counts): # Update Chart with new ticks # Note: ChartWidget.update_ticks expects a dataframe. # If we just append, we might need to handle state inside chart widget better. # But simpler: pass the full set or update logic. # For performance, we should probably append. # In current ChartWidget, update_ticks SETS data. # DataWorker emits chunks (new_ticks) during loop, but FULL history at start. # We need to distinguish or accumulate in ChartWidget? # Actually, DataWorker emits distinct chunks in the loop. # But ChartWidget `setData` replaces content. # We need to accumulate data in ChartWidget or pass accumulated data from Worker. # Passing Full DF every 500ms with millions of rows is bad. # Better: ChartWidget accumulates. # Actually, let's just make ChartWidget append. # Or better: Worker sends everything? No. # Let's Modify ChartWidget to accumulate. # WAIT: My ChartWidget implementation `update_ticks` does: `self.bid_curve.setData(t_float, bids)` # This REPLACES. # I need to fix ChartWidget to handle incremental updates or large data better. # For now, let's just pass the full accumulated history from Worker? # Worker doesn't store accumulated history openly, it just emits `ticks_df` (chunk). # We need a way to append. # Let's fix ChartWidget in next step. For now assume it appends. self.chart_widget.update_ticks(ticks_df) self.chart_widget.update_profile(profile_counts) # Full profile is cheap (dict) def handle_levels(self, times, vah, val, poc): self.chart_widget.update_levels(times, vah, val, poc) def on_worker_finished(self): self.control_panel.on_stop() self.worker = None self.status_bar.showMessage("Ready.")