Conditional Value at Risk (cVaR)
Calculate the Conditional Value at Risk (CVaR) of an investment portfolio or asset’s returns.
Conditional Value at Risk (CVaR) is a risk management metric that quantifies the loss in the worst % of cases of an investment portfolio or asset may experience over a specified time horizon and confidence level. It provides insights into the downside risk associated with an investment and helps investors make informed decisions about risk tolerance.
The CVaR is calculated as the expected loss given that the loss threshold (VaR) with a given confidence level (e.g., 5% for alpha=0.05) is exceeded.
The Conditional Value at Risk (expected shortfall) is the measure banks report for market risk under the Basel framework, at 97.5% rather than 95% confidence, because unlike VaR it accounts for the size of the losses in the tail and never penalises diversification (it is subadditive). With daily data the estimate rests on few observations (one year at 95% leaves about 12 days in the tail), so a single extreme day can move it a lot; a longer window or a parametric distribution gives a steadier figure.
The formula is as follows (with the default distribution=”historic” and alpha=0.05):
\[\text{CVaR} = \operatorname{Mean}(\text{Returns} | \text{Returns} \leq \text{VaR})\] \[\text{VaR} = \operatorname{Quantile}(\text{Returns},\; \alpha)\]The quantile interpolates linearly and the CVaR is reported as a return (negative for a loss). The other distributions use closed forms, with Std the sample standard deviation (ddof=1) and z_alpha the standard normal quantile at alpha:
\[\text{Gaussian CVaR} = \text{Mean} - \text{Std} \cdot \operatorname{pdf}(z_{\alpha}) / \alpha\] \[\text{Student-T CVaR} = \text{Location} - \text{Scale} \cdot (v + t ^{2}) / (v - 1) \cdot \text{pdf}_{v}(t) / \alpha,\;\; \text{with}\; t = t_{v} ^{-1} (1 - \alpha)\] \[\text{Laplace CVaR} = \text{Mean} - b \cdot (1 - \ln(2 \cdot \alpha)),\;\; \text{with}\; b = \text{Std} / \sqrt{2}\] \[\text{Logistic CVaR} = \text{Mean} - s \cdot \ln((1 - \alpha) ^{1 - 1 / \alpha} / \alpha),\;\; \text{with}\; s = \text{Std} \cdot \sqrt{3} / \pi\] \[\text{Cornish-Fisher CVaR} = \text{Mean of} (\text{Mean} + z_{cf}(p) \cdot \text{Std}) \text{over}\; 1,\;\; \text{000 evenly spaced p in (0, alpha)}\] \[\text{EVT CVaR} = - (\text{VaR\_loss} + \text{Scale\_GPD} - \xi \cdot u) / (1 - \xi)\]Where the Student-T v, Location and Scale are fitted by maximum likelihood (NaN for v <= 1), z_cf is the Cornish-Fisher quantile of get_value_at_risk, and u, xi, Scale_GPD and VaR_loss are the loss threshold, the fitted Generalized Pareto shape and scale and the EVT VaR as a positive loss (NaN for xi >= 1).
Also known as: CVaR, expected shortfall, ES, tail risk.
Conditional Value at Risk (cVaR) in Python or via the MCP
Install the Finance Toolkit with:
pip install financetoolkit -U
Then call get_conditional_value_at_risk as shown below.
from financetoolkit import Toolkit
toolkit = Toolkit(
["XOM", "CVX", "COP"],
api_key="FINANCIAL_MODELING_PREP_KEY",
start_date="2025-01-01",
end_date="2025-12-31",
)
toolkit.risk.get_conditional_value_at_risk()
Or, after setting up the Finance Toolkit MCP, ask:
What was the daily 95% conditional Value at Risk (expected shortfall) of ExxonMobil, Chevron, ConocoPhillips and the S&P 500 over 2025?
Which returns:
| Value | |
|---|---|
| XOM | -0.0359 |
| CVX | -0.0383 |
| COP | -0.0532 |
| Benchmark | -0.0275 |
Parameters
get_conditional_value_at_risk accepts the following parameters.
| Parameter | Type | Description | Example |
|---|---|---|---|
period | str | The data frequency for returns (daily, weekly, monthly, quarterly, or yearly). Defaults to “daily”. | "weekly" |
alpha | float | The tail probability for the CVaR calculation (e.g., 0.05 for the 95% confidence level). Defaults to 0.05. | 0.01 |
within_period | bool | Whether to calculate CVaR within the specified period or for the entire period. Thus whether to look at the CVaR within a specific year (if period = ‘yearly’) or look at the entirety of all years. Defaults to False. Note that this requires intraday data when period = ‘daily’, since a single day only nests observations when intraday data was fetched. | True |
rolling | int | The rolling window size to use for the calculation. If set, CVaR is calculated over a rolling window of this many periods across the full return history instead of per period (e.g. a rolling 60-day CVaR). Only available for distribution="historic"; see get_acerbi_szekely_test for a rolling, out-of-sample CVaR path under the parametric distributions. Defaults to None. | 20 |
rounding | int | None | The number of decimals to round the results to. Defaults to None, which uses the rounding of the Toolkit (4 unless set otherwise). | 2 |
growth | bool | Whether to calculate the growth of the CVaR values over time. Defaults to False. | True |
lag | int | list[int] | The lag to use for the growth calculation. Defaults to 1. | 4 |
standardize | bool | Whether to standardize (Z-Score) the result. When combined with growth=True, standardizes the growth values instead of the raw values. Defaults to False. | True |
distribution | str | The distribution to use for the CVaR calculations (historic, gaussian, studentt, laplace, logistic, cornish-fisher or evt). Defaults to “historic”. | "studentt" |
threshold_percentile | float | Only used when distribution is “evt”. The percentile of losses above which the Generalized Pareto Distribution is fitted; alpha can be at most 1 - threshold_percentile, and a larger alpha gives an empty result (with a logged error). Defaults to 0.95. | 0.9 |