Files
crypto_news/risk/drawdown_monitor.py
2026-03-20 07:49:42 +09:00

68 lines
1.8 KiB
Python

"""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