"""Drawdown monitoring and equity curve tracking.""" from __future__ import annotations from dataclasses import dataclass, field from typing import List from loguru import logger @dataclass class DrawdownState: """Current drawdown statistics.""" current_drawdown: float = 0.0 max_drawdown: float = 0.0 peak_equity: float = 0.0 trough_equity: float = 0.0 is_in_drawdown: bool = False class DrawdownMonitor: """Track equity curve and compute drawdown metrics.""" def __init__(self, max_drawdown_limit: float = 0.15): self.limit = max_drawdown_limit self._equity_curve: List[float] = [] self._peak: float = 0.0 self._max_dd: float = 0.0 def update(self, equity: float) -> DrawdownState: """Record new equity point and recalculate drawdown.""" self._equity_curve.append(equity) if equity > self._peak: self._peak = equity current_dd = (self._peak - equity) / self._peak if self._peak > 0 else 0.0 if current_dd > self._max_dd: self._max_dd = current_dd state = DrawdownState( current_drawdown=current_dd, max_drawdown=self._max_dd, peak_equity=self._peak, trough_equity=min(self._equity_curve) if self._equity_curve else 0.0, is_in_drawdown=current_dd > 0, ) if current_dd >= self.limit: logger.warning( "DRAWDOWN ALERT: {:.2%} >= limit {:.2%}", current_dd, self.limit ) return state @property def equity_curve(self) -> List[float]: return list(self._equity_curve) @property def max_drawdown(self) -> float: return self._max_dd def is_breached(self) -> bool: """Return True if max drawdown limit has been exceeded.""" return self._max_dd >= self.limit