Documentation

Fixed-Rate Mortgage Pool

Introduction

Financial Instruments Toolbox™ software supports calculations involved with generic fixed-rate mortgage pools and balloon mortgages. Pass-through certificates typically have embedded call options in the form of prepayment. Prepayment is an excess payment applied to the principal of a PC. These accelerated payments reduce the effective life of a PC.

The toolbox comes with a standard Bond Market Association (PSA) prepayment model and can generate multiples of standard prepayment speeds. The Public Securities Association provides a set of uniform practices for calculating the characteristics of mortgage-backed securities when there is an assumed prepayment function.

Alternatively, aside from the standard PSA implementation in this toolbox, you can supply your own projected prepayment vectors. At this time, however, custom prepayment functionality that incorporates pool-specific information and interest rate forecasts are not available in this toolbox. If you plan to use custom prepayment vectors in your calculations, you presumably already own such a suite in MATLAB®.

Inputs to Functions

Because of the generic, all-purpose nature of the toolbox pass-through functions, you can fine-tune them to conform to a particular mortgage. Most functions require at least this set of inputs:

  • Gross coupon rate

  • Settlement date

  • Issue (effective) date

  • Maturity date

Typical optional inputs include standard prepayment speed (or customized vector), net coupon rate (if different from gross coupon rate), and payment delay in number of days.

All calculations are based on expected payment dates and actual cash flow to the investor. For example, when GrossRate and CouponRate differ as inputs to mbsdurp, the function returns a modified duration based on CouponRate. (A notable exception is mbspassthrough, which returns interest quantities based on the GrossRate.)

Generating Prepayment Vectors

You can generate PSA multiple prepayment vectors quickly. To generate prepayment vectors of 100 and 200 PSA, type

PSASpeed = [100, 200];
[CPR, SMM] = psaspeed2rate(PSASpeed);

This function computes two prepayment values: conditional prepayment rate (CPR) and single monthly mortality (SMM) rate. CPR is the percentage of outstanding principal prepaid in 1 year. SMM is the percentage of outstanding principal prepaid in 1 month. In other words, CPR is an annual version of SMM.

Since the entire 360-by-2 array is too long to show in this document, observe the SMM (100 and 200 PSA) plots, spaced one month apart, instead.

Prepayment assumptions form the basis upon which far more comprehensive MBS calculations are based. As an illustration observe the following example, which shows the use of the function mbscfamounts to generate cash flows and timings based on a set of standard prepayments.

Consider three mortgage pools that were sold on the issue date (which starts unamortized). The first two pools "balloon out" in 60 months, and the third is regularly amortized to the end. The prepayment speeds are assumed to be 100, 200, and 200 PSA, respectively.

Settle     = [datenum('1-Feb-2000');
              datenum('1-Feb-2000');
              datenum('1-Feb-2000')];
                            
Maturity   = [datenum('1-Feb-2030')];
          
IssueDate  = datenum('1-Feb-2000');
GrossRate  = 0.08125;
CouponRate = 0.075;
Delay = 14; 

PSASpeed = [100, 200];
[CPR, SMM] = psaspeed2rate(PSASpeed);

PrepayMatrix = ones(360,3);
PrepayMatrix(1:60,1:2) = SMM(1:60,1:2);
PrepayMatrix(:,3) = SMM(:,2);

[CFlowAmounts, CFlowDates, TFactors, Factors] = ... 
mbscfamounts(Settle, Maturity, IssueDate, GrossRate, ... 
CouponRate, Delay, [], PrepayMatrix);

The fourth output argument, Factors, indicates the fraction of the balance still outstanding at the beginning of each month. A snapshot of this argument in the MATLAB Variables editor illustrates the 60-month life of the first two of the mortgages with balloon payments and the continuation of the third mortgage until the end (360 months).

You can readily see that mbscfamounts is the building block of most fixed rate and balloon pool cash flows.

Mortgage Prepayments

Prepayment is beneficial to the pass-through owner when a mortgage pool has been purchased at discount. The next example compares mortgage yields (compounded monthly) versus the purchase clean price with constant prepayment speed. The example illustrates that when you have purchased a pool at a discount, prepayment generates a higher yield with decreasing purchase price.

Price = [85; 90; 95];
Settle = datenum('15-Apr-2002');
Maturity = datenum('1 Jan 2030');
IssueDate = datenum('1-Jan-2000');
GrossRate = 0.08125;
CouponRate = 0.075;
Delay = 14;
Speed = 100;

Compute the mortgage and bond-equivalent yields.

[MYield, BEMBSYield] = mbsyield(Price, Settle, Maturity, ... 
IssueDate, GrossRate, CouponRate, Delay, Speed)
MYield =

    0.1018
    0.0918
    0.0828

BEMBSYield =

    0.1040
    0.0936
    0.0842

If for this same pool of mortgages, there was no prepayment (Speed = 0), the yields would decline to

MYield =

    0.0926
    0.0861
    0.0802

BEMBSYield =

    0.0944
    0.0877
    0.0815

Likewise, if the rate of prepayment doubled (Speed = 200), the yields would increase to

