Metadata-Version: 2.4
Name: mrv-lib
Version: 0.6.0
Summary: Model Risk Validator for Model Risk Governance
Author-email: Kai Zheng <kai.zheng@mrv-lib.org>
License-Expression: AGPL-3.0-or-later
Project-URL: Homepage, https://mrv-lib.org
Project-URL: Repository, https://github.com/modelguard-lab/mrv-lib
Project-URL: Issues, https://github.com/modelguard-lab/mrv-lib/issues
Project-URL: Changelog, https://github.com/modelguard-lab/mrv-lib/blob/main/CHANGELOG.md
Keywords: model-risk,validation,SR-26-2,SR-11-7,Basel,regime,invariance,governance,MRI,specification-risk,OCC-2026-13
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE.md
Requires-Dist: numpy>=1.23
Requires-Dist: pandas>=1.5
Requires-Dist: pyyaml>=5.4
Requires-Dist: scipy>=1.9
Requires-Dist: matplotlib>=3.5
Requires-Dist: scikit-learn>=1.2
Requires-Dist: hmmlearn>=0.3
Requires-Dist: yfinance>=0.2.30
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: black; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Provides-Extra: examples
Requires-Dist: jupyter; extra == "examples"
Requires-Dist: ipykernel; extra == "examples"
Requires-Dist: matplotlib; extra == "examples"
Requires-Dist: scikit-learn; extra == "examples"
Provides-Extra: docs
Requires-Dist: sphinx>=7; extra == "docs"
Requires-Dist: furo; extra == "docs"
Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
Requires-Dist: myst-parser; extra == "docs"
Dynamic: license-file

# mrv-lib: Model Risk Validator

