Source code for wraquant.risk.portfolio
"""Portfolio-level risk analytics."""
from __future__ import annotations
import numpy as np
[docs]
def portfolio_volatility(
weights: np.ndarray,
cov_matrix: np.ndarray,
) -> float:
"""Compute portfolio volatility from weights and covariance matrix.
Parameters:
weights: Asset weight vector (n,).
cov_matrix: Covariance matrix (n, n).
Returns:
Portfolio volatility (standard deviation).
"""
from wraquant.core._coerce import coerce_array
weights = coerce_array(weights, name="weights")
cov_matrix = np.asarray(cov_matrix, dtype=np.float64)
return float(np.sqrt(weights @ cov_matrix @ weights))
[docs]
def risk_contribution(
weights: np.ndarray,
cov_matrix: np.ndarray,
) -> np.ndarray:
"""Compute each asset's risk contribution to portfolio volatility.
Parameters:
weights: Asset weight vector (n,).
cov_matrix: Covariance matrix (n, n).
Returns:
Array of fractional risk contributions that sum to 1.
"""
from wraquant.core._coerce import coerce_array
weights = coerce_array(weights, name="weights")
cov_matrix = np.asarray(cov_matrix, dtype=np.float64)
port_vol = portfolio_volatility(weights, cov_matrix)
if port_vol == 0:
return np.zeros_like(weights)
marginal = cov_matrix @ weights / port_vol
rc = weights * marginal
return rc / rc.sum()
[docs]
def diversification_ratio(
weights: np.ndarray,
cov_matrix: np.ndarray,
) -> float:
"""Compute the diversification ratio.
The diversification ratio is the ratio of the weighted average of
individual volatilities to the portfolio volatility. A value of 1
means no diversification benefit.
Parameters:
weights: Asset weight vector (n,).
cov_matrix: Covariance matrix (n, n).
Returns:
Diversification ratio (>= 1).
"""
from wraquant.core._coerce import coerce_array
weights = coerce_array(weights, name="weights")
cov_matrix = np.asarray(cov_matrix, dtype=np.float64)
individual_vols = np.sqrt(np.diag(cov_matrix))
weighted_avg_vol = float(weights @ individual_vols)
port_vol = portfolio_volatility(weights, cov_matrix)
if port_vol == 0:
return 1.0
return weighted_avg_vol / port_vol