Loan Trajectory Model

Autoregressive transformer with diffusion head for individual loan path generation.


Architecture

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Loan Static Features
    |
    v
Feature Embedding
    |
    +--- Cohort Transitions (from Transition Transformer)
    |
    v
Causal Transformer Decoder
    |
    v
Diffusion Head (for continuous values)
    |
    v
State Head (for discrete states)
    |
    v
Generated Loan Trajectory

Two-Stage Generation

Stage 1: State Sequence

Generate discrete loan states autoregressively:

1
s_t ~ Categorical(f_state(h_t, P_cohort(t)))

Where the state probability combines:

  • Loan-specific hidden state h_t
  • Cohort-level transition matrix P_cohort(t)
  • Idiosyncratic noise

Stage 2: Continuous Values

For each state, generate continuous outcomes via diffusion:

1
x_t ~ Diffusion(mu_t, sigma_t | s_t, loan_features)

Continuous values include:

  • Scheduled payment
  • Actual payment
  • Outstanding balance
  • Loss given default (if default)

Input Features

Feature Type Description
loan_id ID Unique identifier
original_balance Float Initial loan amount
interest_rate Float Contractual rate
rate_type Categorical Fixed/floating
asset_class Categorical Corporate/consumer/RE/AR
ltv_origination Float Loan-to-value at origination
debt_service_coverage Float DSCR for commercial
fico_origination Float Credit score (consumer)
vintage_month Integer Origination cohort

Output Trajectory

For each loan, generates monthly trajectory:

1
2
3
4
5
6
7
trajectory = {
    'state': [0, 0, 0, 1, 1, 0, ...],      # State indices
    'scheduled_payment': [1000, 1000, ...], # Contractual
    'actual_payment': [1000, 800, ...],     # Realized
    'balance': [100000, 99500, ...],        # Outstanding
    'loss': [0, 0, 0, ...],                 # Loss if default
}

Diffusion Head

The continuous values are generated using a score-based diffusion model:

1
2
Forward: x_t = sqrt(alpha_t) * x_0 + sqrt(1-alpha_t) * epsilon
Reverse: x_{t-1} = (x_t - sqrt(1-alpha_t) * score(x_t, t)) / sqrt(alpha_t)

This captures the complex distributions of payment amounts and recovery values.


Configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from privatecredit.models import LoanTrajectoryModel, TrajectoryConfig

config = TrajectoryConfig(
    n_loan_features=24,
    n_states=7,
    d_model=256,
    n_heads=8,
    n_layers=6,
    diffusion_steps=100
)

model = LoanTrajectoryModel(config)

# Generate trajectories
trajectories = model.generate(
    loan_features=loans_tensor,
    cohort_transitions=P_matrices,
    macro_path=macro_tensor,
    n_samples=1000
)

Idiosyncratic vs Systematic Risk

The model captures both:

Risk Type Mechanism
Systematic Cohort transitions from macro path
Idiosyncratic Loan-specific deviation via diffusion

The balance is controlled by the idio_scale parameter:

1
2
3
config = TrajectoryConfig(
    idio_scale=0.3  # 30% idiosyncratic variance
)

State Transition Rules

Hard constraints ensure valid trajectories:

1
2
3
4
- Default, Prepaid, Matured are absorbing states
- Can only cure from 30/60/90 DPD
- Matured only at contractual term end
- Prepaid requires sufficient payment

Back to Architecture