How to Use the Bond Extension Package¶
To follow the script used in this tutorial, you can
clone the Daml Finance repository. In particular,
the Bond test folder src/test/daml/Daml/Finance/Instrument/Bond/Test/
is the starting point
of this tutorial.
How to Use the Bond Extension in Your Application¶
As explained in the Getting Started section and on the Architecture page, your app should only depend on the interface layer of Daml Finance. For bonds this means that you should only include the bond interface package.
Your initialization scripts are an exception, since they are only run once when your app is initialized. This creates the necessary factories. Your app can then create bonds through these factory interfaces.
How to Create a Bond Instrument¶
There are different types of bonds, which mainly differ in the way the coupon is defined. In order to create a bond instrument you first have to decide what type of bond you need. The bond extension package currently supports the following bond types:
Fixed Rate¶
Fixed rate bonds pay a constant coupon each coupon period. The coupon is quoted on a yearly basis (per annum, p.a.), but it could be paid more frequently. For example, a bond could have a 2% p.a. coupon and a 6M coupon period. That would mean a 1% coupon is paid twice a year.
As an example we will create a bond instrument paying a 1.1% p.a. coupon with a 12M coupon period.
This example is taken from src/test/daml/Daml/Finance/Instrument/Bond/Test/FixedRate.daml
,
where all the details are available.
We start by defining the terms:
let
issueDate = date 2019 Jan 16
firstCouponDate = date 2019 May 15
maturityDate = date 2020 May 15
couponRate = 0.011
couponPeriod = M
couponPeriodMultiplier = 12
dayCountConvention = Act365Fixed
businessDayConvention = Following
The day count convention is used to determine how many days, i.e., what fraction of a full year, each coupon period has. This will determine the exact coupon amount that will be paid each period.
The business day convention determines how a coupon date is adjusted if it falls on a non-business day.
We can use these variables to create a PeriodicSchedule:
let
(y, m, d) = toGregorian firstCouponDate
periodicSchedule = PeriodicSchedule with
businessDayAdjustment =
BusinessDayAdjustment with
calendarIds = holidayCalendarIds
convention = businessDayConvention
effectiveDateBusinessDayAdjustment = None
terminationDateBusinessDayAdjustment = None
frequency =
Periodic Frequency with
rollConvention = DOM d
period = Period with
period = couponPeriod
periodMultiplier = couponPeriodMultiplier
effectiveDate = issueDate
firstRegularPeriodStartDate = Some firstCouponDate
lastRegularPeriodEndDate = Some maturityDate
stubPeriodType = None
terminationDate = maturityDate
This is used to determine the periods that are used to calculate the coupon. There are a few things to note here:
- The RollConventionEnum defines whether dates are rolled at the end of the month or on a given date of the month. In our example above, we went for the latter option.
- The StubPeriodTypeEnum
allows you to explicitly specify what kind of stub period the bond should have. This is optional
and not used in the example above. Instead, we defined the stub implicitly by specifying a
firstRegularPeriodStartDate
: since the time between the issue date and the first regular period start date is less than 12M (our regular coupon period), this implies a short initial stub period.
Now that we have defined the terms we can create the bond instrument:
cid <- toInterfaceContractId <$> submitMulti [depository, issuer] [] do
createCmd FixedRate.Instrument with
depository; issuer; id = Id label; version = "0"; description
observers = M.fromList observers; lastEventTimestamp; periodicSchedule; holidayCalendarIds
calendarDataProvider; dayCountConvention; couponRate; currency
Once this is done, you can create a holding on it using Account.credit.
Floating Rate¶
Floating rate bonds pay a coupon which is determined by a reference rate. There is also a rate spread, which is paid in addition to the reference rate.
Here is an example of a bond paying Euribor 3M + 1.1% p.a. with a 3M coupon period:
let
issueDate = date 2019 Jan 16
firstCouponDate = date 2019 Feb 15
maturityDate = date 2019 May 15
referenceRateId = "EUR/EURIBOR/3M"
couponSpread = 0.011
couponPeriod = M
couponPeriodMultiplier = 3
dayCountConvention = Act365Fixed
businessDayConvention = Following
Using these terms we can create the floating rate bond instrument:
cid <- toInterfaceContractId <$> submitMulti [depository, issuer] [] do
createCmd FloatingRate.Instrument with
depository; issuer; id = Id label; version = "0"; description
observers = M.fromList observers; lastEventTimestamp; periodicSchedule; holidayCalendarIds
calendarDataProvider; dayCountConvention; couponSpread; referenceRateId; currency
The reference rate (Euribor 3M) is observed once at the beginning of each coupon period and used for the coupon payment at the end of that period.
Inflation Linked¶
Inflation linked bonds pay a fixed coupon rate at the end of every coupon period. The coupon is calculated based on a principal that is adjusted according to an inflation index, for example the Consumer Price Index (CPI) in the U.S.
Here is an example of a bond paying 1.1% p.a. (on a CPI adjusted principal) with a 3M coupon period:
let
issueDate = date 2019 Jan 16
firstCouponDate = date 2019 Feb 15
maturityDate = date 2019 May 15
inflationIndexId = "CPI"
couponRate = 0.011
couponPeriod = M
couponPeriodMultiplier = 3
dayCountConvention = Act365Fixed
businessDayConvention = Following
Based on these terms we can create the inflation linked bond instrument:
cid <- toInterfaceContractId <$> submitMulti [depository, issuer] [] do
createCmd InflationLinked.Instrument with
depository; issuer; id = Id label; version = "0"; description
observers = M.fromList observers; lastEventTimestamp; periodicSchedule; holidayCalendarIds
calendarDataProvider; dayCountConvention; couponRate; inflationIndexId; currency
inflationIndexBaseValue
At maturity, the greater of the adjusted principal and the original principal is redeemed. For clarity, this only applies to the redemption amount. The coupons are always calculated based on the adjusted principal. This means that in the case of deflation, the coupons would be lower than the specified coupon rate but the original principal would still be redeemed at maturity.
Zero Coupon¶
A zero coupon bond does not pay any coupons at all. It only pays the redemption amount at maturity.
Here is an example of a zero coupon bond:
let
issueDate = date 2019 Jan 16
maturityDate = date 2020 May 15
Based on this we create the zero coupon bond instrument:
cid <- toInterfaceContractId <$> submitMulti [depository, issuer] [] do
createCmd ZeroCoupon.Instrument with
depository; issuer; id = Id label; version = "0"; description
observers = M.fromList observers; lastEventTimestamp; issueDate; maturityDate; currency
Frequently Asked Questions¶
How do I transfer or trade a bond?¶
When you have created a holding on a bond instrument this can be transferred to another party. This is described in the Getting Started: Transfer tutorial.
In order to trade a bond (transfer it in exchange for cash) you can also initiate a delivery versus payment with atomic settlement. This is described in the Getting Started: Settlement tutorial.
How do I process coupon payments for a bond?¶
On the coupon payment date, the issuer will need to lifecycle the bond. This will result in a lifecycle effect for the coupon, which can be cash settled. This is described in detail in the Lifecycling and the Intermediated Lifecycling tutorials.
How do I redeem a bond?¶
On the redemption date, both the last coupon and the redemption amount will be paid. This is processed in the same way as a single coupon payment described above.