bondDefaultBootstrap
Bootstrap default probability curve from bond prices
Syntax
Description
[
bootstraps
the default probability curve from bond prices.ProbabilityData
,HazardData
]
= bondDefaultBootstrap(ZeroData
,MarketData
,Settle
)
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.
[
adds
optional name-value pair arguments.ProbabilityData
,HazardData
]
= bondDefaultBootstrap(___,Name,Value
)
Examples
Determine the Default Probability and Hazard Rate Values for Treasury Bonds
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 a Bond Listed on the Default Probability Curve
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
01-Dec-2016 01-Jun-2017 01-Dec-2017 01-Jun-2018 01-Dec-2018 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
ZeroData
— Zero rate data
matrix | IRDataCurve
object
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
MarketData
— Bond market data
matrix
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
Settle
— Settlement date
datetime scalar | string scalar | date character vector
Settlement date, specified as a scalar datetime, string, or date character vector.
Settle
must be earlier than or equal to the maturity
dates in MarketData
.
To support existing code, bondDefaultBootstrap
also
accepts serial date numbers as inputs, but they are not recommended.
Data Types: char
| datetime
| string
Name-Value Arguments
Specify optional pairs of arguments as
Name1=Value1,...,NameN=ValueN
, where Name
is
the argument name and Value
is the corresponding value.
Name-value arguments must appear after other arguments, but the order of the
pairs does not matter.
Before R2021a, use commas to separate each name and value, and enclose
Name
in quotes.
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.
RecoveryRate
— Recovery rate
0.4
(default) | decimal
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
ProbabilityDates
— Dates for output of default probability data
column of dates in MarketData
(default) | datetime array | string array | date character vector
Dates for the output of default probability data, specified as the comma-separated pair
consisting of 'ProbabilityDates'
and a
P
-by-1
vector using a datetime
array, string array, or date character vectors.
To support existing code, bondDefaultBootstrap
also
accepts serial date numbers as inputs, but they are not recommended.
Data Types: char
| datetime
| string
ZeroCompounding
— Compounding frequency of the zero curve
2
(semiannual) (default) | integer with value of 1
,2
,3
,4
,6
,12
, or –1
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 compounding2
— Semiannual compounding3
— Compounding three times per year4
— Quarterly compounding6
— Bimonthly compounding12
— Monthly compounding−1
— Continuous compounding
Data Types: double
ZeroBasis
— Basis of the zero curve
0
(actual/actual) (default) | integer with value of 0
to 13
Basis of the zero curve, specified as the comma-separated pair
consisting of 'ZeroBasis'
and the same values listed
for Basis
.
Data Types: double
RecoveryMethod
— Recovery method
'facevalue'
(default) | character vector with value of 'presentvalue'
or 'facevalue'
| string object with value of 'presentvalue'
or 'facevalue'
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
— Face or par value
100
(default) | numeric
Face or par value, specified as the comma-separated pair consisting
of 'Face'
and a NINST
-by-1
vector
of bonds.
Data Types: double
Period
— Payment frequency
2
(default) | numeric with values 0
, 1
, 2
, 3
, 4
, 6
or 12
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
Basis
— Day-count basis of the instrument
0
(actual/actual) (default) | integers of the set [0...13]
| vector of integers of the set [0...13]
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
EndMonthRule
— End-of-month rule flag
1
(in effect) (default) | nonnegative integer 0
or 1
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
IssueDate
— Bond issue date
if IssueDate
not specified, cash flow payment dates determined from other inputs (default) | datetime array | string array | date character vector
Bond issue date, specified as the comma-separated pair consisting of
'IssueDate'
and a
N
-by-1
vector using a datetime
array, string array, or date character vectors.
To support existing code, bondDefaultBootstrap
also
accepts serial date numbers as inputs, but they are not recommended.
Data Types: char
| datetime
| string
FirstCouponDate
— First actual coupon date
if you do not specify a FirstCouponDate
, cash flow payment dates are determined from other inputs (default) | datetime scalar | string scalar | date character vector
First actual coupon date, specified as the comma-separated pair consisting of
'FirstCouponDate'
and a scalar datetime, string,
or date character vector. 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.
To support existing code, bondDefaultBootstrap
also
accepts serial date numbers as inputs, but they are not recommended.
Data Types: char
| datetime
| string
LastCouponDate
— Last actual coupon date
if you do not specify a LastCouponDate
, cash flow payment dates are determined from other inputs (default) | datetime scalar | string scalar | date character vector
Last actual coupon date, specified as the comma-separated pair consisting of
'LastCouponDate'
and a scalar datetime, string,
or date character vector. 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.
To support existing code, bondDefaultBootstrap
also
accepts serial date numbers as inputs, but they are not recommended.
Data Types: char
| datetime
| string
StartDate
— Forward starting date of payments
if you do not specify StartDate
, effective start date is Settle
date (default) | datetime scalar | string scalar | date character vector
Forward starting date of payments, specified as the comma-separated pair consisting of
'StartDate'
and a scalar datetime, string, or
date character vector. 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.
To support existing code, bondDefaultBootstrap
also
accepts serial date numbers as inputs, but they are not recommended.
Data Types: char
| datetime
| string
BusinessDayConvention
— Business day conventions
'actual'
(default) | character vector or string object with values'actual'
, 'follow'
,
'modifiedfollow'
, 'previous'
or
'modifiedprevious'
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
ProbabilityData
— Default probability values
matrix
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.
HazardData
— Hazard rate values
matrix
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
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
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
References
[1] Jarrow, Robert A., and Stuart Turnbull. "Pricing Derivatives on Financial Securities Subject to Credit Risk." Journal of Finance. 50.1, 1995, pp. 53–85.
[2] Berd, A., Mashal, R. and Peili Wang. “Defining, Estimating and Using Credit Term Structures.” Research report, Lehman Brothers, 2004.
Version History
Introduced in R2017aR2022b: Serial date numbers not recommended
Although bondDefaultBootstrap
supports serial date numbers,
datetime
values are recommended instead. The
datetime
data type provides flexible date and time
formats, storage out to nanosecond precision, and properties to account for time
zones and daylight saving time.
To convert serial date numbers or text to datetime
values, use the datetime
function. For example:
t = datetime(738427.656845093,"ConvertFrom","datenum"); y = year(t)
y = 2021
There are no plans to remove support for serial date number inputs.
See Also
IRDataCurve
(Financial Instruments Toolbox) | cdsbootstrap
Topics
- Creating an IRDataCurve Object (Financial Instruments Toolbox)
MATLAB Command
You clicked a link that corresponds to this MATLAB command:
Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)