Credit: Fannie Mae REMIC with a stripped coupon, at six prepayment speeds
Security Group 3 of a Fannie Mae REMIC: a seasoned mortgage pool passing through to a single class, with the coupon stripped between it and an interest-only class that carries no principal.
Every number below is checked against an independent reference implementation on every commit — period by period, and on each metric, inside a declared tolerance. See benchmark methodology.
The case
Fannie Mae REMIC Trust 2019-2 divides $307,727,958 across three groups. Group 3 is $148,372,434 of Fannie Mae mortgage-backed securities, and its priority of payments is a single line:
The Group 3 Principal Distribution Amount to AB until retired.
Which makes it sound like nothing to model. The interest is where the deal is.
The pool passes through at 5.00%. Class AB takes 3.25% of that, and the remaining 1.75% is sold separately as Class IO — an interest-only class with no principal balance at all, entitled instead to 5.00% of a notional balance set at 35.0000000674% of AB's. The two reconstruct the pass-through rate:
3.25% + 0.350000000674 x 5.00% = 5.00000000337%
An investor in IO owns a slice of a coupon and nothing else. Their position shrinks as AB amortizes, they receive not one dollar of principal, and if the loans prepay quickly they lose most of what they paid.
The reference
The Prospectus Supplement dated 24 January 2019, page S-14, which publishes for
Classes AB and IO the percentage of the original balance outstanding after each
January's distribution for thirty years, at seven prepayment speeds, with a
weighted average life for each. See SOURCE.md.
This case takes the 198% PSA column, the pricing speed.
The same supplement publishes, on pages S-10 and S-11, the pre-tax yield of Class IO at an assumed price of 19.25% of its original notional balance, at seven prepayment speeds, and the speed at which that yield is zero. The case asserts those too.
Provenance. The expectations are taken from an independent published reference, cited above. The source is not committed with the case; a reader checks the asserted figures against the published document itself.
What it exercises
| Pack | credit |
| Contract types | credit.loan; credit.note for Class AB |
| Language features | two waterfalls over one collateral, one for principal and one for interest; entity fields carrying class balances; a class's yield at a price, yield over the interest the waterfall pays it, with the price an assumption |
| Conventions | PSA on a pool seasoned past the ramp, a servicing and guaranty strip, a stripped coupon, a notional interest-only class |
A coupon is stripped. Three rates are in play at once and none of them is the mortgage rate:
- the loans carry a 5.451% weighted average coupon;
- 0.451% is the servicing and guaranty strip, carried as
servicing_fee, so what reaches the trust is 5.00% exactly; - that 5.00% is then split 3.25% / 1.75% between a principal class and a notional one.
The interest waterfall is the test. It declares a residual step, and if the strip is right that step takes nothing:
pay ab_interest to party.ab_holders = asset.ab.balance * (0.0325 / 12.0)
pay io_interest to party.io_holders = asset.io.balance * (0.05 / 12.0)
pay residual to party.residual = remainingThe residual is zero in all 361 periods, to ten decimal places.
A note on why the class balances are fields at all. AB is a pass-through, so its
balance is the pool's, and IO's is a fixed fraction of AB's — neither carries
state of its own, and neither is copied. The field says what the class is
(next prev.asset.pool.balance) and derives the number. That the balances land
one period behind the distributions is not a workaround here but the deal's own
convention: the supplement strikes interest on "the outstanding balance of that
Certificate immediately prior to that Distribution Date", which is precisely the
number these fields hold.
The result
Worst disagreement 0.3640 percentage points across 60 published balance cells, for Class AB and the interest-only class (180 values asserted in all), against a floor of 0.5 set by the table's whole-percent rounding.
| Decrement, worst / mean | 0.3640 pp / 0.0841 pp |
| Informative cells (published value neither 0 nor 100) | 14 of 30 |
| Class AB weighted average life | 4.6950, published 4.7 |
| Residual to Classes R and RL | 0.0000000000, every period |
| Principal returned to AB | 148,372,434.00 against an original of 148,372,434 |
Over the 14 informative cells the mean error is 0.1803 pp — the signature of the issuer's rounding and nothing else.
The interest legs are asserted too, and they are external rather than model output: a published balance multiplied by a coupon stated on the cover. Their tolerance is the balance band carried through the coupon.
The class's weighted average life is folded from the principal the waterfall
pays it (wal) and asserted at ±0.05, the print floor of a figure published
to one decimal. Class AB is a note of the trust, and its principal step is
bound to it, so the life counts actual days over 365 from the note's term
to each distribution on the 25th, the way the supplement measures it. The
note's term opens on 1 February 2019, the first period boundary, two days
after settlement, a difference of 0.005 years against a figure published
to a tenth.
The supplement's other columns are scenarios of this case, each varying the one term that differs — the prepayment speed — and asserting its own decrement column and class life from its own file:
| speed | asserted cells | worst balance, pp | Class AB life | published |
|---|---|---|---|---|
| 100% PSA | 180 | 0.414 | 6.0977 | 6.1 |
| 300% PSA | 175 | 0.483 | 3.6682 | 3.7 |
| 400% PSA | 170 | 0.475 | 2.9460 | 2.9 |
| 700% PSA | 150 | 0.427 | 1.6920 | 1.7 |
| 1000% PSA | 135 | 0.455 | 1.0609 | 1.1 |
Every balance sits inside the half-percent floor and every life inside the print floor of 0.05.
The yield table. The supplement assumes Class IO is bought at 19.25% of its original notional, excluding accrued interest, and publishes its pre-tax bond-equivalent yield at seven speeds. The model states the price as an assumption, adds the 29 days of accrued interest a 30 January settlement carries on a 30/360 basis, and solves the yield over the interest the waterfall pays the class:
assume io_price = 0.1925
metric io_outlay = asset.io.original_balance * (inputs.io_price + 0.05 * 29.0 / 360.0)
metric io_yield = yield("g3.interest.io_interest", metric.io_outlay, parse_date("2019-01-30"))
metric io_yield_bey = 2.0 * ((1.0 + metric.io_yield) ^ 0.5 - 1.0)| speed | solved yield | published |
|---|---|---|
| 50% PSA | 14.99% | 15.0% |
| 100% PSA | 11.71% | 11.7% |
| 198% PSA | 5.12% | 5.1% |
| 272% PSA | 0.00% | 0%, the published zero-yield speed |
| 300% PSA | (1.97)% | (2.0)% |
| 400% PSA | (9.20)% | (9.2)% |
| 700% PSA | (32.83)% | (32.9)% |
| 1000% PSA | (60.61)% | (60.6)% |
Each is asserted within 0.001, the print floor of a figure published to a
tenth of a percent. The worst gap is 0.07 points at 700% PSA, where the
class has lost a third of what it cost. The two speeds the decrement
table does not print, 50% and 272%, are scenarios that assert the yield
alone. The 0% PSA column ships as its own case
(fnma_remic_2019_2_g3_psa000): the supplement prepares it on a different
collateral assumption, a 360-month original and remaining term at 7.50%, so
it is a different pool rather than a different speed.
The delta
Group 3 of three. Groups 1 and 2 are Structured Collateral: their assets are seventeen tranches of other Fannie Mae REMICs issued between 2002 and 2006. The instrument is fully specified for those groups too — one line each, the same as this one — but the cash arriving at them is another instrument's output, and reproducing the published tables would need those seventeen deals' own collateral. That is a compositional boundary, not a gap in this document, and it is why only Group 3 is here.
Seven speeds, one model. What the seven columns prove together is stronger than any one alone: a convention error in the prepayment curve, the seasoning ramp or the payment timing that hides under one column's whole-percent rounding has to hide under all seven columns and seven published lives simultaneously.
The outlay's date. The supplement discounts to a settlement on 30 January 2019, and the yield's outlay sits on that date, two days before the model's first period opens, with each distribution on its 25th. The gap in the yield column is the rounding of a figure published to a tenth.
No losses. Fannie Mae guarantees timely payment of principal and interest, so the collateral cannot default in a way the classes would see.
Seasoned past the ramp. Weighted average loan age is 175 months, so 198% PSA is a flat 11.88% CPR in every period. The ramp is written out in full anyway — the model should say the pool prepays at 198% PSA, not at 11.88% CPR, because the second is a consequence of the first and stops being true if the seasoning changes.
model.total is a regression anchor from this model. Every other assertion is a
published figure or derived from one.
Run configuration
{
"deterministic": {
"annual_discount_rate": 0.03
},
"scenarios": {
"psa050": {
"parameters": {
"inputs.psa": 0.5
}
},
"psa100": {
"parameters": {
"inputs.psa": 1.0
}
},
"psa300": {
"parameters": {
"inputs.psa": 3.0
}
},
"psa400": {
"parameters": {
"inputs.psa": 4.0
}
},
"psa700": {
"parameters": {
"inputs.psa": 7.0
}
},
"psa1000": {
"parameters": {
"inputs.psa": 10.0
}
},
"psa272": {
"parameters": {
"inputs.psa": 2.72
}
}
}
}Verified results
Checked period by period: 6 series across 60 periods — 180 values in all, each within the tolerance shown.
domain.credit.principal_paid_to_date— within ±741862.17asset.ab.balance— within ±741862.17asset.io.balance— within ±259651.76g3.interest.ab_interest— within ±2009.21g3.interest.io_interest— within ±1081.88g3.interest.residual— within ±0.01
Checked per scenario, each a full run under its own parameters:
| Scenario | metric.io_yield_bey | model.total | metric.ab_wal |
|---|---|---|---|
psa050 | 0.15 | — | — |
psa100 | 0.117 | 193,718,881.03 | 6.1 |
psa300 | -0.02 | 175,695,352.45 | 3.7 |
psa400 | -0.092 | 170,337,628.95 | 2.9 |
psa700 | -0.329 | 161,035,147.51 | 1.7 |
psa1000 | -0.606 | 156,352,857.6 | 1.1 |
psa272 | 0 | — | — |
Summary metrics for the base run:
| Metric | Value | Tolerance |
|---|---|---|
domain.credit.principal | 148,372,434 | ±0.01 |
model.total | 183,313,276.29 | ±1 |
domain.credit.wal_years | 4.7 | ±0.07 |
metric.ab_wal | 4.7 | ±0.05 |
metric.io_yield_bey | 0.051 | ±0.001 |