Skip to main content

LinkedIn   python   MIT license   CI   Code style: black   Checked with mypy  

vartests is a Python library with statistical tests to backtest Value at Risk (VaR) models and other quantile-based risk measures (e.g. Drawdown at Risk). Coverage tests only need the series of violations and the probability of violation, so they work for any risk measure that is a quantile.

Group Test Question
Coverage kupiec_test (Kupiec, 1995) Is the failure rate the nominal one? (chi-square approximation, two-sided)
Coverage binomial_test Same question, exact binomial distribution (one- or two-sided)
Coverage mid_p_test (Lancaster, 1961) Exact binomial with mid-p correction, closer to the nominal size
Coverage poisson_binomial_test Exact test when each observation has its own probability of violation
Coverage binomial_power Size and power of the binomial test for a given sample
Independence duration_test (Christoffersen and Pelletier, 2004) Do violations have no memory, i.e. no clusters?
Distribution berkowitz_tail_test (Berkowitz, 2001) Is the tail of the forecast distribution right?
Distribution zero_mean_test Is the mean of the PnL zero? (assumption of parametric VaR)

Installation

pip install vartests

Or the latest version from GitHub:

pip install https://github.com/rafa-rod/vartests/archive/refs/heads/main.zip

Requires Python 3.10 or later.

Results

Every test returns a dictionary with the same main keys:

Key Content
null hypothesis H0 being tested
statistic test statistic (for exact tests, the number of violations)
p-value p-value
decision "Reject H0", "Fail to reject H0" or "Not enough data"

Some tests add specific keys, such as critical value (chi-square tests), non-rejection region and size (exact tests) or the estimated parameters.

Example

The file media/Example.xlsx has the PnL of a portfolio, its VaR at 99% and the violations (1 when the loss exceeds the VaR). Reading Excel files requires openpyxl:

import pandas as pd
import vartests

data = pd.read_excel("media/Example.xlsx", index_col=0)
violations = data["Violations"]
pnl = data["PnL"]

All functions accept a list, NumPy array, Series or single-column DataFrame.

Coverage

vartests.failure_rate(violations)

vartests.kupiec_test(violations, var_conf_level=0.99, conf_level=0.95)

vartests.binomial_test(violations, var_conf_level=0.99, conf_level=0.95, alternative="greater")
vartests.mid_p_test(violations, var_conf_level=0.99, conf_level=0.95, alternative="greater")

alternative="greater" (default of the exact tests) tests underestimation of risk, i.e. too many violations. Use "two-sided" to also detect a conservative model, or "less" for that alone.

With zero violations, the Kupiec and binomial tests do not reject automatically: the decision depends on the number of observations and on the nominal rate. For example, at a 5% significance level, Kupiec does not reject 0 to 1 violations in 250 days for a 99.9% VaR, but requires 1 to 6 for a 99% VaR (Giambiagi, ch. 10, Table 10.1).

Because the binomial distribution is discrete, the exact test rejects a correct model less often than the nominal level. The size key reports the actual probability; mid_p_test brings it closer to the nominal level, with no guarantee of staying below it. A common practice is to decide with the exact test and report the mid-p as a complement.

A non-rejection is only informative if the test has power. binomial_power shows the chance of detecting a wrong model:

vartests.binomial_power(n=60, var_conf_level=0.975, true_failure_rate=[0.05, 0.075, 0.10])
# {'non-rejection region': (0, 4), 'size': 0.017, 'power': {0.05: 0.18, 0.075: 0.47, 0.1: 0.73}}

When the probability of violation differs across observations (a VaR with a varying level, or the expected coverage of an estimator at each episode of a Drawdown at Risk), use the Poisson-binomial test with one probability per observation:

vartests.poisson_binomial_test(violations, probabilities, conf_level=0.95, alternative="greater")

Independence

vartests.duration_test(violations, conf_level=0.95)

Under H0 the time between violations is exponential (Weibull shape b = 1); b < 1 indicates clusters. At least two durations, one of them uncensored, are required; otherwise the decision is "Not enough data".

