Skip to content

Loss Forecasting API Reference

Loss Forecasting

Use this module for baseline portfolio lifetime-loss estimates from a square transition matrix, a transition ledger, or a loan-history panel. Start with forecast_lifetime_loss() and treat the static-matrix result as a baseline; use portfolio simulation or Rollforward when you need dynamic cashflow behavior.

cranalytics.loss_forecasting

Loss forecasting utilities based on transition matrices.

forecast_lifetime_loss(portfolio_df: pd.DataFrame, migration_matrix: pd.DataFrame, lgd: float = 0.5, as_of_date: pd.Timestamp | None = None, amortize: bool = False, cpr: float = 0.0, *, history_state_col: str = 'transition_state', history_strict: bool = False) -> float

Estimate total lifetime loss over the remaining contractual term.

Formula: Loss = Exposure at Default (EAD) * Probability of Default (PD) * LGD.

Parameters:

Name Type Description Default
portfolio_df DataFrame

Loan-level portfolio snapshot validated by PortfolioSchema.

required
migration_matrix DataFrame

Square transition matrix, transition ledger, or loan-history panel used to estimate state migration.

required
lgd float

Loss-given-default assumption as a decimal.

0.5
as_of_date Timestamp | None

Forecast date used to calculate remaining contractual term. Defaults to the current date.

None
amortize bool

Whether to decay exposure using scheduled amortization and CPR.

False
cpr float

Annual constant prepayment rate used when amortize=True.

0.0
history_state_col str

Canonical state column for loan-history input.

'transition_state'
history_strict bool

Whether loan-history normalization should reject warnings.

False

Returns:

Type Description
float

Total estimated lifetime loss in portfolio currency units.

Raises:

Type Description
ValueError

If statuses do not map to the transition state space or an input assumption is invalid.

Examples:

>>> import pandas as pd
>>> from cranalytics import forecast_lifetime_loss
>>> portfolio = pd.DataFrame({
...     "loan_id": ["L1"],
...     "principal": [1000.0],
...     "annual_rate": [0.10],
...     "term_months": [12],
...     "start_date": [pd.Timestamp("2024-01-01")],
...     "status": ["Current"],
...     "fico_score": [700],
... })
>>> states = ["Current", "Charged Off"]
>>> matrix = pd.DataFrame(
...     [[0.98, 0.02], [0.0, 1.0]], index=states, columns=states
... )
>>> loss = forecast_lifetime_loss(
...     portfolio, matrix, as_of_date=pd.Timestamp("2024-01-01")
... )
>>> bool(loss > 0)
True

.. warning:: Oversimplified Model for Baseline Testing Only This function uses a static transition matrix. You may pass that matrix directly, a transition ledger (loan_id, period, status), or a raw/ canonical loan-history panel (loan_id, fund_date, as_of_date) that is converted to a cohort matrix internally. The resulting forecast still assumes the matrix is static and the current principal balance does not amortize or prepay over the remaining term unless amortize=True is specified. Even with amortization, it applies fixed PDs scaled against decaying balances instead of true, time-dependent simulation. For robust, term-adjustable forecasting, please use cranalytics.simulation.simulate_portfolio_cashflows.

summarize_lifetime_loss(portfolio_df: pd.DataFrame, migration_matrix: pd.DataFrame, lgd: float = 0.5, as_of_date: pd.Timestamp | None = None, amortize: bool = False, cpr: float = 0.0, *, history_state_col: str = 'transition_state', history_strict: bool = False) -> dict[str, float]

Return a summary report for lifetime loss forecasting.

forecast_portfolio_states(migration_matrix: pd.DataFrame, initial_states: pd.Series, n_periods: int) -> pd.DataFrame

Project future state distributions using a Markov chain.

.. warning:: Static Matrix Assumption This function assumes transition probabilities are static across time (the Markov Property) and identical for all loans regardless of age (Months on Book) or risk factors (FICO). It should be used as a high-level heuristic or baseline test, not as a primary state forecaster.