Portfolio Optimization and Quantitative Strategic Asset Allocation in Python
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive collection of 45+ risk measures and portfolio analysis functions including dispersion measures, downside risk measures, drawdown measures, range measures, and performance metrics for quantitative portfolio risk analysis.
Risk measures based on the distribution of returns around the mean.
def MAD(X):
"""
Mean Absolute Deviation.
Parameters:
- X (DataFrame): Returns data
Returns:
float: MAD risk measure
"""
def SemiDeviation(X, MAR=0):
"""
Semi-standard deviation (downside deviation).
Parameters:
- X (DataFrame): Returns data
- MAR (float): Minimum acceptable return
Returns:
float: Semi-deviation
"""
def Kurtosis(X):
"""
Square root of kurtosis.
Parameters:
- X (DataFrame): Returns data
Returns:
float: Square root of kurtosis
"""
def SemiKurtosis(X, MAR=0):
"""
Square root of semi-kurtosis.
Parameters:
- X (DataFrame): Returns data
- MAR (float): Minimum acceptable return
Returns:
float: Square root of semi-kurtosis
"""
def GMD(X):
"""
Gini Mean Difference.
Parameters:
- X (DataFrame): Returns data
Returns:
float: Gini Mean Difference
"""Risk measures focusing on negative returns and tail risks.
def VaR_Hist(X, alpha=0.05):
"""
Historical Value at Risk.
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level
Returns:
float: Value at Risk
"""
def CVaR_Hist(X, alpha=0.05):
"""
Historical Conditional Value at Risk (Expected Shortfall).
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level
Returns:
float: Conditional Value at Risk
"""
def WR(X):
"""
Worst Realization (minimum return).
Parameters:
- X (DataFrame): Returns data
Returns:
float: Worst realization
"""
def LPM(X, MAR=0, p=1):
"""
Lower Partial Moment.
Parameters:
- X (DataFrame): Returns data
- MAR (float): Minimum acceptable return
- p (float): Moment order
Returns:
float: Lower partial moment
"""
def Entropic_RM(X, z=1, alpha=0.05):
"""
Entropic Risk Measure.
Parameters:
- X (DataFrame): Returns data
- z (float): Entropic parameter
- alpha (float): Significance level
Returns:
float: Entropic risk measure
"""
def EVaR_Hist(X, alpha=0.05, solver="CLARABEL"):
"""
Entropic Value at Risk.
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level
- solver (str): Optimization solver (default: "CLARABEL")
Returns:
float: Entropic Value at Risk
"""
def RLVaR_Hist(X, alpha=0.05, kappa=0.30, solver="CLARABEL"):
"""
Relativistic Value at Risk.
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level
- kappa (float): Deformation parameter
- solver (str): Optimization solver (default: "CLARABEL")
Returns:
float: Relativistic Value at Risk
"""Risk measures based on peak-to-trough declines in portfolio value.
def MDD_Abs(X):
"""
Maximum Drawdown (absolute).
Parameters:
- X (DataFrame): Returns data
Returns:
float: Maximum drawdown
"""
def ADD_Abs(X):
"""
Average Drawdown (absolute).
Parameters:
- X (DataFrame): Returns data
Returns:
float: Average drawdown
"""
def DaR_Abs(X, alpha=0.05):
"""
Drawdown at Risk (absolute).
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level
Returns:
float: Drawdown at Risk
"""
def CDaR_Abs(X, alpha=0.05):
"""
Conditional Drawdown at Risk (absolute).
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level
Returns:
float: Conditional Drawdown at Risk
"""
def EDaR_Abs(X, alpha=0.05):
"""
Entropic Drawdown at Risk (absolute).
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level
Returns:
float: Entropic Drawdown at Risk
"""
def RLDaR_Abs(X, alpha=0.05, kappa=0.30):
"""
Relativistic Drawdown at Risk (absolute).
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level
- kappa (float): Deformation parameter
Returns:
float: Relativistic Drawdown at Risk
"""
def UCI_Abs(X):
"""
Ulcer Index (absolute).
Parameters:
- X (DataFrame): Returns data
Returns:
float: Ulcer Index
"""
# Relative Drawdown Functions
def MDD_Rel(X):
"""
Maximum Drawdown (relative/compounded).
Parameters:
- X (DataFrame): Returns data
Returns:
float: Relative maximum drawdown
"""
def ADD_Rel(X):
"""
Average Drawdown (relative/compounded).
Parameters:
- X (DataFrame): Returns data
Returns:
float: Relative average drawdown
"""
def DaR_Rel(X, alpha=0.05):
"""
Drawdown at Risk (relative/compounded).
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level
Returns:
float: Relative Drawdown at Risk
"""
def CDaR_Rel(X, alpha=0.05):
"""
Conditional Drawdown at Risk (relative/compounded).
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level
Returns:
float: Relative Conditional Drawdown at Risk
"""
def EDaR_Rel(X, alpha=0.05, solver="CLARABEL"):
"""
Entropic Drawdown at Risk (relative/compounded).
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level
- solver (str): Optimization solver
Returns:
float: Relative Entropic Drawdown at Risk
"""
def RLDaR_Rel(X, alpha=0.05, kappa=0.30, solver="CLARABEL"):
"""
Relativistic Drawdown at Risk (relative/compounded).
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level
- kappa (float): Deformation parameter
- solver (str): Optimization solver
Returns:
float: Relative Relativistic Drawdown at Risk
"""
def UCI_Rel(X):
"""
Ulcer Index (relative/compounded).
Parameters:
- X (DataFrame): Returns data
Returns:
float: Relative Ulcer Index
"""
# Additional Missing Functions
def VRG(X, alpha=0.05, beta=0.05):
"""
VaR Range (VaR of gains - VaR of losses).
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level for losses
- beta (float): Significance level for gains
Returns:
float: VaR Range
"""Risk measures based on the range and spread of returns distribution.
def TG(X, alpha=0.05):
"""
Tail Gini coefficient.
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level
Returns:
float: Tail Gini
"""
def RG(X):
"""
Range (max - min).
Parameters:
- X (DataFrame): Returns data
Returns:
float: Range
"""
def CVRG(X, alpha=0.05, beta=0.05):
"""
CVaR Range (CVaR of gains - CVaR of losses).
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level for losses
- beta (float): Significance level for gains
Returns:
float: CVaR Range
"""
def TGRG(X, alpha=0.05, a_sim=100):
"""
Tail Gini Range.
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level
- a_sim (int): Number of simulations
Returns:
float: Tail Gini Range
"""
def EVRG(X, alpha=0.05, beta=0.05):
"""
Entropic Value at Risk Range.
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level for losses
- beta (float): Significance level for gains
Returns:
float: Entropic VaR Range
"""
def RVRG(X, alpha=0.05, beta=0.05, kappa=0.30):
"""
Relativistic Value at Risk Range.
Parameters:
- X (DataFrame): Returns data
- alpha (float): Significance level for losses
- beta (float): Significance level for gains
- kappa (float): Deformation parameter
Returns:
float: Relativistic VaR Range
"""Functions for portfolio performance analysis and risk decomposition.
def Sharpe(X, rf=0):
"""
Sharpe ratio.
Parameters:
- X (DataFrame): Returns data
- rf (float): Risk-free rate
Returns:
float: Sharpe ratio
"""
def Sharpe_Risk(X, rm='MV', rf=0, alpha=0.05):
"""
Sharpe ratio with custom risk measure.
Parameters:
- X (DataFrame): Returns data
- rm (str): Risk measure code
- rf (float): Risk-free rate
- alpha (float): Significance level
Returns:
float: Risk-adjusted Sharpe ratio
"""
def Risk_Contribution(w, cov, rm='MV', alpha=0.05):
"""
Risk contribution analysis.
Parameters:
- w (DataFrame): Portfolio weights
- cov (DataFrame): Covariance matrix
- rm (str): Risk measure
- alpha (float): Significance level
Returns:
DataFrame: Risk contributions by asset
"""
def Risk_Margin(w, cov, alpha=0.05):
"""
Risk margin calculation.
Parameters:
- w (DataFrame): Portfolio weights
- cov (DataFrame): Covariance matrix
- alpha (float): Significance level
Returns:
DataFrame: Risk margins
"""
def Factors_Risk_Contribution(w, cov, B, rm='MV'):
"""
Factor risk contribution analysis.
Parameters:
- w (DataFrame): Portfolio weights
- cov (DataFrame): Factor covariance matrix
- B (DataFrame): Factor loadings
- rm (str): Risk measure
Returns:
DataFrame: Factor risk contributions
"""
def BrinsonAttribution(Ra, Rb, Wa, Wb):
"""
Brinson performance attribution analysis.
Parameters:
- Ra (DataFrame): Portfolio returns
- Rb (DataFrame): Benchmark returns
- Wa (DataFrame): Portfolio weights
- Wb (DataFrame): Benchmark weights
Returns:
DataFrame: Attribution analysis results
"""
def NEA(w):
"""
Number of Effective Assets.
Parameters:
- w (DataFrame): Portfolio weights
Returns:
float: Number of effective assets
"""
def L_Moment(X, k=4):
"""
L-moments calculation.
Parameters:
- X (DataFrame): Returns data
- k (int): Number of L-moments
Returns:
DataFrame: L-moments
"""
def L_Moment_CRM(X, w, k=4):
"""
L-moment coherent risk measure.
Parameters:
- X (DataFrame): Returns data
- w (DataFrame): L-moment weights
- k (int): Number of L-moments
Returns:
float: L-moment risk measure
"""import riskfolio as rp
import pandas as pd
import numpy as np
# Load returns data
returns = pd.read_csv('returns.csv', index_col=0, parse_dates=True)
# Calculate various risk measures
portfolio_returns = returns.mean(axis=1) # Equal-weighted portfolio
# Dispersion measures
mad_risk = rp.MAD(portfolio_returns)
semi_dev = rp.SemiDeviation(portfolio_returns, MAR=0)
gmd_risk = rp.GMD(portfolio_returns)
# Downside measures
var_95 = rp.VaR_Hist(portfolio_returns, alpha=0.05)
cvar_95 = rp.CVaR_Hist(portfolio_returns, alpha=0.05)
worst_return = rp.WR(portfolio_returns)
# Drawdown measures
max_dd = rp.MDD_Abs(portfolio_returns)
avg_dd = rp.ADD_Abs(portfolio_returns)
cdar_95 = rp.CDaR_Abs(portfolio_returns, alpha=0.05)
# Performance measures
sharpe_ratio = rp.Sharpe(portfolio_returns, rf=0.02)
sharpe_cvar = rp.Sharpe_Risk(portfolio_returns, rm='CVaR', rf=0.02)
print(f"MAD: {mad_risk:.4f}")
print(f"VaR (95%): {var_95:.4f}")
print(f"CVaR (95%): {cvar_95:.4f}")
print(f"Max Drawdown: {max_dd:.4f}")
print(f"Sharpe Ratio: {sharpe_ratio:.4f}")
# Portfolio risk contribution analysis
port = rp.Portfolio(returns=returns)
port.assets_stats()
w = port.optimization(obj='Sharpe', rm='CVaR')
# Calculate risk contributions
risk_contrib = rp.Risk_Contribution(w, port.cov, rm='CVaR')
print("\nRisk Contributions:")
print(risk_contrib.sort_values('Risk', ascending=False).head())# Available risk measures
rmeasures = [
"MV", # Mean Variance (Standard Deviation)
"KT", # Square Root Kurtosis
"MAD", # Mean Absolute Deviation
"GMD", # Gini Mean Difference
"MSV", # Mean Square Variation
"SKT", # Square Root Semi-Kurtosis
"FLPM", # First Lower Partial Moment
"SLPM", # Second Lower Partial Moment
"CVaR", # Conditional Value at Risk
"TG", # Tail Gini
"EVaR", # Entropic Value at Risk
"RLVaR", # Relativistic Value at Risk
"WR", # Worst Realization
"CVRG", # CVaR Range
"TGRG", # Tail Gini Range
"EVRG", # Entropic VaR Range
"RVRG", # Relativistic VaR Range
"RG", # Range
"MDD", # Maximum Drawdown
"ADD", # Average Drawdown
"CDaR", # Conditional Drawdown at Risk
"EDaR", # Entropic Drawdown at Risk
"RLDaR", # Relativistic Drawdown at Risk
"UCI" # Ulcer Index
]Install with Tessl CLI
npx tessl i tessl/pypi-riskfolio-lib