import sys import asyncio from PySide6.QtWidgets import QApplication, QMainWindow, QLabel, QWidget, QVBoxLayout, QTabWidget from PySide6.QtCore import Qt, QTimer, QThread, Signal from .dashboard import DashboardPanel from .strategy_panel import StrategyPanel from .positions_panel import PositionsPanel from .orders_panel import OrdersPanel from .logs_panel import LogsPanel class AsyncWorker(QThread): def __init__(self, loop: asyncio.AbstractEventLoop, target_coro, kwargs): super().__init__() self.loop = loop self.target_coro = target_coro self.kwargs = kwargs def run(self): asyncio.set_event_loop(self.loop) self.loop.run_until_complete(self.target_coro(**self.kwargs)) self.loop.close() class MainWindow(QMainWindow): def __init__( self, broker, data_feed, db_session, order_manager, risk_manager, strategy_engine, settings, backend_runner, app_logger, portfolio ): super().__init__() self.broker = broker self.data_feed = data_feed self.db_session = db_session self.order_manager = order_manager self.risk_manager = risk_manager self.strategy_engine = strategy_engine self.settings = settings self.backend_runner = backend_runner self.app_logger = app_logger # Store the app_logger instance self.portfolio = portfolio self.setWindowTitle("Algo Trader") self.setGeometry(100, 100, 1600, 900) # Create main tab widget self.tabs = QTabWidget() self.tabs.setTabPosition(QTabWidget.North) # Create panels self.dashboard_panel = DashboardPanel() self.strategy_panel = StrategyPanel() self.positions_panel = PositionsPanel() self.orders_panel = OrdersPanel() self.logs_panel = LogsPanel() # Add panels to tabs self.tabs.addTab(self.dashboard_panel, "Dashboard") self.tabs.addTab(self.strategy_panel, "Strategies") self.tabs.addTab(self.positions_panel, "Positions") self.tabs.addTab(self.orders_panel, "Orders") self.tabs.addTab(self.logs_panel, "Logs") self.setCentralWidget(self.tabs) # Connect logger signal to logs panel self.app_logger.log_signal.connect(self.logs_panel.append_log) # Connect data_feed signals to dashboard and logger self.data_feed.signals.connected.connect(lambda: self.app_logger.info("DataFeed: Connected")) self.data_feed.signals.disconnected.connect(lambda: self.app_logger.warning("DataFeed: Disconnected")) self.data_feed.signals.error.connect(lambda msg: self.app_logger.error(f"DataFeed Error: {msg}")) self.data_feed.signals.tick.connect(self.dashboard_panel.update_market_data) # Connect order_manager signals to orders panel self.order_manager.signals.order_updated.connect(self.orders_panel.add_or_update_order) # Connect portfolio signals to positions panel self.portfolio.signals.position_updated.connect(self.positions_panel.add_or_update_position) self.portfolio.signals.portfolio_value_updated.connect(lambda value: self.app_logger.info(f"Portfolio Value Updated: {value}")) # Connect strategy_engine signals to strategy_panel and logger self.strategy_engine.signals.strategy_loaded.connect(self.strategy_panel.update_status) self.strategy_engine.signals.strategy_started.connect(lambda name: self.strategy_panel.update_status(f"Running: {name}")) self.strategy_engine.signals.strategy_stopped.connect(lambda name: self.strategy_panel.update_status(f"Stopped: {name}")) self.strategy_engine.signals.trade_signal.connect(lambda signal: self.app_logger.info(f"Trade Signal: {signal}")) # Connect strategy_panel UI signals to strategy_engine methods self.strategy_panel.strategy_selected.connect(self.strategy_engine.load_strategy) self.strategy_panel.start_strategy_requested.connect(self.strategy_engine.start_strategy) self.strategy_panel.stop_strategy_requested.connect(self.strategy_engine.stop_strategy) # --- Asyncio Integration --- self.loop = asyncio.get_event_loop() if self.loop.is_running(): self.loop = asyncio.new_event_loop() self.backend_worker = AsyncWorker( loop=self.loop, target_coro=self.backend_runner, kwargs={ "broker": self.broker, "data_feed": self.data_feed, "db_session": self.db_session, "order_manager": self.order_manager, "risk_manager": self.risk_manager, "strategy_engine": self.strategy_engine, "settings": self.settings, "portfolio": self.portfolio, }, ) self.backend_worker.start() def closeEvent(self, event): if self.data_feed: asyncio.run_coroutine_threadsafe(self.data_feed.close(), self.loop) if self.db_session: self.db_session.close() self.loop.call_soon_threadsafe(self.loop.stop) self.backend_worker.wait() # Wait for the backend thread to finish super().closeEvent(event)