Main Content

# bondDefaultBootstrap

Bootstrap default probability curve from bond prices

## Syntax

``````[ProbabilityData,HazardData] = bondDefaultBootstrap(ZeroData,MarketData,Settle)``````
``````[ProbabilityData,HazardData] = bondDefaultBootstrap(___,Name,Value)``````

## Description

example

``````[ProbabilityData,HazardData] = bondDefaultBootstrap(ZeroData,MarketData,Settle)``` bootstraps the default probability curve from bond prices.Using `bondDefaultBootstrap`, you can: Extract discrete default probabilities for a certain period from market bond data.Interpolate these default probabilities to get the default probability curve for pricing and risk management purposes. ```

example

``````[ProbabilityData,HazardData] = bondDefaultBootstrap(___,Name,Value)``` adds optional name-value pair arguments.```

## Examples

collapse all

Use the following bond data.

``` Settle = datenum('08-Jul-2016'); MarketDate = datenum({'06/15/2018', '01/08/2019', '02/01/2021', '03/18/2021', '08/04/2025'}','mm/dd/yyyy'); CouponRate = [2.240 2.943 5.750 3.336 4.134]'/100; MarketPrice = [101.300 103.020 115.423 104.683 108.642]'; MarketData = [MarketDate,MarketPrice,CouponRate];```

Calculate the `ProbabilityData` and `HazardData`.

```TreasuryParYield = [0.26 0.28 0.36 0.48 0.61 0.71 0.95 1.19 1.37 1.69 2.11]'/100; TreasuryDates = datemnth(Settle, [[1 3 6], 12 * [1 2 3 5 7 10 20 30]]'); [ZeroRates, CurveDates] = pyld2zero(TreasuryParYield, TreasuryDates, Settle); ZeroData = [CurveDates, ZeroRates]; format longg [ProbabilityData,HazardData]=bondDefaultBootstrap(ZeroData,MarketData,Settle)```
```ProbabilityData = 5×2 737226 0.0299675399937611 737433 0.0418832295824674 738188 0.090518332884262 738233 0.101248065083713 739833 0.233002708031915 ```
```HazardData = 5×2 737226 0.0157077745460244 737433 0.0217939816590403 738188 0.025184912824721 738233 0.0962608718640789 739833 0.0361632398787917 ```

In `bondDefaultBootstrap`, the first column of the `ProbabilityData` output and the first column of the `HazardData` output contain the respective ending dates for the corresponding default probabilities and hazard rates. However, the starting dates used for the computation of the time ranges for default probabilities can be different from those of hazard rates. For default probabilities, the time ranges are all computed from the `Settle` date to the respective end dates shown in the first column of `ProbabilityData`. In contrast, the time ranges for the hazard rates are computed using the `Settle` date and the first column of `HazardData`, so that the first hazard rate applies from the `Settle` date to the first market date, the second hazard rate from the first to the second market date, and so on, and the last hazard rate applies from the second-to-last market date onwards.

`datestr(Settle)`
```ans = '08-Jul-2016' ```
`datestr(ProbabilityData(:,1))`
```ans = 5x11 char array '15-Jun-2018' '08-Jan-2019' '01-Feb-2021' '18-Mar-2021' '04-Aug-2025' ```
`datestr(HazardData(:,1))`
```ans = 5x11 char array '15-Jun-2018' '08-Jan-2019' '01-Feb-2021' '18-Mar-2021' '04-Aug-2025' ```

The time ranges for the default probabilities all start on `'08-Jul-2016'` and they end on `'15-Jun-2018'`, `'08-Jan-2019'`, `'01-Feb-2021'`, `'18-Mar-2021'`, and `'04-Aug-2025'`, respectively. As for the hazard rates, the first hazard rate starts on `'08-Jul-2016'` and ends on `'15-Jun-2018'`, the second hazard rate starts on `'15-Jun-2018'` and ends on `'08-Jan-2019'`, the third hazard rate starts on `'08-Jan-2019'` and ends on `'01-Feb-2021'`, and so forth.

Reprice one of the bonds from bonds list based on the default probability curve. The expected result of this repricing is a perfect match with the market quote.

Use the following Treasury data from US Department of the Treasury.

```Settle = datetime('08-Jul-2016','Locale','en_US'); TreasuryParYield = [0.26 0.28 0.36 0.48 0.61 0.71 0.95 1.19 1.37 1.69 2.11]'/100; TreasuryDates = datemnth(Settle, [[1 3 6], 12 * [1 2 3 5 7 10 20 30]]');```

Preview the bond date using semiannual coupon bonds with market quotes, coupon rates, and a settle date of July-08-2016.

```MarketDate = datenum({'06/01/2017','06/01/2019','06/01/2020','06/01/2022'}','mm/dd/yyyy'); CouponRate = [7 8 9 10]'/100; MarketPrice = [101.300 109.020 114.42 118.62]'; MarketData = [MarketDate, MarketPrice, CouponRate]; BondList = array2table(MarketData, 'VariableNames', {'Maturity', 'Price','Coupon'}); BondList.Maturity = datetime(BondList.Maturity,'Locale','en_US','ConvertFrom','datenum'); BondList.Maturity.Format = 'MMM-dd-yyyy'```
```BondList=4×3 table Maturity Price Coupon ___________ ______ ______ Jun-01-2017 101.3 0.07 Jun-01-2019 109.02 0.08 Jun-01-2020 114.42 0.09 Jun-01-2022 118.62 0.1 ```

Choose the second coupon bond as the one to be priced.

```number = 2; TestCase = BondList(number, :);```

Preview the risk-free rate data provided here that is based on a continuous compound rate.

```[ZeroRates, CurveDates] = pyld2zero(TreasuryParYield, TreasuryDates, Settle); ZeroData = [datenum(CurveDates), ZeroRates]; RiskFreeRate = array2table(ZeroData, 'VariableNames', {'Date', 'Rate'}); RiskFreeRate.Date = datetime(RiskFreeRate.Date,'Locale','en_US','ConvertFrom','datenum'); RiskFreeRate.Date.Format = 'MMM-dd-yyyy'```
```RiskFreeRate=11×2 table Date Rate ___________ _________ Aug-08-2016 0.0026057 Oct-08-2016 0.0027914 Jan-08-2017 0.0035706 Jul-08-2017 0.0048014 Jul-08-2018 0.0061053 Jul-08-2019 0.0071115 Jul-08-2021 0.0095416 Jul-08-2023 0.012014 Jul-08-2026 0.013883 Jul-08-2036 0.017359 Jul-08-2046 0.022704 ```

Bootstrap the probability of default (PD) curve from the bonds.

```format longg [defaultProb1, hazard1] = bondDefaultBootstrap(ZeroData, MarketData, Settle)```
```defaultProb1 = 4×2 736847 0.0704863142317494 737577 0.162569420050034 737943 0.217308133826188 738673 0.38956773145021 ```
```hazard1 = 4×2 736847 0.0813390794774647 737577 0.0521615800986281 737943 0.0674145844133183 738673 0.12428587278862 ```
`format`

Reformat the default probability and hazard rate for a better representation.

```DefProbHazard = [defaultProb1, hazard1(:,2)]; DefProbHazardTable = array2table(DefProbHazard, 'VariableNames', {'Date', 'DefaultProbability', 'HazardRate'}); DefProbHazardTable.Date = datetime(DefProbHazardTable.Date,'Locale','en_US','ConvertFrom','datenum'); DefProbHazardTable.Date.Format = 'MMM-dd-yyyy'```
```DefProbHazardTable=4×3 table Date DefaultProbability HazardRate ___________ __________________ __________ Jun-01-2017 0.070486 0.081339 Jun-01-2019 0.16257 0.052162 Jun-01-2020 0.21731 0.067415 Jun-01-2022 0.38957 0.12429 ```

