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
|
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 |
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.