MYield =

    0.1124
    0.0984
    0.0858

BEMBSYield =

    0.1151
    0.1004
    0.0873

For the same prepayment vector, deeper discount pools earn higher yields. For more information, see mbsprice and mbsyield.

Risk Measurement

Financial Instruments Toolbox software provides the most basic risk measures of a pool portfolio:

  • Modified duration

  • Convexity

  • Average life of pool

Consider the following example, which calculates the Macaulay and modified durations given the price of a mortgage pool.

Price = [95; 100; 105];
Settle = datenum('15-Apr-2002');
Maturity = datenum('1-Jan-2030');
IssueDate = datenum('1-Jan-2000');
GrossRate = 0.08125;
CouponRate = 0.075;
Delay = 14;
Speed = 100;
 
[YearDuration, ModDuration] = mbsdurp(Price, Settle, ...
Maturity, IssueDate, GrossRate, CouponRate, Delay, Speed)
YearDuration =

    6.1341
    6.3882
    6.6339

ModDuration =

    5.8863
    6.1552
    6.4159

Using Financial Instruments Toolbox functions, you can obtain modified duration and convexity from either price or yield, as long as you specify a prepayment vector or an assumed prepayment speed. The toolbox risk-measurement functions (mbsdurp, mbsdury, mbsconvp, mbsconvy, and mbswal) adhere to the guidelines listed in the PSA Uniform Practices manual.

Mortgage Pool Valuation

For accurate valuation of a mortgage pool, you must generate interest rate paths and use them with mortgage pool characteristics to properly value the pool. A widely used methodology is the option-adjusted spread (OAS). OAS measures the yield spread that is not directly attributable to the characteristics of a fixed-income investment.

Calculating OAS

Prepayment alters the cash flows of an otherwise regularly amortizing mortgage pool. A comprehensive option-adjusted spread calculation typically begins with the generation of a set of paths of spot rates to predict prepayment. A path is collection of i spot-rate paths, with corresponding j cash flows on each of those paths.

The effect of the OAS on pool pricing is shown mathematically in the following equation, where K is the option-adjusted spread.

PoolPrice=1NumberofPaths×iNumberofPathsjCFijCFij(1+zeroratesij+K)Tij

Calculating Effective Duration

Alternatively, if you are more interested in the sensitivity of a mortgage pool to interest rate changes, use effective duration, which is a more appropriate measure. Effective duration is defined mathematically with the following equation.

EffectiveDuration=P(y+Δy)P(yΔy)2P(y)Δy

Calculating Market Price

The toolbox has all the components required to calculate OAS and effective duration if you supply prepayment vectors or assumptions. For OAS, given a prepayment vector, you can generate a set of cash flows with mbscfamounts. Discounting these cash flows with the reference curve and then adding OAS produces the market price. See Computing Option-Adjusted Spread for a discussion on the computation of option-adjusted spread.

Effective duration is a more difficult issue. While modified duration changes the discounting process (by changing the yield used to discount cash flows), effective duration must account for the change in cash flow because of the change in yield. A possible solution is to recompute prices using mbsprice for a small change in yield, in both the upwards and downwards directions. In this case, you must recompute the prepayment input. Internally, this alters the cash flows of the mortgage pool. Assuming that the OAS stays constant in all yield environments, you can apply a set of discounting factors to the cash flows in up and down yield environments to find the effective duration.

Computing Option-Adjusted Spread

The option-adjusted spread (OAS) is an amount of extra interest added above (or below if negative) the reference zero curve. To compute the OAS, you must provide the zero curve as an extra input. You can specify the zero curve in any intervals and with any compounding method. (To minimize any error due to interpolation, keep the intervals as regular and frequent as possible.) You must supply a prepayment vector or specify a speed corresponding to a standard PSA prepayment vector.

One way to compute the appropriate zero curve for an agency is to look at its bond yields and bootstrap them from the shortest maturity onwards. You can do this with Financial Toolbox™ functions zbtprice and zbtyield.

The following example shows how to calculate an appropriate zero curve followed by computation of the pool's OAS. This example calculates the OAS of a 30-year fixed rate mortgage with about a 28-year weighted average maturity left, given an assumption of 0, 50, and 100 PSA prepayment speeds.

Create curve for zerorates.

Bonds = [datenum('11/21/2002')   0        100    0    2    1;    
         datenum('02/20/2003')   0        100    0    2    1;
         datenum('07/31/2004')   0.03     100    2    3    1;
         datenum('08/15/2007')   0.035    100    2    3    1;
         datenum('08/15/2012')   0.04875  100    2    3    1;
         datenum('02/15/2031')   0.05375  100    2    3    1];
  
Yields = [0.0162;
          0.0163;
          0.0211;
          0.0328;
          0.0420;
          0.0501];

Since the above is Treasury data and not selected agency data, a term structure of spread is assumed. In this example, the spread declines proportionally from a maximum of 250 basis points at the shortest maturity.

