"""Periodic scheduler for VaR and PnL snapshots.""" from __future__ import annotations import logging import threading from datetime import datetime, timedelta logger = logging.getLogger(__name__) _var_thread: threading.Thread | None = None _pnl_thread: threading.Thread | None = None _var_stop = threading.Event() _pnl_stop = threading.Event() def _var_loop(stop: threading.Event): while not stop.wait(0): from .database import get_config try: enabled = (get_config("var_scheduler_enabled") or "false").lower() == "true" hours = float(get_config("var_scheduler_hours") or "6") except Exception: enabled, hours = False, 6.0 if not enabled: stop.wait(timeout=300) continue # Run snapshot try: from .var_service import compute_var, save_var_snapshot result = compute_var() if "error" not in result: save_var_snapshot(result, confidence=0.95, horizon_days=1, lookback_days=252, default_iv=0.20) logger.info("[VaR Scheduler] Snapshot saved") else: logger.warning(f"[VaR Scheduler] Compute failed: {result['error']}") except Exception as e: logger.error(f"[VaR Scheduler] Exception: {e}") stop.wait(timeout=hours * 3600) def _pnl_loop(stop: threading.Event): while not stop.wait(0): from .database import get_config try: enabled = (get_config("pnl_scheduler_enabled") or "false").lower() == "true" hours = float(get_config("pnl_scheduler_hours") or "1") except Exception: enabled, hours = False, 1.0 if not enabled: stop.wait(timeout=120) continue try: from .var_service import save_pnl_snapshot save_pnl_snapshot() logger.info("[PnL Scheduler] Snapshot saved") except Exception as e: logger.error(f"[PnL Scheduler] Exception: {e}") stop.wait(timeout=hours * 3600) def start_var_scheduler(): global _var_thread, _var_stop _var_stop.clear() if _var_thread and _var_thread.is_alive(): return _var_thread = threading.Thread(target=_var_loop, args=(_var_stop,), name="var-scheduler", daemon=True) _var_thread.start() logger.info("[VaR Scheduler] Started") def start_pnl_scheduler(): global _pnl_thread, _pnl_stop _pnl_stop.clear() if _pnl_thread and _pnl_thread.is_alive(): return _pnl_thread = threading.Thread(target=_pnl_loop, args=(_pnl_stop,), name="pnl-scheduler", daemon=True) _pnl_thread.start() logger.info("[PnL Scheduler] Started") def stop_var_scheduler(): _var_stop.set() def stop_pnl_scheduler(): _pnl_stop.set() def restart_var_scheduler(): stop_var_scheduler() import time; time.sleep(0.2) start_var_scheduler() def restart_pnl_scheduler(): stop_pnl_scheduler() import time; time.sleep(0.2) start_pnl_scheduler() def get_scheduler_status() -> dict: from .database import get_config return { "var": { "enabled": (get_config("var_scheduler_enabled") or "false").lower() == "true", "hours": float(get_config("var_scheduler_hours") or "6"), "alive": bool(_var_thread and _var_thread.is_alive()), }, "pnl": { "enabled": (get_config("pnl_scheduler_enabled") or "false").lower() == "true", "hours": float(get_config("pnl_scheduler_hours") or "1"), "alive": bool(_pnl_thread and _pnl_thread.is_alive()), }, }