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.

ParameterTypeDescriptionExample
periodstrThe data frequency for returns (daily, weekly, monthly, quarterly, or yearly). Defaults to “daily”."weekly"
alphafloatThe tail probability for the CVaR calculation (e.g., 0.05 for the 95% confidence level). Defaults to 0.05.0.01
within_periodboolWhether 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
rollingintThe 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
roundingint | NoneThe number of decimals to round the results to. Defaults to None, which uses the rounding of the Toolkit (4 unless set otherwise).2
growthboolWhether to calculate the growth of the CVaR values over time. Defaults to False.True
lagint | list[int]The lag to use for the growth calculation. Defaults to 1.4
standardizeboolWhether to standardize (Z-Score) the result. When combined with growth=True, standardizes the growth values instead of the raw values. Defaults to False.True
distributionstrThe distribution to use for the CVaR calculations (historic, gaussian, studentt, laplace, logistic, cornish-fisher or evt). Defaults to “historic”."studentt"
threshold_percentilefloatOnly 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
Share