mirror of
https://github.com/Sabermrddz/QuantCore-FX.git
synced 2026-08-15 11:48:05 +00:00
v1 first layer
This commit is contained in:
+208
@@ -0,0 +1,208 @@
|
||||
"""
|
||||
APEX Layer 1 — Main Application Window
|
||||
|
||||
Assembles all 4 tabs:
|
||||
- Tab 1: Dashboard (main signal + ranking table)
|
||||
- Tab 2: Monthly Entry (CPI + PMI input form)
|
||||
- Tab 3: History (past signals)
|
||||
- Tab 4: Settings (configuration)
|
||||
|
||||
Responsibilities:
|
||||
- Create QMainWindow with QTabWidget
|
||||
- Instantiate all UI tabs
|
||||
- Manage database connection
|
||||
- Run FRED API fetch in background thread (QThread)
|
||||
- Connect inter-tab signals (e.g., entry tab saves → dashboard tab refreshes)
|
||||
- Handle window events and cleanup
|
||||
"""
|
||||
|
||||
from PyQt5.QtWidgets import QMainWindow, QTabWidget, QVBoxLayout, QWidget, QMessageBox
|
||||
from PyQt5.QtCore import Qt, QThread, pyqtSignal
|
||||
from PyQt5.QtGui import QFont
|
||||
from typing import Dict, Optional
|
||||
import config
|
||||
from database import Database
|
||||
from fred_client import FredClient
|
||||
from ui.dashboard_tab import DashboardTab
|
||||
from ui.entry_tab import MonthlyEntryTab
|
||||
from ui.history_tab import HistoryTab
|
||||
from ui.settings_tab import SettingsTab
|
||||
|
||||
|
||||
class FredFetchWorker(QThread):
|
||||
"""Background worker thread for fetching rates from FRED API."""
|
||||
|
||||
# Signals
|
||||
rates_fetched = pyqtSignal(dict) # Emitted with {currency: rate} dict
|
||||
error_occurred = pyqtSignal(str) # Emitted on error
|
||||
|
||||
def __init__(self, db: Database):
|
||||
"""
|
||||
Initialize FRED fetch worker.
|
||||
|
||||
Args:
|
||||
db: Database instance to save rates
|
||||
"""
|
||||
super().__init__()
|
||||
self.db = db
|
||||
self.client = FredClient()
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Fetch rates from FRED API and save to database.
|
||||
"""
|
||||
try:
|
||||
if config.DEBUG:
|
||||
print("[Worker] Starting FRED rate fetch...")
|
||||
|
||||
rates = self.client.fetch_all_rates()
|
||||
|
||||
# Save to database
|
||||
for currency, rate in rates.items():
|
||||
if rate is not None:
|
||||
self.db.upsert_rate(currency, rate, source="FRED")
|
||||
|
||||
if config.DEBUG:
|
||||
print("[Worker] FRED fetch complete")
|
||||
|
||||
self.rates_fetched.emit(rates)
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"FRED fetch error: {str(e)}"
|
||||
if config.DEBUG:
|
||||
print(f"[Worker] {error_msg}")
|
||||
self.error_occurred.emit(error_msg)
|
||||
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
"""Main application window."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize main window."""
|
||||
super().__init__()
|
||||
|
||||
# Initialize database
|
||||
try:
|
||||
self.db = Database()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(
|
||||
self,
|
||||
"Database Error",
|
||||
f"Failed to initialize database: {e}\n\nPlease check your configuration."
|
||||
)
|
||||
raise
|
||||
|
||||
# UI components
|
||||
self.dashboard_tab = None
|
||||
self.entry_tab = None
|
||||
self.history_tab = None
|
||||
self.settings_tab = None
|
||||
|
||||
# Worker thread
|
||||
self.fred_worker = None
|
||||
|
||||
self._init_ui()
|
||||
self._connect_signals()
|
||||
self._setup_auto_fetch()
|
||||
|
||||
def _init_ui(self):
|
||||
"""Build the main window UI."""
|
||||
self.setWindowTitle(config.APP_TITLE)
|
||||
self.setGeometry(100, 100, config.WINDOW_WIDTH, config.WINDOW_HEIGHT)
|
||||
|
||||
# Tab widget
|
||||
tabs = QTabWidget()
|
||||
|
||||
# Tab 1: Dashboard
|
||||
self.dashboard_tab = DashboardTab(self.db)
|
||||
tabs.addTab(self.dashboard_tab, config.TAB_NAMES["dashboard"])
|
||||
|
||||
# Tab 2: Monthly Entry
|
||||
self.entry_tab = MonthlyEntryTab(self.db)
|
||||
tabs.addTab(self.entry_tab, config.TAB_NAMES["entry"])
|
||||
|
||||
# Tab 3: History
|
||||
self.history_tab = HistoryTab(self.db)
|
||||
tabs.addTab(self.history_tab, config.TAB_NAMES["history"])
|
||||
|
||||
# Tab 4: Settings
|
||||
self.settings_tab = SettingsTab()
|
||||
tabs.addTab(self.settings_tab, config.TAB_NAMES["settings"])
|
||||
|
||||
# Set main widget
|
||||
self.setCentralWidget(tabs)
|
||||
|
||||
# Style tabs
|
||||
tab_font = QFont("Arial", 11)
|
||||
tabs.setFont(tab_font)
|
||||
|
||||
def _connect_signals(self):
|
||||
"""Connect inter-tab signals."""
|
||||
# Entry tab saves data → Dashboard tab refreshes
|
||||
self.entry_tab.data_saved.connect(self.dashboard_tab.on_data_saved)
|
||||
|
||||
# Entry tab saves data → History tab refreshes
|
||||
self.entry_tab.data_saved.connect(self.history_tab.refresh_history)
|
||||
|
||||
# Dashboard requests FRED fetch → Start worker thread
|
||||
self.dashboard_tab.fetch_rates_requested.connect(self._fetch_rates)
|
||||
|
||||
def _setup_auto_fetch(self):
|
||||
"""Auto-fetch rates on startup if enabled."""
|
||||
if config.AUTO_FETCH_RATES_ON_STARTUP:
|
||||
if config.DEBUG:
|
||||
print("[Main] Auto-fetch enabled, fetching rates on startup...")
|
||||
self._fetch_rates()
|
||||
|
||||
def _fetch_rates(self):
|
||||
"""
|
||||
Trigger background FRED rate fetch.
|
||||
Emits results to dashboard when complete.
|
||||
"""
|
||||
if self.fred_worker is not None and self.fred_worker.isRunning():
|
||||
# Already fetching
|
||||
return
|
||||
|
||||
self.fred_worker = FredFetchWorker(self.db)
|
||||
self.fred_worker.rates_fetched.connect(self._on_rates_fetched)
|
||||
self.fred_worker.error_occurred.connect(self._on_fetch_error)
|
||||
self.fred_worker.start()
|
||||
|
||||
def _on_rates_fetched(self, rates: Dict[str, Optional[float]]):
|
||||
"""
|
||||
Handle successful FRED fetch.
|
||||
|
||||
Args:
|
||||
rates: Dict mapping currency to rate
|
||||
"""
|
||||
if config.DEBUG:
|
||||
print("[Main] Rates fetched successfully, updating dashboard...")
|
||||
|
||||
# Update dashboard display
|
||||
self.dashboard_tab.on_rates_updated(rates)
|
||||
|
||||
def _on_fetch_error(self, error_msg: str):
|
||||
"""
|
||||
Handle FRED fetch error.
|
||||
|
||||
Args:
|
||||
error_msg: Error message string
|
||||
"""
|
||||
print(f"[ERROR] {error_msg}")
|
||||
# Don't show error message to user; display gracefully in dashboard
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""Handle window close event."""
|
||||
try:
|
||||
# Stop any running threads
|
||||
if self.fred_worker is not None and self.fred_worker.isRunning():
|
||||
self.fred_worker.quit()
|
||||
self.fred_worker.wait()
|
||||
|
||||
# Close database
|
||||
self.db.close()
|
||||
|
||||
event.accept()
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Error during shutdown: {e}")
|
||||
event.accept()
|
||||
Reference in New Issue
Block a user