Tier 1 · Gaap Ifrs Financial Reporting

CECL Bond Loss Model

M-040 · lifecycle: monitoring · RAT-040-v1.0.2 (conditional)

Intended Use

CECL Bond Loss Model Estimate lifetime expected credit losses on the bond portfolio for ASC 326 financial reporting.

Per §12.2 worked example. PD-LGD-EAD framework with vendor PD inputs from Moody's. Sensitivity primarily to PD/LGD inputs and scenario stress overlays.


Components

Inputs, processing, outputs

data sources
DS-021 · DS-022
assumptions
A-030, A-031, A-090
engines
finview.L3.cecl_calculator
finview.L0.credit_data
contracts
cecl_results_v1
dimensions
D2

Methodology & Mechanics

Methodology

M-040 implements the ASC 326 Current Expected Credit Loss (CECL) standard for the fixed-income (bond) portfolio. CECL replaced the prior incurred-loss model with a lifetime expected-loss measure: at every reporting date the allowance equals the credit losses expected over the entire remaining contractual life of each instrument, recognized up front rather than when a loss event becomes probable.

The engine is FinView-resident (cross-repo): the implementation is finlib.cecl.CECLCalculator (governance id finview.L3.cecl_calculator) in [redacted], consuming the credit-parameter library finlib.credit_data (governance id finview.L0.credit_data). The CECL allowance it produces is consumed by the insurance capital/reserve stack (the bond-portfolio expected-loss feeds invested-asset impairment and capital adequacy), but the source code does not live in InsModel — see Limitation 1.

The model uses a discounted-cash-flow loss method built on a PD × LGD × EAD decomposition rendered period-by-period (ASC 326-20-30-4 permits a DCF method; the period losses are PV-discounted at the instrument's effective interest rate):

  1. Government/agency carve-out. Instruments rated AAA/AA+ and in sector Government/Agency are assigned zero ECL (_is_government_bond), reflecting the ASC 326 practical recognition that US sovereign/agency exposures carry no expected credit loss.

  2. LGD (loss given default). LGD = 1 − recovery_rate. Recovery defaults by seniority/sector from RECOVERY_RATES: senior-secured 0.65, senior-unsecured 0.45 (the corporate-bond default), subordinated 0.25, government/agency 0.90. A generic BBB corporate is therefore LGD = 0.55.

  3. PD / hazard rate. With pd_source='moody', get_counterparty_pd maps the S&P-scale rating to its Moody's equivalent (BBB → Baa) and reads the Moody's published cumulative-default table MOODY_CUMULATIVE_PD (1y/3y/5y/10y), interpolating to the bond's maturity. A continuous hazard rate is backed out as λ = −ln(1 − PD_cum) / T. With pd_source='oas' the hazard is instead derived from live FRED/OAS spreads (λ = spread / (1 − recovery)); the snapshot uses the deterministic Moody's path so no live data is touched.

  4. Stress multiplier. The hazard is scaled by a scenario factor from PD_MULTIPLIERS (base 1.0, mild 1.5, stress 2.0, severe 3.0) before cash-flow generation, giving CCAR-style scenario sensitivity.

  5. Cash-flow loss schedule (EAD). BondCashflows.generate_schedule(hazard_rate, recovery_rate) produces a period-by-period schedule carrying default_amount and recovery per coupon period (semiannual by default). The period loss is default_amount − recovery, and each is PV-discounted at the effective interest rate (the coupon rate as the ASC 326 EIR proxy): pv_loss = loss / (1 + r)^t.

  6. Lifetime ECL & allowance. lifetime_ecl = Σ pv_loss over all periods to maturity; ecl_rate = lifetime_ecl / face_value. At portfolio level compute_portfolio_ecl sums per-bond ECL and rolls it up ecl_by_rating and ecl_by_sector. The lifetime ECL is the CECL allowance.


Key Assumptions

Key Assumptions and Their Justification

ID Assumption Value / source Justification
K-1 PD source Moody's published cumulative default rates (MOODY_CUMULATIVE_PD, 1y/3y/5y/10y by Aaa…Caa) Industry-standard rating-agency default experience (Moody's Annual Default Study, 1970–2023); transparent, auditable, no live-data dependency. See Q-07 / Limitation 4.
K-2 Rating crosswalk S&P scale → Moody's (_SP_TO_MOODY); 14 notches collapse to 7 Moody's buckets Lets a single S&P-scale portfolio feed Moody's tables; BBB→Baa, A→A, etc. Loses sub-notch granularity (Limitation 3).
K-3 LGD / recovery 1 − recovery; recovery by seniority: sr-secured 0.65, sr-unsecured 0.45, sub 0.25, gov/agency 0.90 Standard market recovery assumptions; senior-unsecured 0.45 is the long-run corporate average. Static, not name-specific (Limitation 2).
K-4 Discount rate (EIR) Effective interest rate ≈ coupon rate (fallback 5%) ASC 326-20-30 requires DCF losses discounted at the instrument's EIR; coupon is the available proxy in the canonical input (Limitation 5).
K-5 Reasonable-and-supportable horizon Full contractual life (to maturity) CECL is a lifetime measure; the model projects period losses over the entire remaining life rather than a truncated R&S window.
K-6 Reversion to historical Implicit — Moody's long-run average PDs are the through-the-cycle mean ASC 326 requires reversion to historical loss experience beyond the R&S horizon; using through-the-cycle Moody's averages means the model is effectively at the reverted mean already (Limitation 6).
K-7 Government/agency ECL Zero for AAA/AA+ Government/Agency US sovereign/agency exposures are treated as carrying no expected credit loss under ASC 326 practical application.
K-8 Scenario stress Hazard × {1.0, 1.5, 2.0, 3.0} Multiplicative hazard stress provides base/mild/stress/severe scenarios for CCAR-style sensitivity without re-sourcing PDs.