[![CI](https://github.com/modelguard-lab/mrv-lib/actions/workflows/ci.yml/badge.svg)](https://github.com/modelguard-lab/mrv-lib/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/mrv-lib)](https://pypi.org/project/mrv-lib/)
[![Python](https://img.shields.io/pypi/pyversions/mrv-lib)](https://pypi.org/project/mrv-lib/)

**Your model might be producing different outputs depending on which features you feed it, which seed you use, or how you bin the data: and your current validation doesn't catch this.** mrv-lib tests whether your model outputs are stable across admissible specification choices, or silently depend on arbitrary modelling decisions.

mrv is a **pure validation library**: you supply labels from your own models, mrv measures how stable they are. Bank MRM (OCC Bulletin 2026-13 -- the 2026-04-17 Revised Model Risk Management Guidance that supersedes SR 11-7 -- Basel IV / FRTB, RBNZ BS2A, APRA CPS 220, MAS AI MRM, EU AI Act) is the anchor application; the same framework deploys equally to **quant-fund risk discipline** (sizing-gate at matched Sharpe with reduced MaxDD) and **production ML monitoring** (route to fallback or human-in-the-loop on RED, regardless of whether the model is for finance or any other domain).

The framework is **identification-locked, not alpha**: see [Paper 4a §6 (Orthogonality to the Realized-Data Class)](https://github.com/modelguard-lab) for the empirical chain establishing that the underlying primitive is orthogonal to realized-vol metrics (joint R^2 < 0.05 on the daily axis), does not predict forward returns, and is not autocorrelated beyond its construction window. mrv-lib is therefore a governance signal, not a forecast.

## What it does

| Test | Question | Status |
| ---- | -------- | ------ |
| **Representation Invariance** | Do labels change when you use different feature representations? | v0.1.0 |
| **Resolution Invariance** | Do labels agree across 5m / 15m / 1h / 1d frequencies? | v0.2.1 |
| **Model Risk Index (MRI)** | A single score combining rep + res into actionable governance signal | v0.3.0 |

Also includes: business impact function (`impact_fn`), continuous monitoring with alerts, disagreement attribution (LOO / frequency-pair / temporal), model-risk report aligned to OCC Bulletin 2026-13 (formerly SR 11-7) with auto-generated findings, and a findings engine with severity classification.

## Use cases

Three production-grade deployment patterns share one Gate / Envelope / Tier mechanic:

| Domain | What you gate | RED action |
| ------ | ------------- | ---------- |
| **Bank MRM** (OCC Bulletin 2026-13 / Basel / MAS AI MRM) | Internal model output (VaR, ECL, IRB risk-weights) | Suspend primary; activate fallback; committee review within 5 days |
| **Quant fund risk discipline** | Strategy position sizing (deployment of an alpha you trust) | Reduce to 30% of target; flatten after 3 consecutive RED days |
| **Production ML monitoring** | Live ML system serving predictions (any domain: finance, recsys, fraud, healthcare, autonomous systems) | Route to fallback (rule-based, prior-version, human-in-the-loop); page on-call |

The cross-domain fit is not aspirational: the same `quick_mri(close)` API drives the Tier classification in all three; the difference is which downstream action the GREEN/YELLOW/RED tier triggers.

## Install

```bash
pip install mrv-lib
```

## Quick start

One-liner from daily close prices (no extra data required):

```python
import numpy as np
import pandas as pd
from mrv.mri import quick_mri

# Generate a sample close-price series (replace with your own pd.Series)
rng = np.random.default_rng(0)
dates = pd.bdate_range("2022-01-03", periods=500)
close = pd.Series(100 * np.exp(rng.normal(0, 0.01, 500).cumsum()), index=dates)

mri = quick_mri(close)
mri.report()            # sub-metric breakdown
df = mri.to_dataframe()
```

Labels-first API (supply labels from your own model):

```python
from mrv.pipeline import validate_rep

result = validate_rep(labels={
    "SPY": {
        "vol+dd+var":   labels_a,  # 1-D integer ndarray of regime labels
        "vol+var+cvar": labels_b,
    }
})
print(result["assets"]["SPY"]["mean_ari"])
```

## Logging

mrv-lib uses Python's standard `logging` module with hierarchical names
(`mrv.mri.index`, `mrv.validator.rep`, etc.). By default nothing is emitted.

```python
import logging

# Show all mrv INFO+ messages (compute_mri run summaries, zone changes)
logging.basicConfig(level=logging.INFO)

# Show DEBUG for the MRI engine only, keep everything else quiet
logging.getLogger("mrv.mri").setLevel(logging.DEBUG)

# Route mrv logs to a file
handler = logging.FileHandler("mrv_run.log")
logging.getLogger("mrv").addHandler(handler)
```

See `src/mrv/utils/log.py` and `src/mrv/default_config.yaml` for the YAML-based
logging configuration used by the convenience pipeline.

## Theorem-applicability checks

Before interpreting MRI sub-scores, verify that the underlying theoretical
preconditions hold for your data. Two helper functions expose the most
commonly violated preconditions:

```python
import numpy as np
from mrv.mri import verify_thm_rep_applicability, kappa_reversible_bound

# Check Paper 3a thm:rep Hypothesis (vii) small-perturbation regime
# L * D <= Delta / 2  (required for the linear bound to be rigorous)
applicable = verify_thm_rep_applicability(L=1.0, D=0.3, Delta=1.0)
# True if L * D <= Delta / 2; False otherwise.
# Raises ValueError on non-positive L/Delta or negative/non-finite D.

# Tighter kappa bound for reversible chains (Paper 3a thm:res supplement)
# For approximately-balanced empirical regimes (pi ratios 2-3 on Paper 1
# fitted HMMs), this gives kappa(V) <= sqrt(3) ~ 1.73 independent of K.
pi = np.array([0.5, 0.3, 0.2])   # stationary distribution from fitted HMM
kappa_tight = kappa_reversible_bound(pi)
# Returns NaN if pi has zero entries, sums != 1, or contains non-finite values.
```

See `docs/THEOREM_API_BINDING.md` for the full precondition table linking
every public API to its supporting theorem and verification status.

## Project layout

```text
mrv-lib/
├── config.yaml              # Configuration (for convenience pipeline)
├── templates/
│   ├── template.tex         # Academic report template
│   ├── sr26_2_template.tex  # Model-risk regulatory report template (SR 26-2 / OCC Bulletin 2026-13)
│   └── sr11_7_template.tex  # Deprecated stub; forwards to sr26_2_template.tex (SR 11-7 superseded 2026-04-17)
├── examples/
│   ├── quickstart.ipynb
│   ├── paper1_representation_invariance.ipynb
│   ├── paper2_resolution_invariance.ipynb
│   ├── paper4a_model_risk_index.ipynb
│   └── example_california_housing.ipynb
├── src/mrv/
│   ├── pipeline.py          # validate_rep() / validate_res() + convenience wrappers
│   ├── data/                # Data loading, factors, normalization (optional)
│   ├── models/              # GMM/HMM fitting
│   ├── validator/
│   │   ├── base.py          # BaseValidator (subclass for custom tests)
│   │   ├── rep.py           # Representation Invariance (Paper 1)
│   │   ├── res.py           # Resolution Invariance (Paper 2)
│   │   ├── metrics.py       # ARI, AMI, NMI, Spearman, VI
│   │   ├── attribution.py   # LOO, frequency-pair, temporal hotspots
│   │   ├── findings.py      # Model-risk findings engine (aligned to SR 26-2 / OCC Bulletin 2026-13)
│   │   ├── monitor.py       # Continuous monitoring + alerts
│   │   └── report.py        # JSON -> LaTeX -> PDF
│   ├── mri/                 # Model Risk Index (Paper 3)
│   │   ├── index.py         # compute_mri(), compute_rolling_mri(), quick_mri()
│   │   ├── bounds.py        # Ordinal bound G, SOE, zone classification
│   │   ├── spectral.py      # Markov spectral gap, stress diagnostics
│   │   └── wasserstein.py   # Sliced Wasserstein, MRI_cross
│   └── utils/
│       ├── config.py        # YAML config loading
│       ├── download.py      # IB data download
│       └── log.py           # Logging setup
├── reports/                  # Output (gitignored)
└── tests/                    # 280 tests
```

## Output

Each run creates a timestamped directory under `reports/`:

- **result.json** -- Complete data (reusable for report regeneration)
- **report.pdf** -- Professional report with cover page, dashboard, heatmaps, and remediation plan
- **summary.txt** -- Plain text quick view
- **{asset}_ari_heatmap.png** -- ARI heatmap per asset
- **{asset}_timeline.png** -- Regime timeline (res validator)
- **pipeline_summary.csv** -- Summary metrics per asset

## Audit trail

The v0.5.x `result.json` covers the format-compliance requirements of OCC
Bulletin 2026-13 (Revised Model Risk Management Guidance, effective 2026-04-17,
supersedes SR 11-7), Basel IV (FRTB), RBNZ BS2A, APRA CPS 220, and MAS AI
Model Risk Management Guidelines: cross-specification subscores, composite MRI,
zone classification, and remediation rationale. The 2026-13 framework explicitly
emphasises **versioned, reproducible validation artifacts** -- the BCBS 239
audit-trail extension (six additional fields: `input_hash` (sha256), `seed`,
`config_snapshot`, `library_version`, `model_id`, `signatures`) directly
satisfies this requirement and is planned for v0.6.0 alongside
`mrv.audit.write_trail`. Importing `mrv.audit` today returns a stub that raises
`NotImplementedError` with a pointer to the v0.5.x model-risk report path.

## Research

Based on the following PhD research:

- Zheng, Low & Wang (2026). *Regime Labels Are Not Representation-Invariant* (Paper 1). Submitted to Finance Research Letters.
- Zheng, Low & Wang (2026). *Regime Labels Are Not Resolution-Invariant* (Paper 2). Provisional accept at Finance Research Letters.
- Zheng (2026). *Inference Collapse Theory I: Theoretical Ceiling* (Paper 3a). Working paper.
- Zheng (2026). *Model Risk Index* (Paper 4a). Working paper.

## License

Dual-licensed.

- **Open source:** GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later). See [LICENSE](LICENSE). Free for academic research, teaching, and personal use. Note that the AGPL's network-use clause requires any modified version offered over a network to also offer its complete source.
- **Commercial:** Organizations that wish to use mrv-lib in proprietary or closed-source systems, or otherwise cannot meet the AGPL obligations, require a separate commercial license. See [COMMERCIAL-LICENSE.md](COMMERCIAL-LICENSE.md).

## Maintainers

[ModelGuard Lab](https://github.com/modelguard-lab) -- Author: Kai Zheng.