Preview the selected bond to reprice based on the PD curve.

`TestCase`
```TestCase=1×3 table Maturity Price Coupon ___________ ______ ______ Jun-01-2019 109.02 0.08 ```

To reprice the bond, first generate cash flows and payment dates.

```[Payments, PaymentDates] = cfamounts(TestCase.Coupon, Settle, TestCase.Maturity); AccInt=-Payments(1); % Truncate the payments as well as payment dates for calculation % PaymentDates(1) is the settle date, no need for following calculations PaymentDates = PaymentDates(2:end)```
```PaymentDates = 1x6 datetime Columns 1 through 5 01-Dec-2016 01-Jun-2017 01-Dec-2017 01-Jun-2018 01-Dec-2018 Column 6 01-Jun-2019 ```
`Payments = Payments(2:end)`
```Payments = 1×6 4 4 4 4 4 104 ```

Calculate the discount factors on the payment dates.

`DF = zero2disc(interp1(RiskFreeRate.Date, RiskFreeRate.Rate, PaymentDates, 'linear', 'extrap'), PaymentDates, Settle, -1)`
```DF = 1×6 0.9987 0.9959 0.9926 0.9887 0.9845 0.9799 ```

Assume that the recovery amount is a fixed proportion of bond's face value. The bond’s face value is `100`, and the recovery ratio is set to 40% as assumed in `bondDefaultBootstrap`.

```Num = length(Payments); RecoveryAmount = repmat(100*0.4, 1, Num)```
```RecoveryAmount = 1×6 40 40 40 40 40 40 ```

Calculate the probability of default based on the default curve.

```DefaultProb1 = bondDefaultBootstrap(ZeroData, MarketData, Settle, 'ZeroCompounding', -1, 'ProbabilityDates', PaymentDates'); SurvivalProb = 1 - DefaultProb1(:,2)```
```SurvivalProb = 6×1 0.9680 0.9295 0.9055 0.8823 0.8595 0.8375 ```

Calculate the model-based clean bond price.

```DirtyPrice = DF * (SurvivalProb.*Payments') + (RecoveryAmount.*DF) * (-diff([1;SurvivalProb])); ModelPrice = DirtyPrice - AccInt```
```ModelPrice = 109.0200 ```

Compare the repriced bond to the market quote.

```ResultTable = TestCase; ResultTable.ModelPrice = ModelPrice; ResultTable.Difference = ModelPrice - TestCase.Price```
```ResultTable=1×5 table Maturity Price Coupon ModelPrice Difference ___________ ______ ______ __________ __________ Jun-01-2019 109.02 0.08 109.02 1.4211e-14 ```

## Input Arguments

collapse all

Zero rate data, specified as an `M`-by-`2` matrix of dates and zero rates or an `IRDataCurve` object of zero rates. For array input, the dates must be entered as serial date numbers, and discount rate must be in decimal form.

When `ZeroData` is an `IRDataCurve` object, `ZeroCompounding` and `ZeroBasis` are implicit in `ZeroData` and are redundant inside this function. In this case, specify these optional parameters when constructing the `IRDataCurve` object before using this `bondDefaultBootstrap` function.

For more information on an `IRDataCurve` (Financial Instruments Toolbox) object, see Creating an IRDataCurve Object (Financial Instruments Toolbox).

Data Types: `double`

Bond market data, specified as an `N`-by-`3` matrix of maturity dates, market prices, and coupon rates for bonds. The dates must be entered as serial date numbers, market prices must be numeric values, and coupon rate must be in decimal form.

Note

A warning is displayed when `MarketData` is not sorted in ascending order by time.

Data Types: `double`

Settlement date, specified as a serial date number, a date character vector, a datetime object, or a date string object. `Settle` must be earlier than or equal to the maturity dates in `MarketData`.