Prose. The two load-bearing assumptions are the PD table (K-1) and LGD (K-3). The Moody's cumulative-default table is the spine of the lifetime measure: PD at maturity is interpolated from the four published tenor points (e.g. Baa 10y = 3.27%) and converted to a continuous hazard. Because these are through-the-cycle averages, the model satisfies CECL's reversion requirement (K-6) almost by construction — there is no explicit R&S-then-revert two-segment curve; the single Moody's curve is already the long-run mean. The reasonable-and-supportable horizon (K-5) is the full contractual life rather than the more common 1–2 year R&S window, which is conservative and avoids a reversion-segment modeling choice but reduces sensitivity to near-term macro forecasts. LGD is seniority-bucketed, not name-level — a known simplification (Limitation 2).


Output Snapshot

Output Snapshot

Deterministic run of CECLCalculator (finview.L3.cecl_calculator, FinView) — reproducible, requires no live firm data (BV-032 immune); Moody's published PD table, base scenario, no FRED/OAS live spreads. Reproduce with python scripts/model_snapshots.py M-040; the underlying engine is asserted by FinView tests/test_cecl.py (6 tests, all passing — test_bbb_10y_ecl_reasonable bounds this exact BBB 10Y bond's ECL to (5k, 30k) and asserts LGD = 0.55).

Input: canonical 2-bond portfolio — UST $1M par · 4.00% cpn · 10y · AAA/Government (zero-ECL) + BBB corporate $1M par · 5.25% cpn · 10y · senior-unsecured.

