# risk-metrics-calculation > Calculate portfolio risk metrics including VaR, CVaR, Sharpe, Sortino, and drawdown analysis for gold futures. - Author: aqibhassan - Repository: aqibhassan/gold-trading-bot - Version: 20260209222550 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-09 - Source: https://github.com/aqibhassan/gold-trading-bot - Web: https://mule.run/skillshub/@@aqibhassan/gold-trading-bot~risk-metrics-calculation:20260209222550 --- --- name: risk-metrics-calculation description: Calculate portfolio risk metrics including VaR, CVaR, Sharpe, Sortino, and drawdown analysis for gold futures. --- # Risk Metrics Calculation ## When to Use Apply when measuring portfolio risk, implementing risk limits, calculating performance metrics, or building risk dashboards for gold futures. ## Core Risk Metrics ### Value at Risk (VaR) ```python from scipy.stats import norm def parametric_var(returns: pd.Series, confidence: float = 0.99) -> Decimal: """Parametric VaR assuming normal distribution.""" mu = returns.mean() sigma = returns.std() return Decimal(str(abs(norm.ppf(1 - confidence, mu, sigma)))) def historical_var(returns: pd.Series, confidence: float = 0.99) -> Decimal: """Historical simulation VaR — no distribution assumption.""" return Decimal(str(abs(np.percentile(returns, (1 - confidence) * 100)))) ``` ### Conditional VaR (CVaR / Expected Shortfall) ```python def cvar(returns: pd.Series, confidence: float = 0.99) -> Decimal: """Average loss beyond VaR threshold.""" var = historical_var(returns, confidence) tail_losses = returns[returns <= -float(var)] return Decimal(str(abs(tail_losses.mean()))) ``` ### Sharpe Ratio ```python def sharpe_ratio(returns: pd.Series, risk_free_rate: float = 0.0, annualization: int = 365) -> float: excess = returns - risk_free_rate / annualization return float(excess.mean() / excess.std() * np.sqrt(annualization)) ``` ### Sortino Ratio ```python def sortino_ratio(returns: pd.Series, risk_free_rate: float = 0.0, annualization: int = 365) -> float: excess = returns - risk_free_rate / annualization downside = excess[excess < 0].std() return float(excess.mean() / downside * np.sqrt(annualization)) ``` ### Maximum Drawdown ```python def max_drawdown(equity_curve: pd.Series) -> tuple[Decimal, int]: """Returns (max_dd_pct, duration_in_bars).""" peak = equity_curve.expanding(min_periods=1).max() drawdown = (equity_curve - peak) / peak max_dd = drawdown.min() # Duration: bars from peak to recovery return Decimal(str(abs(max_dd))), compute_dd_duration(drawdown) ``` ### Calmar Ratio ```python def calmar_ratio(returns: pd.Series, equity: pd.Series) -> float: ann_return = returns.mean() * 365 mdd = float(max_drawdown(equity)[0]) return ann_return / mdd if mdd > 0 else float('inf') ``` ## Gold-Specific Risk Thresholds | Metric | Target | Hard Limit | |--------|--------|------------| | Daily VaR (99%) | < 1.5% | 2.0% | | CVaR (99%) | < 2.0% | 3.0% | | Sharpe Ratio | > 2.0 | > 1.0 minimum | | Sortino Ratio | > 3.0 | > 1.5 minimum | | Max Drawdown | < 5% | 10% circuit breaker | | Calmar Ratio | > 3.0 | > 1.0 minimum | | Win Rate | > 55% | > 45% minimum | | Profit Factor | > 1.5 | > 1.1 minimum | ## Implementation Notes - All monetary calculations use `Decimal` — never float - Compute metrics on rolling windows (30d, 90d, all-time) - Store daily metrics in ClickHouse for historical analysis - Publish real-time metrics to Grafana dashboard - Alert when any metric breaches "Hard Limit" threshold