Data Types: `double` | `char` | `datetime` | `string`

### Name-Value Pair Arguments

Specify optional comma-separated pairs of `Name,Value` arguments. `Name` is the argument name and `Value` is the corresponding value. `Name` must appear inside quotes. You can specify several name and value pair arguments in any order as `Name1,Value1,...,NameN,ValueN`.

Example: `[ProbabilityData,HazardData] = bondDefaultBootstrap(ZeroData,MarketData,Settle,'RecoveryRate',Recovery,'ZeroCompounding',-1)`

Note

Any optional input of size `N`-by-`1` is also acceptable as an array of size `1`-by-`N`, or as a single value applicable to all contracts.

Recovery rate, specified as the comma-separated pair consisting of `'RecoveryRate'` and a `N`-by-`1` vector of recovery rates, expressed as a decimal from `0` through `1`.

Data Types: `double`

Dates for the output of default probability data, specified as the comma-separated pair consisting of `'ProbabilityDates'` and a `P`-by-`1` vector, given as serial date numbers, datetime objects, date character vectors, or date string objects.

Data Types: `double` | `char` | `datetime` | `string`

Compounding frequency of the zero curve, specified as the comma-separated pair consisting of `'ZeroCompounding'` and a `N`-by-`1` vector. Values are:

• `1` — Annual compounding

• `2` — Semiannual compounding

• `3` — Compounding three times per year

• `4` — Quarterly compounding

• `6` — Bimonthly compounding

• `12` — Monthly compounding

• `−1` — Continuous compounding

Data Types: `double`

Basis of the zero curve, specified as the comma-separated pair consisting of `'ZeroBasis'` and the same values listed for `Basis`.

Data Types: `double`

Recovery method, specified as the comma-separated pair consisting of `'RecoveryMethod'` and a character vector or a string with a value of `'presentvalue'` or `'facevalue'`.

• `'presentvalue'` assumes that upon default, a bond is valued at a given fraction to the hypothetical present value of its remaining cash flows, discounted at risk-free rate.

• `'facevalue'` assumes that a bond recovers a given fraction of its face value upon recovery.

Data Types: `char` | `string`

Face or par value, specified as the comma-separated pair consisting of `'Face'` and a `NINST`-by-`1` vector of bonds.

Data Types: `double`

Payment frequency, specified as the comma-separated pair consisting of `'Period'` and a `N`-by-`1` vector with values of `0`, `1`, `2`, `3`, `4`, `6`, or `12`.

Data Types: `double`

Day-count basis of the instrument, specified as the comma-separated pair consisting of `'Basis'` and a positive integer using a `NINST`-by-`1` vector. Values are:

• 0 = actual/actual

• 1 = 30/360 (SIA)

• 2 = actual/360

• 3 = actual/365

• 4 = 30/360 (PSA)

• 5 = 30/360 (ISDA)

• 6 = 30/360 (European)

• 7 = actual/365 (Japanese)

• 8 = actual/actual (ICMA)

• 9 = actual/360 (ICMA)

• 10 = actual/365 (ICMA)

• 11 = 30/360E (ICMA)

• 12 = actual/365 (ISDA)

• 13 = BUS/252

For more information, see Basis.

Data Types: `double`

End-of-month rule flag, specified as the comma-separated pair consisting of `'EndMonthRule'` and a nonnegative integer, `0` or `1`, using a `NINST`-by-`1` vector. This rule applies only when `Maturity` is an end-of-month date for a month having 30 or fewer days.

• `0` = Ignore rule, meaning that a bond coupon payment date is always the same numerical day of the month.

• `1` = Set rule on, meaning that a bond coupon payment date is always the last actual day of the month.

Data Types: `double`

Bond issue date, specified as the comma-separated pair consisting of `'IssueDate'` and a `N`-by-`1` vector, given as serial date numbers, datetime objects, date character vectors, or date string objects.

