Observations (using a floating rate bond)¶
This tutorial describes how to define observations. It builds on the previous
Time-based Lifecycling tutorial, which uses a fixed rate bond where all
coupons are pre-defined using a constant annualized rate. In contrast, the coupons of a
floating rate bond depend on the value of a reference rate for each coupon period. Hence, the
lifecycling framework requires the future values of the reference rate. This is referred to as
Observations
, which is the main topic of this tutorial.
In this tutorial, we are going to:
- create a floating rate bond instrument and book a holding on it
- create an observation of the floating rate, which is used to define the coupon payment
- reuse the lifecycle rule and lifecycle event from the fixed rate bond tutorial
- process the event to produce the effects of a coupon payment
- instruct settlement by presenting a bond holding
- settle the resulting batch atomically
Run the Script¶
The code for this tutorial can be executed via the runFloatingRateBond
script in the
FloatingRateBond.daml
module.
Instrument and Holding¶
For the purpose of showcasing the Observation concept, we need a suitable sample instrument. Floating rate bonds pay a coupon which is determined by a reference rate, e.g. 3M Libor. The Bond Instrument packages page describes this instrument in more detail. Here, we briefly show how to create the bond instrument using a factory:
-- Create a floating rate bond factory
floatingRateBondFactoryCid <- toInterfaceContractId @FloatingRateBondFactory.I <$> submit bank do
createCmd FloatingRateBond.Factory with
provider = bank
observers = mempty
-- Define an instrument key for the bond
let
bondInstrument = InstrumentKey with
issuer = bank
depository = bank
id = Id "FloatingRateBond"
version = "0"
holdingStandard = TransferableFungible
-- Bank creates the bond instrument
floatingRateBondCid <- submit bank do
exerciseCmd floatingRateBondFactoryCid FloatingRateBondFactory.Create with
floatingRate = FloatingRate with
instrument = bondInstrument
description = "Instrument representing units of a floating rate bond"
floatingRate
couponSpread
periodicSchedule
holidayCalendarIds
calendarDataProvider = bank
dayCountConvention
currency = usdInstrument
notional
lastEventTimestamp = initialTimestamp
observers = Map.fromList pp
Compared to the fixed rate bond, notice that this floating rate instrument also has a
referenceRateId
, that specifies which Observations
to use in the lifecycling section below.
We also create a bond holding in Bob’s account:
-- Credit Bob's account with a bond holding
bobRequestCid <- submit bob do
createCmd CreditAccount.Request with
account = bobAccount
instrument = bondInstrument
amount = 100000.0
bobBondHoldingCid <- submit bank do exerciseCmd bobRequestCid CreditAccount.Accept
Now, we have both an instrument definition and a holding. Let us proceed to lifecycle the bond using
Observations
, which is the main purpose of this tutorial.
Lifecycle Events and Rule¶
An Observation of a reference rate contains two pieces of information: the interest rate level and the date to which it applies. The rate level can be positive or negative. In our example, we have a negative interest rate:
let observations = Map.fromList [(dateToDateClockTime $ date 2019 Jan 16, -0.00311)]
observableCid <- toInterfaceContractId <$> submit bank do
createCmd Observation with
provider = bank; id = Id referenceRateId; observations; observers = mempty
In our case, the bank then creates the observation on the ledger. The Observation implements the NumericObservable interface, which is used during lifecycling.
In order to lifecycle a coupon payment, we need a lifecycle rule that defines how to process all time events. We also need a time event corresponding to the date of the first coupon. Both of these are the same as in the previous tutorial using a fixed rate bond, so we will reuse them from there.
Now, we have what we need to actually lifecycle the bond:
-- Try to lifecycle the instrument
(lifecycleCid, [effectCid]) <- submit bank do
exerciseCmd lifecycleRuleCid Lifecycle.Evolve with
eventCid = firstCouponClockEventCid
observableCids = [observableCid]
instrument = bondInstrument
The difference compared to the previous tutorial is that here we also pass in the observables to the Evolve choice. They are used to evaluate the reference rate on the relevant fixing date of the coupon payment currently being lifecycled.
The result of this is an effect describing the per-unit asset movements to be executed for bond holders. Each holder can now present their holding to claim the effect and instruct settlement of the associated entitlements.
The remaining steps (define a claim rule, claim the effect and settle the entitlements) are identical to the previous tutorial.
Note that the lifecycling process above is not limited to floating rate bonds, which have a reference rate as observable. It also works for other instruments that depend on an underlying asset, for example:
Instrument | Observed variable |
---|---|
Inflation linked bond | Inflation index |
Interest rate swap | Reference rate (similar to a floating rate bond) |
Asset swap | Reference asset |
Credit default swap | Default probability & Recovery rate (two observables) |
Vanilla option | Reference asset (often end of day fixing) |
Barrier option | Reference asset (often intraday observations) |
Frequently Asked Questions¶
Which party should create the observations?¶
In the simplified scenario for this tutorial, the bank created the observation. In a real-world case, it would probably be the issuer (or a 3rd-party reference data agent) that creates the observations.
Summary¶
You have learned how to create a floating rate bond and how to define observations that define the amount of the coupon payments. The key concepts to take away are:
- Observations are required in order to lifecycle some instruments.
- Observations are a general concept that can be used to model different kind of payoffs, using various types of underlyings.
- Lifecycling instruments with observations works in a very similar manner compared to those without.