Skip to main content

cpm-approx

Analytical Value at Risk and Expected Shortfall of a credit portfolio in the multi-factor Merton model — no simulation, deterministic, fast for portfolios with thousands of facilities. It implements the multi-factor adjustment of M. Pykhtin, "Multi-factor adjustment", Risk, March 2004, in Rust with Python bindings. It is not affiliated with the author of the paper or its publisher.

All figures are loss rates relative to total exposure; the loss quantile includes the expected loss.

Install

Python 3.12 or newer, no dependencies (NumPy arrays are accepted as input).

pip install cpm-approx            # once released on PyPI
pip install --index-url https://test.pypi.org/simple/ cpm-approx    # current test release

Usage

The example portfolio is the one of the paper (Table C: 11 factors, ten buckets, 750 facilities):

from cpm_approx import paper_portfolio, portfolio_risk

r = portfolio_risk(**paper_portfolio(rho=0.5), confidence=0.999)
print(f"VaR {r.var:.2%}  ES {r.es:.2%}  one-factor limit {r.var_limit:.2%}")    # VaR 2.33%  ES 2.76%

paper_portfolio() returns a dictionary with the keys pd, lgd, exposure, asset_correlation, lgd_std and loadings. The two stars unpack it into keyword arguments, so the call is the same as portfolio_risk(pd=..., lgd=..., exposure=..., asset_correlation=..., lgd_std=..., loadings=..., confidence=0.999).

Your own portfolio, one entry per facility:

r = portfolio_risk(
    pd, lgd, exposure, asset_correlation, 0.999,
    factor_weights=weights,            # sector weights per facility ...
    factor_correlation=corr,           # ... and the correlation matrix of the factors
    lgd_std=lgd_std,                   # optional: standard deviation of the LGD
)
  • asset_correlation is the squared loading R² on the systematic factors.
  • Instead of weights and correlation matrix you can pass loadings (rows of unit norm on independent factors). Without any factor input a single factor is used.
  • The result RiskResult has expected_loss, var, es and, for comparison, var_limit and es_limit of the comparable one-factor portfolio before the multi-factor and granularity corrections.
  • analyze(dict) takes and returns JSON-like dictionaries. Invalid input raises ValueError. The GIL is released during the computation.

The cost grows quadratically with the number of facilities (3000 facilities ≈ 1 s on two cores). The method is a second-order expansion; for very concentrated portfolios with few facilities, check against a simulation.

Theory

Portfolio of M facilities with exposure weights w_i, default probabilities PD_i, random LGD λ_i with mean μ_i and standard deviation σ_i (independent of everything else). The asset value depends on K independent standard normal systematic factors η and an idiosyncratic factor ξ_i; a facility defaults when its asset value falls below the threshold. r_i² is the asset correlation (asset_correlation), β_i the unit-norm loading on the factors.

asset value model and portfolio loss

Step 1 — comparable one-factor portfolio. The factors are collapsed to the one direction b that matters most in the tail; a_i is the effective loading of facility i on it.

direction b and effective loadings

Given the single factor Y = b·η the conditional default probability and expected loss are

conditional default probability and expected loss

and for infinitely many small facilities VaR and expected shortfall follow directly (Φ₂ is the bivariate normal CDF). These are var_limit and es_limit.

one-factor limit of VaR and expected shortfall

Step 2 — second-order correction. The real loss is ℓ(Y) plus a residual with conditional variance v(y). A Taylor expansion of the quantile in v gives

second-order correction of VaR and expected shortfall

The variance has two parts, the multi-factor adjustment (the factors beyond Y still move the loss) and the granularity adjustment (finite number of facilities, LGD risk), with h_i = Φ⁻¹(p_i(y)):

conditional variance: multi-factor and granularity part

var_rate is t_0 + Δt with v = v_∞ + v_GA. The bivariate normal CDF is evaluated with Plackett's identity by Gauss–Legendre quadrature (5 to 24 nodes chosen by |ρ|, error below 2·10⁻¹⁵; 40 nodes with the substitution r = sin t for |ρ| ≥ 0.9):

Plackett's identity for the bivariate normal CDF

Development

uv sync && uv run pytest      # builds the Rust extension (Rust toolchain required)
cargo test --release          # Rust tests: Table C of the paper, parity with a Python reference implementation

The Rust library (cpm_approx) and a JSON command line tool (cpm-approx) are built from the same sources.

The formulas above are PNG images rendered with typst; their typst source is kept in HTML comments in this README (invisible on GitHub). Edit the comment and run python tools/formulas.py to regenerate docs/img/*.png.

Reference

M. Pykhtin, Multi-factor adjustment, Risk 17(3), 2004, 85–90.

License

MIT

Metadata

Release files for cpm-approx 0.1.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 cpm-approx 0.1.0
File Size Uploaded Provenance Actions
cpm_approx-0.1.0.tar.gz 210.2 kB Without provenance Details for cpm_approx-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for cpm-approx 0.1.0
File Interpreter ABI Platform Actions
cpm_approx-0.1.0-cp312-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl CPython 3.12 abi3 Linux glibc 2.17+ x86-64 Details for cpm_approx-0.1.0-cp312-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl

Total release size: 533.7 kB

Release files / cpm_approx-0.1.0.tar.gz

Download URL cpm_approx-0.1.0.tar.gz
Size 210.2 kB
Tags Source
SHA-256 checksum
How to use checksums
5d699fed98b39e8601d54de224270052cbaa8cdb290d794efe510430c1a99188
BLAKE2b-256 checksum
How to use checksums
d51994949fb46a27cba0deb118774b84cdb3496b3b39e1af7db2a2f7792a947b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"CachyOS Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / cpm_approx-0.1.0-cp312-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl

Download URL cpm_approx-0.1.0-cp312-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Size 323.5 kB
Tags CPython 3.12 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
1937d26ad0dfe86627d2fd849b260eb3d845f0d1af6264a799f76c206734ad23
BLAKE2b-256 checksum
How to use checksums
2faf98826472e79635bb5fc5ddc746661e2120bf4f8ac10b07ec3411f5695c86
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"CachyOS Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for cpm-approx 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

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