Distribution

The Berkowitz test checks whether losses beyond the VaR have the size a normal VaR model predicts, not only how often they happen. It takes the realized PnL and the VaR forecast for each day, in the same unit:

vartests.berkowitz_tail_test(pnl, var, var_conf_level=0.99, conf_level=0.95)

The test assumes a normal VaR with zero mean, so the forecast standard deviation is |VaR_t| / z, where z is the normal quantile of var_conf_level. The VaR can be reported as a positive loss or a negative return, as long as all values have the same sign. In the example file, the test rejects H0: the largest loss is about 3.3 times the VaR, much more than a normal tail allows.

Parametric models such as EWMA and GARCH often assume zero mean:

vartests.zero_mean_test(pnl, conf_level=0.95)

Changes in 0.4.0

  • berkowitz_tail_test(pnl, var, ...) now takes the realized PnL and the VaR series, instead of the PIT, and assumes a normal VaR with zero mean.
  • berkowtiz_tail_test (misspelled, deprecated in 0.3.0) was removed.

Changes in 0.3.0

Version 0.3.0 fixes errors and changes the output of some functions:

  • kupiec_test no longer rejects automatically with zero violations and returns the p-value.
  • duration_test fixes the likelihood when the series does not end with a violation (the usual case); p-values change in most samples.
  • zero_mean_test works with pandas 2 and 3 and accepts Series.
  • berkowitz_tail_test receives the PIT of the model being tested. Results differ slightly from 0.2.x because the conditional mean is now forecast without look-ahead.
  • Result keys are standardized (statistic, p-value, decision).
  • New tests: binomial_test, mid_p_test, poisson_binomial_test and binomial_power.

References

  • Berkowitz, J. (2001). Testing density forecasts, with applications to risk management. Journal of Business & Economic Statistics, 19(4), 465-474.
  • Christoffersen, P. and Pelletier, D. (2004). Backtesting Value-at-Risk: a duration-based approach. Journal of Financial Econometrics, 2(1), 84-108.
  • Giambiagi, F. (Org.). Derivativos e risco de mercado. Elsevier. Ch. 10 (Backtesting).
  • Kupiec, P. (1995). Techniques for verifying the accuracy of risk measurement models. Journal of Derivatives, 3(2), 73-84.
  • Lancaster, H. O. (1961). Significance tests in discrete distributions. Journal of the American Statistical Association, 56(294), 223-234.

Metadata

Release files for vartests 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for vartests 0.4.0
File Size Uploaded
vartests-0.4.0.tar.gz 15.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for vartests 0.4.0
File Interpreter ABI Platform
vartests-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 29.5 kB

Release files / vartests-0.4.0.tar.gz

Download URL vartests-0.4.0.tar.gz
Size 15.0 kB
Tags Source
SHA-256 checksum
How to use checksums
32cc0f26753d5978b4b5abe8c04bdcfdcc2f5b2d95bbd08db895fbaaea97e243
BLAKE2b-256 checksum
How to use checksums
f1b5b0b09ef92b8f67d6ba8af5d795ece3ce26149934dbe377385b9d2843701c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.5.1 CPython/3.11.17 Linux/6.17.0-1022-azure

Release files / vartests-0.4.0-py3-none-any.whl

Download URL vartests-0.4.0-py3-none-any.whl
Size 14.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5b4b12a37498afa7654d2b33bb94c50044a404ef3f4880c5688a0e7092c72061
BLAKE2b-256 checksum
How to use checksums
ff4c68af1cb00df888c705208a8e57c8a373822540362b41ff02502c3eee9338
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.5.1 CPython/3.11.17 Linux/6.17.0-1022-azure

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2.4

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.19

2 release files

0.1.17

2 release files

0.1.16

2 release files

0.1.15

2 release files

0.1.14

2 release files

0.1.13

2 release files

0.1.12

2 release files

0.1.11

2 release files

0.1.10

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page