# Credit Risk Modeling

Orxaq models credit risk causally. Instead of fitting a logistic regression on a feature matrix, it fits a PD model along the causal paths in the World DAG. This enables interventional queries ("what happens to PD if unemployment rises 2%?") and counterfactual analysis.

## The Credit Ontology

Orxaq ships with a 19-variable credit ontology covering:

- **Macroeconomic** — GDP growth, unemployment rate, interest rates, housing price index
- **Borrower** — Income, credit score, debt-to-income ratio, employment length
- **Loan** — Loan amount, loan-to-value ratio, loan age
- **Performance** — Delinquency status, default flag

```bash
orxaq credit ontology --show
```

## Computing Expected Credit Loss

The CECL engine computes lifetime expected credit loss by propagating PD estimates through the DAG with dynamic forecast horizons:

```bash
orxaq credit ecl
```

Output includes total ECL, per-segment breakdown, horizon (in quarters), and confidence bands.

## Stress Testing

Run CCAR/DFAST-compliant stress tests with predefined scenarios:

```bash
orxaq --json credit ecl
```

The scenario engine applies baseline, adverse, and severely adverse shocks to macroeconomic nodes and propagates effects through the DAG to compute stressed PD.

## Fair Lending

Decompose the effect of a protected attribute (e.g., age) into direct and indirect causal channels:

```bash
orxaq credit fairness --protected age
```

Direct effects flow from the protected attribute straight to the outcome. Indirect effects pass through mediators. If indirect effects flow only through legitimate mediators (e.g., employment history), they are permissible. If they bypass legitimate channels, they indicate potential discrimination.

## Try It: Full Pipeline

```python
from orxaq.orchestration.integration import OrxaqEngine

engine = OrxaqEngine()
engine.load_credit_ontology()
data = engine.generate_synthetic(n=500, seed=42)
engine.fit_pd_model(data)

ecl = engine.compute_ecl(data)
print(f"Total ECL: {ecl['total_ecl']:.4f}")

stress = engine.stress_test(data, scenario="severely_adverse")
print(f"Baseline PD: {stress['base_pd']:.4f}")
print(f"Stressed PD: {stress['stress_pd']:.4f}")
```
