Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import numpy as np
- from scipy.stats import skew, kurtosis, anderson, shapiro
- def compute_risk_metrics(portfolio_returns, portfolio_beta, rf_rate=0.0):
- """
- Compute various risk metrics for the portfolio.
- Note, that it works for RF and CPI Adjusted returns.
- """
- mean_return = portfolio_returns.mean() * 12
- std_dev = portfolio_returns.std(ddof=1) * np.sqrt(12)
- downside_returns = portfolio_returns[portfolio_returns < rf_rate]
- downside_dev = downside_returns.std(ddof=1) * np.sqrt(12)
- cumulative = (1 + portfolio_returns).cumprod()
- running_max = np.maximum.accumulate(cumulative)
- drawdowns = (cumulative - running_max) / running_max
- max_drawdown = drawdowns.min()
- cumulative_return = cumulative.iloc[-1] - 1
- calmar_ratio = mean_return / abs(max_drawdown) if max_drawdown != 0 else np.nan
- VaR_95 = np.percentile(portfolio_returns, 5)
- CVaR_95 = portfolio_returns[portfolio_returns <= VaR_95].mean()
- omega_ratio = (portfolio_returns[portfolio_returns > rf_rate].sum() /
- abs(portfolio_returns[portfolio_returns < rf_rate].sum()))
- anderson_stat = anderson(portfolio_returns).statistic
- shapiro_stat, shapiro_p = shapiro(portfolio_returns)
- neg_deviation = abs(portfolio_returns[portfolio_returns < rf_rate] - rf_rate)
- sasr = mean_return / neg_deviation.mean() if not neg_deviation.empty else np.nan
- mad = np.mean(np.abs(portfolio_returns - portfolio_returns.mean()))
- iqr = np.percentile(portfolio_returns, 75) - np.percentile(portfolio_returns, 25)
- ulcer_index = np.sqrt(np.mean(drawdowns[drawdowns < 0] ** 2))
- sorted_drawdowns = drawdowns.sort_values()
- threshold_index = int(0.05 * len(sorted_drawdowns))
- cdar_5 = sorted_drawdowns[:threshold_index].mean() if threshold_index > 0 else np.nan
- pain_ratio = mean_return / abs(drawdowns.mean()) if drawdowns.mean() != 0 else np.nan
- return {
- 'Annual Return': mean_return,
- 'Annual Volatility': std_dev,
- 'Sharpe Ratio': mean_return / std_dev,
- 'Sortino Ratio': mean_return / downside_dev if downside_dev != 0 else np.nan,
- 'Treynor Ratio': mean_return / portfolio_beta if portfolio_beta != 0 else np.nan,
- 'Calmar Ratio': calmar_ratio,
- 'Max Drawdown': max_drawdown,
- 'VaR 95%': VaR_95,
- 'CVaR 95%': CVaR_95,
- 'Downside Deviation': downside_dev,
- 'Omega Ratio': omega_ratio,
- 'Skewness': skew(portfolio_returns),
- 'Kurtosis': kurtosis(portfolio_returns),
- 'Anderson-Darling Stat': anderson_stat,
- 'Shapiro-Wilk Stat': shapiro_stat,
- 'Shapiro-Wilk p': shapiro_p,
- 'SASR': sasr,
- 'MAD': mad,
- 'IQR': iqr,
- 'Ulcer Index': ulcer_index,
- 'CDaR (5%)': cdar_5,
- 'Pain Ratio': pain_ratio,
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement