Maximum CVaR Ratio
Calculate the weights of the portfolio with the highest CVaR ratio: the average return above the risk free rate divided by the Conditional Value at Risk, the average loss in the worst periods. It is the maximum Sharpe ratio portfolio with the tail loss in place of the volatility, so upside swings are not penalized and crash risk is.
The ratio (r̄ - r_f)’w / CVaR_α(w), with the CVaR of Rockafellar and Uryasev (2000), is maximized exactly as a linear programme with the Charnes-Cooper transformation y = κw, κ > 0: maximize (r̄ - r_f)’y subject to ζ + Σ max(0, -r_t’y - ζ) / ((1 - α)T) ≤ 1 and the weight constraints, then w = y / κ.
For more information, see the following papers:
- Martin, R. D., Rachev, S. T. and Siboulet, F. (2003). “Phi-Alpha Optimal Portfolios and Extreme Risk Management.” Wilmott Magazine, November, 70-83.
- Rockafellar, R. T. and Uryasev, S. (2000). “Optimization of Conditional Value-at-Risk.” Journal of Risk, 2(3), 21-41.
Also known as: maximum STARR, stable tail adjusted return ratio, maximum return-to-CVaR, mean-CVaR tangency portfolio.
Maximum CVaR Ratio in Python or via the MCP
Install the Finance Toolkit with:
pip install financetoolkit -U
Then call get_maximum_cvar_ratio_weights as shown below.
from financetoolkit import Toolkit
toolkit = Toolkit(
["AAPL", "MSFT", "JNJ", "XOM"],
api_key="FINANCIAL_MODELING_PREP_KEY",
start_date="2021-01-01",
end_date="2025-12-31",
)
toolkit.portfolio.get_maximum_cvar_ratio_weights()[
["Weight", "Expected Return", "Risk Contribution", "CVaR", "CVaR Ratio"]
]
Or, after setting up the Finance Toolkit MCP, ask:
Which weights in Apple, Microsoft, Johnson & Johnson and ExxonMobil maximized the return per unit of conditional value at risk, based on 2021 to 2025?
Which returns:
| Weight | Expected Return | Risk Contribution | CVaR | CVaR Ratio | |
|---|---|---|---|---|---|
| AAPL | 0 | 0.1932 | 0 | 0.039 | 0.0162 |
| MSFT | 0.277 | 0.2017 | 0.2061 | 0.0356 | 0.0187 |
| JNJ | 0.1978 | 0.0987 | 0.064 | 0.0227 | 0.0113 |
| XOM | 0.5253 | 0.2911 | 0.7299 | 0.0373 | 0.0274 |
| Portfolio | 1 | 0.2283 | 1 | 0.0237 | 0.0326 |
Parameters
get_maximum_cvar_ratio_weights accepts the following parameters.
| Parameter | Type | Description | Example |
|---|---|---|---|
confidence_level | float | The confidence level of the CVaR, e.g. 0.95 for the average of the worst 5% of periods. Defaults to 0.95. | 0.95 |
period | str | The frequency of the returns (daily, weekly, monthly, quarterly or yearly). Defaults to “daily”. | "weekly" |
expected_returns | str | The estimator of the expected returns: “mean” (the historical average), “exponential” (the exponentially weighted average, recent periods weigh most), “capm” (the returns the Capital Asset Pricing Model implies from each asset’s beta to the benchmark, Sharpe, 1964) or “james_stein” (the averages shrunk towards that of the minimum variance portfolio, Jorion, 1986). Defaults to “mean”. | "mean" |
expected_returns_span | int | The span in periods of the “exponential” expected returns. Defaults to 180. | 180 |
minimum_weight | float | dict[str, float] | The lowest weight of every asset, or per asset, e.g. {“AAPL”: 0.05} (the others keep 0); a negative value allows short positions. Defaults to 0. | 0 |
maximum_weight | float | dict[str, float] | The highest weight of every asset, or per asset, e.g. {“AAPL”: 0.3} (the others keep 1). Defaults to 1. | 1 |
sector_bounds | dict[str, tuple[float, float]] | None | The minimum and maximum total weight per sector, e.g. {“Technology”: (0, 0.4)}, with the sector of each asset from its company profile. Defaults to None. | None |
country_bounds | dict[str, tuple[float, float]] | None | The minimum and maximum total weight per country, named in full or by its two-letter code, e.g. {“United States”: (0, 0.6)}, with the country of each asset from its company profile. Defaults to None. | None |
net_exposure | float | The sum of the weights: 1 for a fully invested portfolio, 0 for a market neutral one. Defaults to 1. | 1 |
gross_exposure | float | None | The highest sum of the absolute weights, which limits the leverage of a long-short portfolio, e.g. 1.6 for a 130/30 portfolio. Defaults to None, no limit. | None, no limit |
current_weights | dict[str, float] | None | The weights held now, e.g. {“AAPL”: 0.5, “MSFT”: 0.5} (an asset left out is not held), which the turnover is measured from; they add a Turnover column, |w_i - w0_i| per asset and its sum for the portfolio. Defaults to None, which uses the latest weights of the Portfolio the Toolkit came from when a maximum turnover needs them. | None, which uses the latest weights of the Portfolio the Toolkit came from when a maximum turnover needs them |
maximum_turnover | float | None | The highest turnover Σ |w_i - w0_i| from the current weights, e.g. 0.2 to trade at most 10% of the portfolio each way. Defaults to None, no limit. | None, no limit |
include_benchmark | bool | Whether to include the benchmark as an asset. Defaults to False. | True |
rounding | int | None | The number of decimals to round the results to. Defaults to None, which uses the Toolkit’s rounding. | 2 |