Skip to content

Commit 72d9ded

Browse files
committed
fix: guard max_drawdown and per-asset risk against empty DataFrames
1 parent 13e34c2 commit 72d9ded

1 file changed

Lines changed: 7 additions & 1 deletion

File tree

backend/app/services/risk_metrics.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ def sharpe_ratio(returns: pd.Series, risk_free: float = RISK_FREE_RATE) -> float
2626

2727

2828
def max_drawdown(prices: pd.Series) -> float:
29+
if prices is None or len(prices) == 0:
30+
return 0.0
2931
cumulative = prices / prices.iloc[0]
3032
running_max = cumulative.cummax()
3133
drawdown = (cumulative - running_max) / running_max
@@ -47,6 +49,9 @@ def compute_per_asset_risk(processed: Dict[str, pd.DataFrame]) -> Dict[str, Dict
4749
"""Risk metrics for each symbol."""
4850
metrics: Dict[str, Dict[str, float]] = {}
4951
for symbol, df in processed.items():
52+
if df.empty or len(df) == 0 or "daily_return" not in df.columns:
53+
metrics[symbol] = {"volatility": 0.0, "sharpe_ratio": 0.0, "max_drawdown": 0.0}
54+
continue
5055
returns = df["daily_return"].dropna()
5156
metrics[symbol] = {
5257
"volatility": round(annualized_volatility(returns), 4),
@@ -58,8 +63,9 @@ def compute_per_asset_risk(processed: Dict[str, pd.DataFrame]) -> Dict[str, Dict
5863

5964
def correlation_matrix(processed: Dict[str, pd.DataFrame]) -> Dict[str, Dict[str, float]]:
6065
"""Pairwise return correlations across assets."""
66+
cleaned = {s: df for s, df in processed.items() if not df.empty and len(df) > 0}
6167
returns_df = pd.DataFrame(
62-
{symbol: df.set_index("date")["daily_return"] for symbol, df in processed.items()}
68+
{symbol: df.set_index("date")["daily_return"] for symbol, df in cleaned.items()}
6369
).dropna()
6470

6571
if returns_df.empty or returns_df.shape[1] < 2:

0 commit comments

Comments
 (0)