Acerbi-Szekely Test
Backtest a Conditional Value at Risk (Expected Shortfall) model against realized returns, via the Acerbi-Szekely (2014) Z2 statistic.
get_var_backtest above only backtests the VaR estimate itself – it checks how often (and how independently) the VaR threshold is breached, but says nothing about the severity of the losses on those breach days, which is exactly the extra information a CVaR (Expected Shortfall) estimate is supposed to add over VaR. This method builds a rolling, out-of-sample CVaR (and VaR) path and compares the actual loss on each breach day to the CVaR that was supposed to describe the average loss on such days.
The formula is as follows (with the default distribution=”historic”, alpha=0.05 and window_size=252):
\[Z_{2} = \text{Σ} (\text{Return}_{t} \cdot \text{Breach}_{t} / \text{CVaR}_{t}) / (n \cdot \alpha) - 1\] \[\text{P-Value} = 1 - \Phi(Z_{2} / \text{Standard Error})\]Where VaR_t and CVaR_t are estimated from the 252 returns before t (see get_var_backtest), Breach_t is 1 if Return_t < VaR_t and 0 otherwise, n is the number of estimates and the Standard Error is the sample standard deviation (ddof=1) of Z2 over n_bootstrap paired bootstrap resamples. Returns and CVaR are both negative, so Z2 is about 0 for a well-calibrated model and positive when the realized tail losses exceed the CVaR (the opposite sign of the paper, which counts losses as positive).
For more information about the method, see the following paper:
- Acerbi, C., & Szekely, B. (2014). “Back-Testing Expected Shortfall.” RISK Magazine, 27(11), 76-81.
Also known as: Acerbi-Szekely test, ES backtest, Z2 test.
Acerbi-Szekely Test in Python or via the MCP
Install the Finance Toolkit with:
pip install financetoolkit -U
Then call get_acerbi_szekely_test as shown below.
from financetoolkit import Toolkit
toolkit = Toolkit(
["BA", "DAL", "CCL"],
api_key="FINANCIAL_MODELING_PREP_KEY",
start_date="2021-01-01",
end_date="2025-12-31",
)
toolkit.risk.get_acerbi_szekely_test().loc[["Acerbi-Szekely Statistic", "P-Value"]]
Or, after setting up the Finance Toolkit MCP, ask:
Does a rolling one-year 95% historical expected shortfall pass the Acerbi-Szekely test for Boeing, Delta Air Lines, Carnival and the S&P 500 from 2021 to 2025?
Which returns:
| BA | DAL | CCL | Benchmark | |
|---|---|---|---|---|
| Acerbi-Szekely Statistic | 0.1548 | 0.2473 | 0.1402 | 0.2394 |
| P-Value | 0.176 | 0.0762 | 0.1963 | 0.0785 |
Parameters
get_acerbi_szekely_test accepts the following parameters.
| Parameter | Type | Description | Example |
|---|---|---|---|
period | str | The data frequency for returns (daily, weekly, monthly, quarterly or yearly). Defaults to “daily”, since window_size is expressed in return observations of this frequency. | "weekly" |
distribution | str | The distribution to use for the rolling VaR/CVaR estimates, one of “historic”, “gaussian”, “studentt” or “evt”. Defaults to “historic”. “studentt” and “evt” fit their distribution to every window, which takes minutes for years of daily data, where “historic” and “gaussian” take well under a second. | "studentt" |
alpha | float | The tail probability for the VaR/CVaR estimates (e.g., 0.05 for the 95% confidence level). Defaults to 0.05. With “evt” it can be at most 0.05, since the Generalized Pareto Distribution is fitted above the 95th percentile of losses; a larger alpha gives an empty result (with a logged error). | 0.01 |
window_size | int | The rolling window size (in number of return observations) used to estimate each VaR/CVaR value. Defaults to 252 (approximately one trading year of daily returns). | 52 |
n_bootstrap | int | The number of bootstrap resamples used to estimate the Standard Error of Z2. Defaults to 1000. | 5000 |
random_state | int | The seed for the bootstrap random number generator. Defaults to 42. | 1 |
rounding | int | None | The number of decimals to round the results to. Defaults to None. | 2 |