<a id="sphx-glr-auto-examples-mean-risk-plot-4-mean-variance-cdar-py"></a>

<a id="mean-variance-cdar-surface"></a>

# Mean-Variance-CDaR Surface

This tutorial uses the [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) optimization to find an
ensemble of portfolios belonging to the Mean-Variance-CDaR efficient frontier.

<a id="data"></a>

## Data

We load the S&P 500 [dataset](https://skfolio.org/user_guide/datasets.html.md#datasets) composed of the daily prices of 20
assets from the S&P 500 Index composition starting from 2015-01-05 up to 2022-12-28:

```Python
import numpy as np
from plotly.io import show
from sklearn.model_selection import train_test_split

from skfolio import PerfMeasure, RatioMeasure, RiskMeasure
from skfolio.datasets import load_sp500_dataset
from skfolio.optimization import MeanRisk, ObjectiveFunction
from skfolio.preprocessing import prices_to_returns

prices = load_sp500_dataset()
prices = prices["2015":]

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

<a id="model"></a>

## Model

First, we create a Maximum Sharpe Ratio model that we fit on the training set:

```Python
model = MeanRisk(
    risk_measure=RiskMeasure.STANDARD_DEVIATION,
    objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
)
portfolio = model.fit_predict(X_train)
print(portfolio.cdar)
```

```none
0.17001212853184347
```

Let’s assume that we are not satisfied with the CDaR (Conditional Drawdown at Risk)
of 17% corresponding to the maximum Sharpe portfolio. We want to analyze alternative
portfolios that maximize the Sharpe under CDaR constraints.
To have an idea of the feasible CDaR constraints, we analyze the Minimum CDaR
portfolio:

```Python
model = MeanRisk(risk_measure=RiskMeasure.CDAR)
portfolio = model.fit_predict(X_train)
print(portfolio.cdar)
```

```none
0.09718550832245015
```

The minimum CDaR is 9.72%.
Now we find the Pareto-optimal portfolios that maximize the Sharpe under CDaR
constraint ranging from 9.72% to 17%:

```Python
model = MeanRisk(
    risk_measure=RiskMeasure.STANDARD_DEVIATION,
    objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
    max_cdar=np.linspace(start=0.0972, stop=0.17, num=10),
)
model.fit(X_train)
print(model.weights_.shape)
```

```none
(10, 20)
```

<a id="analysis"></a>

## Analysis

We predict this model on both the training set and the test set to analyze the
deformation of the efficient frontier:

```Python
population_train = model.predict(X_train)
population_test = model.predict(X_test)

population_train.set_portfolio_params(tag="Train")
population_test.set_portfolio_params(tag="Test")

population = population_train + population_test

population.plot_measures(
    x=RiskMeasure.CDAR,
    y=RatioMeasure.ANNUALIZED_SHARPE_RATIO,
    color_scale=RatioMeasure.ANNUALIZED_SHARPE_RATIO,
    hover_measures=[RiskMeasure.MAX_DRAWDOWN, RatioMeasure.ANNUALIZED_SORTINO_RATIO],
)
```

<style>html[data-theme="dark"] div.output_subarea:has(.plotly-graph-div){background:#fff;border-radius:0.25rem;padding:0.5rem}@media (prefers-color-scheme: dark){html:not([data-theme="light"]) div.output_subarea:has(.plotly-graph-div){background:#fff;border-radius:0.25rem;padding:0.5rem}}</style><script>if (!window.plotlySphinxGalleryResize) {window.plotlySphinxGalleryResize = true;window.addEventListener("load", function () {document.querySelectorAll(".plotly-graph-div").forEach(function (gd) { Plotly.Plots.resize(gd); });});}</script>[plotly figure stripped from llms output]
<br />
<br />

<a id="pareto-optimal-surface"></a>

## Pareto Optimal Surface

Instead of analyzing the Sharpe-CDaR efficient frontier, we can analyze the
Mean-Variance-CDaR Pareto-optimal surface:

```Python
variance_upper = population_train.max_measure(PerfMeasure.MEAN).variance
x = np.linspace(start=0.00012, stop=variance_upper, num=10)
y = np.linspace(start=0.11, stop=0.17, num=10)
x, y = map(np.ravel, np.meshgrid(x, y))

model = MeanRisk(
    objective_function=ObjectiveFunction.MAXIMIZE_RETURN,
    max_variance=x,
    max_cdar=y,
    raise_on_failure=False,
)
model.fit(X_train)

population_train = model.predict(X_train)

fig = population_train.plot_measures(
    x=RiskMeasure.ANNUALIZED_VARIANCE,
    y=RiskMeasure.CDAR,
    z=PerfMeasure.ANNUALIZED_MEAN,
    to_surface=True,
)
fig.update_layout(scene_camera=dict(eye=dict(x=-2, y=-0.5, z=1)))
show(fig)
```

[plotly figure stripped from llms output]<style>html[data-theme="dark"] div.output_subarea:has(.plotly-graph-div){background:#fff;border-radius:0.25rem;padding:0.5rem}@media (prefers-color-scheme: dark){html:not([data-theme="light"]) div.output_subarea:has(.plotly-graph-div){background:#fff;border-radius:0.25rem;padding:0.5rem}}</style><script>if (!window.plotlySphinxGalleryResize) {window.plotlySphinxGalleryResize = true;window.addEventListener("load", function () {document.querySelectorAll(".plotly-graph-div").forEach(function (gd) { Plotly.Plots.resize(gd); });});}</script>
```none
/home/runner/work/skfolio/skfolio/src/skfolio/optimization/convex/_base.py:1247: UserWarning: Solution may be inaccurate. Try changing the solver params or the scale. For more details, set `solver_params=dict(verbose=True)`
  weights, problem_values = _solve(
/home/runner/work/skfolio/skfolio/src/skfolio/optimization/convex/_base.py:1247: UserWarning: Solution may be inaccurate. Try changing the solver params or the scale. For more details, set `solver_params=dict(verbose=True)`
  weights, problem_values = _solve(
/home/runner/work/skfolio/skfolio/src/skfolio/optimization/convex/_base.py:1247: UserWarning: Solution may be inaccurate. Try changing the solver params or the scale. For more details, set `solver_params=dict(verbose=True)`
  weights, problem_values = _solve(
/home/runner/work/skfolio/skfolio/src/skfolio/optimization/convex/_base.py:1247: UserWarning: Solution may be inaccurate. Try changing the solver params or the scale. For more details, set `solver_params=dict(verbose=True)`
  weights, problem_values = _solve(
/home/runner/work/skfolio/skfolio/src/skfolio/optimization/convex/_base.py:1247: UserWarning: Solution may be inaccurate. Try changing the solver params or the scale. For more details, set `solver_params=dict(verbose=True)`
  weights, problem_values = _solve(
/home/runner/work/skfolio/skfolio/src/skfolio/optimization/convex/_base.py:1247: UserWarning: Solution may be inaccurate. Try changing the solver params or the scale. For more details, set `solver_params=dict(verbose=True)`
  weights, problem_values = _solve(
/home/runner/work/skfolio/skfolio/src/skfolio/optimization/convex/_base.py:1247: UserWarning: Solution may be inaccurate. Try changing the solver params or the scale. For more details, set `solver_params=dict(verbose=True)`
  weights, problem_values = _solve(
/home/runner/work/skfolio/skfolio/src/skfolio/optimization/convex/_base.py:1247: UserWarning: Solution may be inaccurate. Try changing the solver params or the scale. For more details, set `solver_params=dict(verbose=True)`
  weights, problem_values = _solve(
```

<br/>

Let’s plot the composition of the portfolios:

```Python
population_train.plot_composition()
```

<style>html[data-theme="dark"] div.output_subarea:has(.plotly-graph-div){background:#fff;border-radius:0.25rem;padding:0.5rem}@media (prefers-color-scheme: dark){html:not([data-theme="light"]) div.output_subarea:has(.plotly-graph-div){background:#fff;border-radius:0.25rem;padding:0.5rem}}</style><script>if (!window.plotlySphinxGalleryResize) {window.plotlySphinxGalleryResize = true;window.addEventListener("load", function () {document.querySelectorAll(".plotly-graph-div").forEach(function (gd) { Plotly.Plots.resize(gd); });});}</script>[plotly figure stripped from llms output]
<br />
<br />

Let’s compare the average and standard-deviation of the Sharpe Ratio and CDaR Ratio of
the portfolios on the training set versus the test set:

Train:

```Python
print(population_train.measures_mean(measure=RatioMeasure.ANNUALIZED_SHARPE_RATIO))
print(population_train.measures_std(measure=RatioMeasure.ANNUALIZED_SHARPE_RATIO))
```

```none
1.362741656336506
0.09606306762254788
```

Test:

```Python
print(population_test.measures_mean(measure=RatioMeasure.ANNUALIZED_SHARPE_RATIO))
print(population_test.measures_std(measure=RatioMeasure.ANNUALIZED_SHARPE_RATIO))
```

```none
0.9038068241543424
0.06763765525558574
```

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

<a id="sphx-glr-download-auto-examples-mean-risk-plot-4-mean-variance-cdar-py"></a>
