Risk Budgeting - CVaR#

This tutorial uses the RiskBudgeting optimization to build a risk budgeting portfolio by specifying a risk budget on each asset with CVaR as the risk measure.

Data#

We load the S&P 500 dataset composed of the daily prices of 20 assets from the S&P 500 Index composition starting from 1990-01-02 up to 2022-12-28:

from plotly.io import show
from sklearn.model_selection import train_test_split

from skfolio import Population, RiskMeasure
from skfolio.datasets import load_sp500_dataset
from skfolio.optimization import InverseVolatility, RiskBudgeting
from skfolio.preprocessing import prices_to_returns

prices = load_sp500_dataset()

X = prices_to_returns(prices)
X_train, X_test = train_test_split(X, test_size=0.33, shuffle=False)

Risk Budget#

We chose the following risk budget: 1.5 on Apples, 0.2 on General Electric and JPMorgan and 1.0 on the remaining assets:

risk_budget = {asset_name: 1 for asset_name in X.columns}
risk_budget["AAPL"] = 1.5
risk_budget["GE"] = 0.2
risk_budget["JPM"] = 0.2

Model#

We create the risk budgeting model and then fit it on the training set:

model = RiskBudgeting(
    risk_measure=RiskMeasure.CVAR,
    risk_budget=risk_budget,
    portfolio_params=dict(name="Risk Budgeting - CVaR"),
)
model.fit(X_train)
model.weights_
array([0.06173016, 0.03257461, 0.03336015, 0.03994768, 0.06348968,
       0.0093012 , 0.04579241, 0.06880861, 0.00765335, 0.06700177,
       0.05537228, 0.05430773, 0.04828249, 0.07033698, 0.05371274,
       0.06892752, 0.04230882, 0.04897392, 0.06251756, 0.06560031])

To compare this model, we use an inverse volatility benchmark using the InverseVolatility estimator:

bench = InverseVolatility(portfolio_params=dict(name="Inverse Vol"))
bench.fit(X_train)
bench.weights_
array([0.03306735, 0.02548697, 0.03551377, 0.0296872 , 0.06358463,
       0.05434705, 0.04742354, 0.07049715, 0.03882539, 0.06697905,
       0.05570808, 0.05576851, 0.04723274, 0.06351213, 0.05581397,
       0.0676481 , 0.02564642, 0.03970752, 0.05744543, 0.06610498])

Risk Contribution Analysis#

Let’s analyze the risk contribution of both models on the training set. As expected, the risk budgeting model has 50% more CVaR contribution to Apple and 80% less to General Electric and JPMorgan compared to the other assets:

ptf_model_train = model.predict(X_train)
fig = ptf_model_train.plot_contribution(measure=RiskMeasure.CVAR)
show(fig)

And the inverse volatility model has different CVaR contribution for each asset:

ptf_bench_train = bench.predict(X_train)
ptf_bench_train.plot_contribution(measure=RiskMeasure.CVAR)


Prediction#

We predict the model and the benchmark on the test set:

ptf_model_test = model.predict(X_test)
ptf_bench_test = bench.predict(X_test)

Analysis#

For improved analysis, it’s possible to load both predicted portfolios into a Population:

population = Population([ptf_model_test, ptf_bench_test])

Let’s plot each portfolio composition:

population.plot_composition()


Let’s plot each portfolio cumulative returns:

fig = population.plot_cumulative_returns()
show(fig)

Finally, we print a full summary of both strategies evaluated on the test set:

population.summary()
Risk Budgeting - CVaR Inverse Vol
Mean 0.067% 0.064%
Annualized Mean 17.00% 16.06%
Variance 0.010% 0.010%
Annualized Variance 2.57% 2.56%
Semi-Variance 0.0052% 0.0053%
Annualized Semi-Variance 1.32% 1.33%
Standard Deviation 1.01% 1.01%
Annualized Standard Deviation 16.02% 16.00%
Semi-Deviation 0.72% 0.73%
Annualized Semi-Deviation 11.50% 11.54%
Mean Absolute Deviation 0.65% 0.65%
CVaR at 95% 2.33% 2.35%
EVaR at 95% 5.12% 5.29%
Worst Realization 10.08% 10.49%
CDaR at 95% 12.03% 12.22%
MAX Drawdown 32.78% 34.83%
Average Drawdown 2.34% 2.34%
EDaR at 95% 18.98% 20.05%
First Lower Partial Moment 0.33% 0.32%
Ulcer Index 0.040 0.040
Gini Mean Difference 0.99% 0.98%
Value at Risk at 95% 1.43% 1.45%
Drawdown at Risk at 95% 8.81% 8.79%
Entropic Risk Measure at 95% 3.00 3.00
Fourth Central Moment 0.000021% 0.000022%
Fourth Lower Partial Moment 0.000010% 0.000011%
Skew -2.47% -14.94%
Kurtosis 2031.63% 2117.02%
Sharpe Ratio 0.067 0.063
Annualized Sharpe Ratio 1.06 1.00
Sortino Ratio 0.093 0.088
Annualized Sortino Ratio 1.48 1.39
Mean Absolute Deviation Ratio 0.10 0.098
First Lower Partial Moment Ratio 0.21 0.20
Value at Risk Ratio at 95% 0.047 0.044
CVaR Ratio at 95% 0.029 0.027
Entropic Risk Measure Ratio at 95% 0.00023 0.00021
EVaR Ratio at 95% 0.013 0.012
Worst Realization Ratio 0.0067 0.0061
Drawdown at Risk Ratio at 95% 0.0077 0.0073
CDaR Ratio at 95% 0.0056 0.0052
Calmar Ratio 0.0021 0.0018
Average Drawdown Ratio 0.029 0.027
EDaR Ratio at 95% 0.0036 0.0032
Ulcer Index Ratio 0.017 0.016
Gini Mean Difference Ratio 0.068 0.065
Effective Number of Assets 17.728117696106207 18.460872007821077
Assets Number 20 20


Total running time of the script: (0 minutes 1.948 seconds)

Gallery generated by Sphinx-Gallery