Yields = Yields + 0.025 * (1./[1:6]');

Get parameters from Bonds matrix.

Settle = datenum('20-Aug-2002');
Maturity = Bonds(:,1);
CouponRate = Bonds(:,2);
Face = Bonds(:,3);
Period = Bonds(:,4);
Basis = Bonds(:,5);
EndMonthRule = Bonds(:,6);
  
[Prices, AccruedInterest] = bndprice(Yields, CouponRate, ...
Settle, Maturity, Period, Basis, EndMonthRule, [], [], [], [], ... 
Face);

Use zbtprice to solve for zero rates.

[ZeroRatesP, CurveDatesP] = zbtprice(Bonds, Prices, Settle);
ZeroCompounding = 2*ones(size(ZeroRatesP));
ZeroMatrix = [CurveDatesP, ZeroRatesP, ZeroCompounding];

Use output from zbtprice to calculate the OAS.

Price = 95;
Settle = datenum('20-Aug-2002');
Maturity = datenum('2-Jan-2030');
IssueDate = datenum('2-Jan-2000');
GrossRate = 0.08125;
CouponRate = 0.075;
Delay = 14;
Interpolation = 1;
PrepaySpeed = [0; 50; 100];
  
OAS = mbsprice2oas(ZeroMatrix, Price, Settle, Maturity, ...
IssueDate, GrossRate, CouponRate, Delay, Interpolation, ... 
PrepaySpeed)
OAS =

    26.0502
    28.6348
    31.2222

This example shows that one cash flow set is being discounted and solved for its OAS, as contrasted with the NumberOfPaths set of cash flows as shown in Mortgage Pool Valuation. Averaging the sets of cash flows resulting from all simulations into one average cash flow vector and solving for the OAS, discounts the averaged cash flows to have a present value of today's (average) price.

While this example uses the mortgage pool price (mbsprice2oas) to determine the OAS, you can also use yield to resolve it (mbsyield2oas). Also, there are reverse OAS functions that return prices and yields given OAS (mbsoas2price and mbsoas2yield).

The example also restates earlier examples that show discount securities benefit from higher level of prepayment, keeping everything else unchanged. The relation is reversed for premium securities.

Prepayments with Fewer Than 360 Months Remaining

When fewer than 360 months remain in the pool, the applicable PSA prepayment vector is "seasoned" by the pool's age. (Elements in the 360-element prepayment vector that represent past payments are skipped. For example, on a 30-year mortgage that is 10 months old, only the final 350 prepayments are applied.)

Assume, for example, that you have two 30-year loans, one new and another 10 months old. Both have the same PSA speed of 100 and prepay using the vectors plotted below.

Still within the scope of relative valuation, you could also solve for the percentage of the standard PSA prepayment vector given the pool's arbitrary, user-supplied prepayment vector, such that the PSA speed gives the same Macaulay duration as the user-supplied prepayment vector.

If you supply a custom prepayment vector, you must account for the number of months remaining.

Price = 101;
Settle = datenum('1-Jan-2001');
Maturity = datenum('1-Jan-2030');
IssueDate = datenum('1-Jan-2000');
GrossRate = 0.08125;
PrepayMatrix = 0.005*ones(348,1);
CouponRate   = 0.075;
Delay = 14;
 
ImpliedSpeed = mbsprice2speed(Price, Settle, Maturity, ...
IssueDate, GrossRate, PrepayMatrix, CouponRate, Delay)
ImpliedSpeed =

  104.2543

Examine the prepayment input. The remaining 29 years require 348 monthly elements in the prepayment vector. Suppose then, keeping everything the same, you change Settle to February 14, 2003.

Settle = datenum('14-Feb-2003');

You can use cpncount to count all incoming coupons received after Settle by invoking

NumCouponsRemaining = cpncount(Settle, Maturity, 12, 1, [], ... 
IssueDate) 
NumCouponsRemaining =
323

The input 12 defines the monthly payment frequency, 1 defines the 30/360 basis, and IssueDate defines aging and determination-of-holder date. Thus, you must supply a 323-element vector to account for a prepayment corresponding to each monthly payment.

Pools with Different Numbers of Coupons Remaining

Suppose one pool has two remaining coupons, and the other has three. MATLAB software expects the prepayment matrix to be in the following format:

V11       V21
V12       V22
NaN       V23

Vij denotes the single monthly mortality (SMM) rate for pool i during the jth coupon period since Settle.

The use of NaN to pad the prepayment matrix is necessary because MATLAB cannot concatenate vectors of different lengths into a matrix. Also, it can serve as an error check against any unintended operation (any MATLAB operation that would return NaN).

For example, assume that the 2 month pool has a constant SMM of 0.5% and the 3 month has a constant SMM of 1% in every period. The prepayment matrix you would create is depicted below.

Create this input in whatever manner is best for you.

Summary of Prepayment Data Vector Representation

  • When you specify a PSA prepayment speed, MATLAB "seasons" the pool according to its age.

  • When you specify your own prepayment matrix, identify the maximum number of coupons remaining using cpncount. Then supply the matrix elements up to the point when cash flow ceases to exist.

  • When different length pools must exist in the same matrix, pad the shorter one(s) with NaN. Each column of the prepayment matrix corresponds to a specific pool.

Was this topic helpful?