Production-grade open-source credit risk analytics: Basel III/CRR3 RWA, IFRS 9/CECL ECL (including revolving credit and governance overlays), IRB modeling, FR 2052a liquidity reporting, and model validation
Project description
CreditRiskEngine
Production-grade open-source credit risk analytics library.
The scikit-learn of credit risk.
Features
- RWA Calculation -- Basel III/IV Standardized Approach and IRB (F-IRB / A-IRB) with output floor phase-in, double default (CRE32), and equity IRB (CRE33)
- ECL Engines -- IFRS 9, US CECL (ASC 326), and Ind AS 109 with staging, SICR, lifetime PD, scenario weighting, management overlays (post-model adjustments), and revolving credit ECL (credit cards, overdrafts, HELOCs, corporate revolvers) with behavioral life, multi-approach CCF, drawn/undrawn split, and multi-jurisdiction provision floors
- ECL Governance Layer -- Management overlay framework (7 overlay types with approval/expiry/rationale tracking per EBA/GL/2020/06), scenario governance with sensitivity analysis (IFRS 9.B5.5.41-43), multi-variable satellite models with logistic/log link functions and mean-reversion (IFRS 9.B5.5.50), LGD macro overlays, CECL Q-factor governance with per-category caps (OCC 2020-49), and overlay audit trail with JSON export
- PD / LGD / EAD Modeling -- Scorecard development, calibration (anchor-point & Bayesian), TTC-to-PIT conversion, term structures, Merton structural model, Altman Z-score, and transition matrix estimation
- Model Validation -- Discrimination (AUROC, Gini, KS, IV), calibration (binomial, Hosmer-Lemeshow, traffic-light), stability (PSI, CSI, migration)
- Portfolio Risk -- Vasicek ASRF, Gaussian copula Monte Carlo, parametric VaR, economic capital, and stress testing (including reverse stress)
- Concentration Risk -- Single-name, sector-level, and granularity adjustment analytics
- Capital Adequacy -- Capital buffers (CConB, CCyB, G-SIB/D-SIB), leverage ratio (CRE80), and MDA framework
- CVA Risk -- BA-CVA (CVA25) and SA-CVA delta risk charge (CVA26) with supervisory parameters
- Market Risk -- FRTB credit spread SbM (MAR21), Default Risk Charge (MAR22), and RRAO (MAR23)
- Securitisation -- SEC-SA, SEC-ERBA, and SEC-IRBA per CRE40-45
- Operational Risk -- Standardised Measurement Approach (SMA) per OPE25
- Credit Risk Mitigation -- Comprehensive and simple approaches, haircut framework per CRE22
- Multi-Jurisdiction -- EU CRR3, UK PRA, US Basel III Endgame, India RBI (full IRAC norms with SMA/NPA classification, provisioning floors, and restructured account handling), Singapore MAS, Hong Kong HKMA, Japan JFSA, Australia APRA, Canada OSFI, Saudi Arabia SAMA, and BCBS baseline
- Regulatory Reporting -- COREP, Pillar 3 disclosure templates (CR1/CR3/CR4/CR6), FR Y-14 (CCAR), FR 2052a (Complex Institution Liquidity Monitoring), and model inventory
- Stress Testing -- EBA, BoE ACS, US CCAR/DFAST, RBI frameworks, and reverse stress testing
Installation
pip install creditriskengine
From source
git clone https://github.com/ankitjha67/baselkit.git
cd baselkit
pip install -e ".[dev]"
Requires Python 3.11+.
Quick Start
IRB Risk Weight
from creditriskengine.rwa.irb.formulas import irb_risk_weight
# Corporate exposure: PD=1%, LGD=45%, maturity=2.5y
rw = irb_risk_weight(pd=0.01, lgd=0.45, asset_class="corporate", maturity=2.5)
print(f"Risk Weight: {rw:.2f}%")
Standardized Approach
from creditriskengine.rwa.standardized.credit_risk_sa import assign_sa_risk_weight
from creditriskengine.core.types import SAExposureClass, CreditQualityStep, Jurisdiction
rw = assign_sa_risk_weight(
exposure_class=SAExposureClass.CORPORATE,
cqs=CreditQualityStep.CQS_2,
jurisdiction=Jurisdiction.EU,
)
print(f"SA Risk Weight: {rw:.0f}%")
IFRS 9 ECL
from creditriskengine.ecl.ifrs9.ecl_calc import calculate_ecl
from creditriskengine.core.types import IFRS9Stage
ecl = calculate_ecl(
stage=IFRS9Stage.STAGE_1,
pd_12m=0.02,
lgd=0.40,
ead=1_000_000,
eir=0.05,
)
print(f"12-month ECL: {ecl:,.2f}")
PD Scorecard
from creditriskengine.models.pd.scorecard import scorecard_to_pd, assign_rating_grade, build_master_scale
import numpy as np
scores = np.array([537, 587, 640, 706])
pds = scorecard_to_pd(scores) # Convert scorecard points to PD
master_scale = build_master_scale([0.0003, 0.001, 0.005, 0.01, 0.02, 0.05, 0.10, 0.20, 1.0])
grades = [assign_rating_grade(pd, master_scale) for pd in pds]
# grades: ['Grade_7', 'Grade_5', 'Grade_2', 'Grade_1']
print(f"PDs: {pds}")
print(f"Grades: {grades}")
Model Validation
from creditriskengine.validation.discrimination import auroc, gini_coefficient, ks_statistic
import numpy as np
y_true = np.array([0, 0, 1, 0, 1, 1, 0, 0, 1, 0])
y_score = np.array([0.1, 0.2, 0.7, 0.3, 0.8, 0.6, 0.2, 0.15, 0.9, 0.05])
print(f"AUROC: {auroc(y_true, y_score):.4f}")
print(f"Gini: {gini_coefficient(y_true, y_score):.4f}")
print(f"KS: {ks_statistic(y_true, y_score):.4f}")
Revolving Credit ECL (Credit Card)
from creditriskengine.ecl.ifrs9.revolving import (
calculate_revolving_ecl, regulatory_ccf_sa,
RevolvingProductType, determine_behavioral_life,
)
from creditriskengine.core.types import IFRS9Stage
import numpy as np
# Credit card: $10K limit, $6K drawn, $4K undrawn
life = determine_behavioral_life(product_type=RevolvingProductType.CREDIT_CARD)
ccf = 0.80 # Behavioral CCF (regulatory SA = 10%, but IFRS 9 uses PIT)
marginal_pds = np.full(life, 0.0025) # ~3% annual PD
result = calculate_revolving_ecl(
stage=IFRS9Stage.STAGE_2, drawn=6000, undrawn=4000, ccf=ccf,
pd_12m=0.03, lgd=0.85, eir=0.015,
marginal_pds=marginal_pds, behavioral_life_months=life,
)
print(f"Total ECL: ${result.total_ecl:,.2f}")
print(f" Drawn (loss allowance): ${result.ecl_drawn:,.2f}")
print(f" Undrawn (provision): ${result.ecl_undrawn:,.2f}")
ECL Governance: Management Overlays & Scenario Sensitivity
from creditriskengine.ecl.ifrs9.overlays import (
ManagementOverlay, OverlayType, apply_overlays, validate_overlay,
)
from creditriskengine.ecl.ifrs9.scenarios import (
Scenario, ScenarioSetMetadata, weighted_ecl,
scenario_sensitivity_analysis, validate_scenario_governance,
)
from datetime import datetime, UTC, timedelta
# --- Management Overlays (post-model adjustments) ---
overlay = ManagementOverlay(
name="CRE sector stress",
overlay_type=OverlayType.SECTOR_SPECIFIC,
adjustment_rate=0.15, # +15% uplift on model ECL
rationale="Commercial real estate valuations declining in Q3",
regulatory_basis="IFRS 9.B5.5.52",
approved_by="Credit Risk Committee",
approval_date=datetime.now(UTC),
expiry_date=datetime.now(UTC) + timedelta(days=90),
portfolio_scope="UK CRE Stage 2 exposures",
)
# Validate governance completeness (auditor-ready)
warnings = validate_overlay(overlay) # [] = fully compliant
# Apply overlay to model ECL
result = apply_overlays(model_ecl=1_000_000, overlays=[overlay])
print(f"Model ECL: {result.model_ecl:,.0f}")
print(f"After overlay: {result.overlay_ecl:,.0f} (+{result.total_adjustment:,.0f})")
# --- Scenario Sensitivity Analysis ---
scenarios = [
Scenario("base", 0.50, 500_000),
Scenario("downside", 0.30, 900_000),
Scenario("severe", 0.20, 1_500_000),
]
ecl = weighted_ecl(scenarios) # Probability-weighted ECL
sensitivity = scenario_sensitivity_analysis(scenarios, shift_size=0.10)
print(f"Most sensitive to: {sensitivity.max_sensitivity_scenario}")
print(f" ECL changes {sensitivity.max_sensitivity_pct:.1f}% per 10pp weight shift")
Ind AS 109 with RBI IRAC Norms
from creditriskengine.ecl.ind_as109 import (
classify_irac, irac_to_ifrs9_stage, rbi_minimum_provision,
calculate_ecl_ind_as, IRACAssetClass,
)
from creditriskengine.core.types import IFRS9Stage
import numpy as np
# Classify per RBI IRAC norms
irac = classify_irac(days_past_due=95, months_as_npa=3)
print(f"IRAC class: {irac.value}") # "substandard"
stage = irac_to_ifrs9_stage(irac) # Stage 3
# RBI minimum provision (15% for secured substandard)
rbi_floor = rbi_minimum_provision(ead=1_000_000, irac_class=irac, is_secured=True)
print(f"RBI floor: {rbi_floor:,.0f}") # 150,000
# ECL with RBI provisioning floor (higher of model ECL and RBI floor)
ecl = calculate_ecl_ind_as(
stage=stage, pd_12m=0.10, lgd=0.45, ead=1_000_000,
marginal_pds=np.array([0.10, 0.08]),
irac_class=irac, is_secured=True,
)
print(f"ECL (with RBI floor): {ecl:,.0f}")
FR 2052a Liquidity Report
from creditriskengine.reporting.fr2052a import (
InflowAssetRecord, OutflowDepositRecord,
build_submission, validate_submission, generate_summary,
AssetCategory, CounterpartyType, InsuredType,
MaturityBucket, ReporterCategory,
)
# Build records for each schedule
records = [
InflowAssetRecord(
reporting_entity="MegaBank", as_of_date="2024-06-30",
product_id=1, # Unencumbered Assets
maturity_bucket=MaturityBucket.OPEN,
maturity_amount=5000.0,
collateral_class=AssetCategory.A_1_Q, # US Treasury
market_value=5000.0, treasury_control=True,
),
OutflowDepositRecord(
reporting_entity="MegaBank", as_of_date="2024-06-30",
product_id=1, # Transactional Accounts
maturity_bucket=MaturityBucket.OPEN,
maturity_amount=3000.0,
counterparty=CounterpartyType.RETAIL,
insured=InsuredType.FDIC,
),
]
# Validate and generate summary
result = validate_submission(records, reporting_entity="MegaBank")
print(f"Valid: {result.is_valid}")
submission = build_submission(
"MegaBank", "2024-06-30", ReporterCategory.CATEGORY_I, records
)
summary = generate_summary(submission)
print(f"Net liquidity: {summary['net_liquidity_position']:,.0f}M")
# Net liquidity: 2,000M
Project Structure
src/creditriskengine/
core/ # Exposure model, portfolio container, enums, audit trail, logging
regulatory/ # Jurisdiction YAML configs (17 jurisdictions) and loader
rwa/
standardized/ # SA risk weight tables (CRE20)
irb/ # IRB formulas (CRE31) -- correlation, K, RW
output_floor.py # Output floor phase-in by jurisdiction
capital_buffers.py # CConB, CCyB, G-SIB/D-SIB, MDA (RBC40)
leverage_ratio.py # Basel III leverage ratio (CRE80)
cva.py # BA-CVA (CVA25) and SA-CVA (CVA26) capital charges
market_risk.py # FRTB SbM, DRC, RRAO (MAR21-23)
securitisation.py # SEC-SA, SEC-ERBA, SEC-IRBA (CRE40-45)
operational_risk.py # Standardised Measurement Approach (OPE25)
crm.py # Credit risk mitigation, haircuts (CRE22)
ecl/
ifrs9/ # Staging, SICR, lifetime PD, scenarios, TTC-to-PIT, ECL calc
revolving/ # Revolving credit ECL: behavioral life, CCF, drawn/undrawn split, provision floors
overlays.py # Management overlay / PMA framework (7 types, governance, audit)
forward_looking.py # Satellite models, mean-reversion, LGD macro overlay
scenarios.py # Probability-weighted ECL, governance metadata, sensitivity analysis
cecl/ # PD*LGD, loss-rate, vintage, DCF, Q-factors with governance caps
ind_as109/ # Ind AS 109 with full RBI IRAC norms (SMA/NPA classification, provisioning)
models/
pd/ # Scorecard, calibration, master scale, Vasicek PD, Merton, Z-score, transition matrices
lgd/ # Workout LGD, downturn LGD, term structure, floors, cure rate
ead/ # CCF estimation, supervisory CCF, EAD term structure
concentration/ # Single-name, sector, granularity adjustment
portfolio/ # Copula simulation, VaR, economic capital, stress testing, Vasicek ASRF
validation/ # Discrimination, calibration, stability, backtesting, benchmarking
reporting/ # COREP, Pillar 3 (CR1/CR3/CR4/CR6), FR Y-14 (CCAR), model inventory
fr2052a/ # FR 2052a Complex Institution Liquidity Monitoring (OMB 7100-0361)
Testing
# Run full test suite
pytest
# Quick run without coverage
pytest -q --no-cov
# Specific module
pytest tests/test_rwa/ -v
2,068 tests across all modules with 100% line coverage. Type-checked with mypy --strict and linted with ruff.
Performance
Benchmarked on a single core (run python benchmarks/bench_portfolio.py):
| Operation | Throughput |
|---|---|
| IRB risk weight (single) | ~100k calc/sec |
| IRB portfolio (10k exposures) | ~10k exp/sec |
| SA risk weight (10k exposures) | ~100k exp/sec |
| IFRS 9 ECL (10k calculations) | ~100k calc/sec |
| Stress test (10k × 3yr) | < 0.01s |
| Monte Carlo (10k × 10k sims) | < 2s |
Dependencies
| Package | Version | Purpose |
|---|---|---|
| NumPy | ≥1.26, <3.0 | Numerical computation |
| SciPy | ≥1.12, <2.0 | Statistical distributions (norm CDF/PPF) |
| pandas | ≥2.2, <3.0 | Data manipulation and audit trail export |
| Pydantic | ≥2.6, <3.0 | Data validation and exposure model |
| PyYAML | ≥6.0.1, <7.0 | Regulatory configuration loading |
| scikit-learn | ≥1.4, <2.0 | AUC, logistic regression, model validation |
| statsmodels | ≥0.14, <1.0 | Statistical tests for calibration |
| Jinja2 | ≥3.1, <4.0 | Regulatory report templating |
Documentation
Build and serve the docs locally:
pip install -e ".[docs]"
mkdocs serve
Governance
- Regulatory Mapping: Every function traced to its Basel/IFRS paragraph (185+ mappings)
- Regulatory Disclaimers: Important caveats for production use
- Config Versioning: How regulatory config changes are managed
- Audit Trail:
AuditTrailclass records every calculation with inputs, outputs, timestamps, and regulatory references. Overlay audit records track post-model adjustment lifecycle events (applied, reviewed, revoked, expired) - Management Overlay Governance: Structured PMA framework with approval chain, expiry dates, rationale documentation, and governance validation per EBA/GL/2020/06 and PRA Dear CFO letter (Jul 2020)
- Scenario Governance: Scenario weight approval metadata, review cadence tracking, methodology documentation, and sensitivity analysis per IFRS 9.B5.5.41-43
- Input Validation: Schema validation for YAML configs and sanitization for exposure inputs
Contributing
See CONTRIBUTING.md for full guidelines. Quick start:
git clone https://github.com/ankitjha67/baselkit.git
cd baselkit
pip install -e ".[dev]"
pytest # Run tests
ruff check src/ tests/ # Lint
mypy src/ # Type check
Community Projects
- Basel Risk Dashboard by @adipandey956 — ICAAP stress testing + jurisdiction RWA dashboard with IRB scenarios across BCBS, EU CRR3, UK PRA, and RBI
License
Apache 2.0 -- see LICENSE for details.
Disclaimer: This library is provided for educational and analytical purposes. It has not been reviewed or endorsed by any regulatory authority. See Regulatory Disclaimers for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file creditriskengine-0.6.0.tar.gz.
File metadata
- Download URL: creditriskengine-0.6.0.tar.gz
- Upload date:
- Size: 344.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bcba78479646a3630eba84ffaadb43041e173bd6e445c0bf07d916b449d3bc29
|
|
| MD5 |
ad3bd40bda8e38eeaebf310502c6f79b
|
|
| BLAKE2b-256 |
d37cf110e451e804677723743dedae21962edbab45b950cf364956ed3c4e7b73
|
Provenance
The following attestation bundles were made for creditriskengine-0.6.0.tar.gz:
Publisher:
release.yml on ankitjha67/baselkit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
creditriskengine-0.6.0.tar.gz -
Subject digest:
bcba78479646a3630eba84ffaadb43041e173bd6e445c0bf07d916b449d3bc29 - Sigstore transparency entry: 1224415300
- Sigstore integration time:
-
Permalink:
ankitjha67/baselkit@84f2ac623ecc8915a6bd4eb442390e99138d24b1 -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/ankitjha67
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@84f2ac623ecc8915a6bd4eb442390e99138d24b1 -
Trigger Event:
release
-
Statement type:
File details
Details for the file creditriskengine-0.6.0-py3-none-any.whl.
File metadata
- Download URL: creditriskengine-0.6.0-py3-none-any.whl
- Upload date:
- Size: 274.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b3a94d7a004d9ef7355f6a4d870c1659a9947778a10807e3265e43ce37516e8
|
|
| MD5 |
1b59dd6b994669d72453bee3f6a11772
|
|
| BLAKE2b-256 |
9e791f972208b61f7206a17d5d83ed38ebe91bdc4538ee8cb11bdab687ae7921
|
Provenance
The following attestation bundles were made for creditriskengine-0.6.0-py3-none-any.whl:
Publisher:
release.yml on ankitjha67/baselkit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
creditriskengine-0.6.0-py3-none-any.whl -
Subject digest:
1b3a94d7a004d9ef7355f6a4d870c1659a9947778a10807e3265e43ce37516e8 - Sigstore transparency entry: 1224415359
- Sigstore integration time:
-
Permalink:
ankitjha67/baselkit@84f2ac623ecc8915a6bd4eb442390e99138d24b1 -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/ankitjha67
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@84f2ac623ecc8915a6bd4eb442390e99138d24b1 -
Trigger Event:
release
-
Statement type: