You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
PrepaymentABS: SMM can exceed 1 before exhaustion, over-reporting prepayment vs outstanding balance #358
Context — the PrepaymentABS feature from PR #322 (#323). The crash and negative-SMM failure modes at/after the implied balance-exhaustion month are fixed in src/Asset.hs (smm now returns 0 when 1 - r*(m-1) <= 0).
Residual issue — before exhaustion, SMM(m) = r / (1 - r*(m-1)) can exceed 1:
r = 6%, m = 17 → 1.5 (150% of the outstanding balance in one month)
r = 2%, m = 50 → 1.0
In general, the month just before exhaustion (m = floor(1/r) + 1) already yields SMM >= 1; any projection that runs to ~1/r months (e.g. a 30-year monthly schedule with r >= ~0.28%/month) enters this region.
Downstream impact — the rate is applied without clamping the amount:
same pattern at src/AssetClass/Mortgage.hs:53, :274; src/AssetClass/Loan.hs:51; src/AssetClass/Installment.hs:55
The balance is clamped (intBal = max 0 (begBal - newDefault - newPrepay)), but the recorded newPrepay row can exceed begBal - newDefault — i.e. reported prepayments exceed the outstanding balance, row identities (begin balance vs outflows) stop tying, and pool aggregations over-report prepayments.
Suggested fixes (decision needed)
(recommended) Clamp the amount at the application sites: newPrepay = min (begBal - newDefault) (mulBR (max 0 (begBal - newDefault)) ppyRate) — preserves the modeled rate, keeps row identities consistent, and applies uniformly to every prepayment source.
Clamp the rate to min 1 inside smm — simpler, but changes the ABS model semantics (the final months effectively prepay 100% of the remaining balance).
Reject rate/horizon combinations that cross exhaustion with a descriptive Left — consistent with the other buildPrepayRates validations, but reduces usability.
Acceptance criteria
With PrepaymentABS 6%, month age 17: newPrepay <= begBal - newDefault, and the row satisfies begBal = endBal + principal + prepayment + default.
A unit test pinning the chosen semantics (Mortgage/Loan/Installment projection).
References — PR #322, review finding H1; issue #323 (feature); the exhaustion fix in src/Asset.hs.
Activity
yellowbean commentedon Oct 17, 2026
The issue is , when
defaulthappens, the schedule prepayment shall beshrinkas well as planned.