Data Types: `double` | `char` | `datetime` | `string`

First actual coupon date, specified as the comma-separated pair consisting of `'FirstCouponDate'` and a serial date number. `FirstCouponDate` is used when a bond has an irregular first coupon period. When `FirstCouponDate` and `LastCouponDate` are both specified, `FirstCouponDate` takes precedence in determining the coupon payment structure.

Data Types: `double`

Last actual coupon date, specified as the comma-separated pair consisting of `'LastCouponDate'` and a serial date number. `LastCouponDate` is used when a bond has an irregular last coupon period. In the absence of a specified `FirstCouponDate`, a specified `LastCouponDate` determines the coupon structure of the bond. The coupon structure of a bond is truncated at the `LastCouponDate`, regardless of where it falls, and is followed only by the bond's maturity cash flow date.

Data Types: `double`

Forward starting date of payments, specified as the comma-separated pair consisting of `'StartDate'` and a serial date number. `StartDate` is when a bond actually starts (the date from which a bond cash flow is considered). To make an instrument forward-starting, specify this date as a future date.

Data Types: `double`

Business day conventions, specified as the comma-separated pair consisting of `'BusinessDayConvention'` and a character vector or a string object. The selection for business day convention determines how nonbusiness days are treated. Nonbusiness days are defined as weekends plus any other date that businesses are not open (for example, statutory holidays). Values are:

• `'actual'` — Nonbusiness days are effectively ignored. Cash flows that fall on non-business days are assumed to be distributed on the actual date.

• `'follow'` — Cash flows that fall on a nonbusiness day are assumed to be distributed on the following business day.

• `'modifiedfollow'` — Cash flows that fall on a non-business day are assumed to be distributed on the following business day. However if the following business day is in a different month, the previous business day is adopted instead.

• `'previous'` — Cash flows that fall on a nonbusiness day are assumed to be distributed on the previous business day.

• `'modifiedprevious'` — Cash flows that fall on a nonbusiness day are assumed to be distributed on the previous business day. However if the previous business day is in a different month, the following business day is adopted instead.

Data Types: `char` | `cell` | `string`

## Output Arguments

collapse all

Default probability values, returned as a `P`-by-`2` matrix with dates and corresponding cumulative default probability values. The dates match those in `MarketData`, unless the optional input parameter `ProbabilityDates` is provided.

Hazard rate values, returned as an `N`-by-`2` matrix with dates and corresponding hazard rate values for the survival probability model. The dates match those in `MarketData`.

Note

A warning is displayed when nonmonotone default probabilities (that is, negative hazard rates) are found.

## More About

collapse all

### Bootstrap Default Probability

A default probability curve can be bootstrapped from a collection of bond market quotes.

Extracting discrete default probabilities for a certain period from market bond data is represented by the formula

`$Price=Disc\left({t}_{N}\right)×FV×Q\left({t}_{N}\right)+\frac{C}{f}×\sum _{i=1}^{N}Disc\left({t}_{i}\right)×Q\left({t}_{i}\right)+\sum _{\left(i=1\right)}^{N}Disc\left({t}_{i}\right)×R\left({t}_{i}\right)×\left(Q\left({t}_{i}-1\right)-Q\left({t}_{i}\right)\right)$`

where:

FV — Face value

Q — Survival probability

C — Coupon

R — Recovery amount

f — Payment frequency (for example, 2 for semiannual coupon bonds)

The default probability is:

`DefaultProbability` = `1``SurvivalProbability`

 Jarrow, Robert A., and Stuart Turnbull. "Pricing Derivatives on Financial Securities Subject to Credit Risk." Journal of Finance. 50.1, 1995, pp. 53–85.

 Berd, A., Mashal, R. and Peili Wang. “Defining, Estimating and Using Credit Term Structures.” Research report, Lehman Brothers, 2004.

Download ebook