output value meaning
par / amortized cost (BBB bond) 1,000,000.00 exposure at default (EAD) basis
pd_cumulative (10y, Moody's Baa) 0.0327 lifetime cumulative default probability
lgd (1 − recovery, sr unsecured) 0.55 loss given default
hazard_rate (λ, base) 0.00332 continuous default intensity backed from PD
ecl_rate (lifetime_ecl / par) 0.0134 lifetime ECL as % of par
lifetime_ecl (BBB allowance) 13,387.20 CECL lifetime expected credit loss, PV-discounted
ecl AAA/Government (zero-ECL rule) 0.00 government carve-out applied
total_ecl (portfolio allowance) 13,387.20 portfolio CECL allowance
ecl_rate (portfolio) 0.0067 portfolio allowance / $2M total par

The undiscounted PD×LGD×EAD product for the BBB bond is 0.0327 × 0.55 × $1M ≈ $17,985; the reported $13,387 is lower because losses are spread across 20 semiannual periods and PV-discounted at the 5.25% EIR — exactly the ASC 326 DCF mechanic. The Treasury contributes zero by the government carve-out, so the portfolio allowance equals the single corporate ECL.

Captured 2026-06-04 · deterministic, no live data.


Limitations

Limitations and Known Gaps

  1. Cross-repo FinView ownership. The engine is FinView-resident (finlib.cecl.CECLCalculator, finview.L3.cecl_calculator), not InsModel. The insurance capital/reserve stack consumes its CECL allowance but does not own the code, version, or test suite. Governance crosses a repo boundary; any change-control, MRM ratification, and registry binding for M-040 must reference FinView artifacts, and the model card's authority over the implementation is by reference only.

  2. LGD is seniority-bucketed, not name-level. Recovery is a static lookup by seniority/sector (RECOVERY_RATES), not calibrated per issuer, vintage, or collateral. Senior-unsecured 0.45 is a long-run market average; idiosyncratic recovery dispersion is not captured.

  3. 14 S&P notches collapse to 7 Moody's buckets. The _SP_TO_MOODY crosswalk maps e.g. BBB+/BBB/BBB- all to Baa, so sub-notch credit differentiation is lost in the Moody's PD path. (The OAS path preserves notch detail via interpolation, but the deterministic snapshot uses Moody's.)

  4. Q-07 — Moody's PD is vendor data, not a promoted vendor model. The cumulative-default table is hard-coded vendor data in finlib.credit_data.MOODY_CUMULATIVE_PD. It has not been promoted through the vendor-model governance process (no vendor-model registry entry, no independent validation packet, no provenance/version pin to a specific Moody's Annual Default Study release). It is consumed as a constant. This is an open governance gap (Q-07).

  5. EIR proxied by coupon rate. ASC 326 requires DCF discounting at the instrument's effective interest rate; the engine uses the coupon rate (fallback 5%) as the EIR proxy. For bonds bought at a material premium/discount to par the true EIR diverges from the coupon, biasing the PV of losses.

  6. No explicit reasonable-and-supportable / reversion segmentation. CECL contemplates a forecast-based R&S horizon that reverts to historical experience. The model uses through-the-cycle Moody's averages over the full life — effectively "reverted everywhere." This is defensible but means near-term macro forecasts and a documented reversion technique are absent; the scenario multiplier (K-8) is the only forward-looking lever.

  7. No 10-K / live-firm validation. The snapshot is a deterministic engine demonstration on a canonical synthetic portfolio. No claim is made that these figures reconcile to any issuer's 10-K disclosed CECL allowance (BV-032 firm-data divergence is avoided by not using live data).

  8. Mid-period timing / amortization simplifications. BondCashflows recognizes default and recovery at period end (not mid-period) and the canonical input is a bullet (amortization='bullet'); amortizing or prepaying (CPR) structures are supported by the engine but not exercised in the canonical snapshot.


Validation Evidence

Validation Packet

Check Where Evidence
BBB 10Y ECL in reasonable band FinView tests/test_cecl.py::test_bbb_10y_ecl_reasonable asserts 5,000 < lifetime_ecl < 30,000 and lgd == 0.55 (snapshot: 13,387.20 / 0.55) ✓
Government bond zero-ECL test_government_bond_zero_ecl AAA/Government → lifetime_ecl == 0.0, ecl_rate == 0.0 ✓
Stress monotonicity test_stress_increases_ecl stress-scenario ECL > base-scenario ECL ✓
Rating monotonicity test_higher_rating_lower_ecl A-rated ECL < BBB ECL ✓
Portfolio additivity test_portfolio_ecl total_ecl = Σ bond ECL; AAA bucket 0, BBB bucket > 0; 2 bond_detail rows ✓
OAS PD path test_oas_pd_source live_spreads → positive ECL and hazard_rate ✓
Deterministic snapshot scripts/model_snapshots.py M-040 reproduces table above with no live data ✓
Full CECL suite pytest tests/test_cecl.py 6 passed ✓

Sanity invariant: PV-discounted lifetime ECL ($13,387) < undiscounted PD×LGD×EAD ($17,985), consistent with ASC 326 DCF discounting over the bond's life.

Aggregate-risk view (per MRM §10.5 item 8): the CECL allowance is consumed downstream by the insurance capital/reserve stack (invested-asset impairment / capital adequacy). M-040 shares upstream component-model families M-130 (bond pricing) and M-133 (credit-pricing hazard-rate) with M-052 (Counterparty Concentration & Network Risk) per model_registry.yaml — so a change in those shared pricing/credit-spread components propagates to both the CECL allowance here and counterparty exposure in M-052. (The finview.L0.credit_data engine itself is bound to M-040 only.)

Open MRM items: Q-07 (Moody's PD vendor-data promotion) and Limitation 1 (cross-repo FinView ownership / change-control binding) are unresolved and should be tracked as governance issues. A full validation evidence pack with outcomes back-testing of the CECL allowance vs realized credit losses (COND-001 / RAT-040), independent effective-challenge / ratification closure (RAT-040 → approved), Q-07 vendor-model promotion, and the INV-032 packaged-interface / CI drift gate for the FinView-resident engines are gated modeling/governance items tracked for ratification — out of scope for this documentation pass.


References

References

Regulatory / accounting: - FASB ASC 326 (CECL) — Financial Instruments — Credit Losses; ASC 326-20 (measurement of expected credit losses on amortized-cost assets), 326-20-30 (DCF method, discount at effective interest rate). - ASU 2016-13 — the standard that introduced CECL.

Vendor data: - Moody's Annual Default Study (1970–2023) — cumulative default rates by rating and the 1-year transition matrix, encoded in finlib.credit_data.MOODY_CUMULATIVE_PD / MOODY_TRANSITION_MATRIX. (Vendor data, not a promoted vendor model — Q-07.)

Engine source (FinView-resident, cross-repo): - [redacted]CECLCalculator (finview.L3.cecl_calculator): compute_bond_ecl, compute_portfolio_ecl. - [redacted]finview.L0.credit_data: MOODY_CUMULATIVE_PD, RECOVERY_RATES, _SP_TO_MOODY, get_counterparty_pd, _pd_from_moody, _pd_from_oas. - [redacted]BondCashflows.generate_schedule (period-by-period default/recovery cash-flow loss schedule).

Tests: - [redacted] — 6 tests (government zero-ECL, BBB band, stress monotonicity, portfolio additivity, OAS path, rating monotonicity).

Internal: - BV-032 — firm-data divergence (avoided here by deterministic, no-live-data snapshot). - Q-07 — Moody's PD as vendor data not yet promoted to a governed vendor model.


Change Log

Change Log

Card change history. Code-side change history lives in git log of the component files.

  • 2026-05-08 — stub created from registry data per Decision 023 Phase 5 / B-07.
  • 2026-05/06 — Tier-1 hand-authoring of Methodology, Key Assumptions and Their Justification, Output Snapshot, Limitations and Known Gaps, Validation Packet, and References from the FinView CECL engine code (finlib/cecl.py, finlib/credit_data.py, finlib/bond_cashflows.py) + the deterministic model_snapshots.py M-040 run. Stub marker advanced to ``.
  • 2026-06-06 — documentation pass: added Standards Coverage (ASC 326-20 / 326-20-30-4, ASOP 56, PCAOB AS 2501 mapped to the engine) and Dependencies (no upstream M-NNN models; relies on finview.L3.cecl_calculator + finview.L0.credit_data; shares M-130 / M-133 component families with M-052; allowance consumed by the capital/reserve stack) sections, and an Aggregate-risk view note (§10.5 item 8). Doc-currency baseline confirmed: stamp present (model_doc_stamps.yaml), status current, fingerprint 39e093d0aca90fe6, no identity/currency drift. Registry-grounded only; no model outputs changed.

2L Inventory Review

Open findings (2)

Independent 2nd-line review (INV-2026-06) — implemented capability vs registered scope. Each carries a recommended fix and is tracked in insightalm-mrm until closed.

HIGH INV-029 · P5 · validation-gap

Validation evidence + change logs missing across most of the inventory

Only M-001/M-020/M-050 carried full documentation packs before this pass. Most models record validation_evidence: missing and change_log: missing with peer_review: pending. Gold tests freeze behaviour but many assert only structural invariants (e.g. reserve>0), not correctness against external truth. The flagship T0-vs-10-K match is circular (BV-032).

Recommendation: For each Tier-1 model: produce a validation-evidence pack (back-test vs disclosed results once BV-032 re-calibration lands, sensitivity suite, challenger comparison), a change log, and a 2L ratification. Sequence behind BV-032 (firm-data) for anything needing 10-K reconciliation.

LOW INV-032 · cross-repo · cross-repo

FinView-resident pricing/CECL engines reached cross-repo with no drift gate

M-040 (CECL) and M-130-137 (asset pricing) are FinView-resident, consumed by InsModel only via sys.path insertion. No packaged interface or drift gate — a finlib signature change silently breaks the InsModel snapshot harness / consumers.

Recommendation: Define a packaged interface (or a versioned contract) for the FinView pricing library and a CI drift gate, so cross-repo consumers fail loudly on signature change. Tie to D041 ownership.


Validation Coverage

Per-tier expectations

Per MRM Framework §10.2 + §10.3, this model's regulatory_frameworks tag list activates the following overlays:

asop_56 asc_326 sr_26_2 pcaob_as_2501 internal
component tier-1 expectation status
Registry entry required present
Model card (§10.5 doc pack) required present
Validation evidence required present
Change log required present
Independent effective challenge (2L) required pending

Ratification

Conditionally approved — RAT-040-v1.0.2

2L issued RAT-040-v1.0.2 with the following conditions outstanding. Bridge audit Rule 2 treats this as a WARN; the model can remain in monitoring with the conditions on record.

id deadline condition
COND-003 2026-08-23 The M-040 validation evidence pack is structurally complete and real, but one §10.5 item-5 sub-requirement is honestly disclosed as PENDING: a backtest of the CECL allowance against a realized-credit-loss outcome (or a disclosed-issuer CECL allowance), which §10.5 expects "annual or each reporting period." No such reconciliation dataset yet exists on the platform (deliberately avoided to keep the deterministic snapshot BV-032-immune), so the sub-item is intentionally absent rather than synthesized — see pack §4 and card Limitation 7. The backtest_results.yaml 'covered' label (BT-005..007) was independently verified to be a DFAST scenario-stress plausibility check, NOT a realized-outcome reconciliation, and does NOT clear this condition. For a Tier-1 model this is an adequacy gap in validation evidence; per charter §4.2 the model is held at conditionally_approved until a realized-loss / disclosed-allowance reconciliation is sourced and a back-test run is added (within tolerance, or with the residual explained).