LUSID has a ComplexBond
instrument type designed to model most kinds of bond.
Kind of bond | LUSID instrument type | More information |
---|---|---|
Fixed rate with irregular coupons (other than the first) |
| Continue reading this article. |
Fixed rate with regular coupons (only the first can be irregular) |
| |
Inflation-linked |
|
Mastering an instrument
There are numerous methods you can use to master an instrument of type ComplexBond
in the LUSID Security Master.
Some fields are common to all types of instrument, such as an intuitive name
, the requirement to specify a set of identifiers
, and the facility to store extra information as properties
.
Fields in the economic definition
object are specific to ComplexBond
. For more information on these fields, select ComplexBond from the definition dropdown in the API documentation:
Understanding the economic definition of a complex bond
The composition of the definition
object is highly dependent on the type of bond you want to master. Consider the following call to the UpsertInstruments API; note this is actually a no-op request since the schedules
array must be populated:
curl -X POST "https://<your-domain>.lusid.com/api/api/instruments?scope=mycustominstrscope"
-H "Content-Type: application/json-patch+json"
-H "Authorization: Bearer <your-API-access-token>"
-d '{
"upsert-request-1": {
"name": "UKT 0 ⅜ 10/22/26",
"identifiers": {"Figi": {"value": "BBG00ZF1T7P5"}},
"definition": {
"instrumentType": "ComplexBond",
"calculationType": "Standard",
"roundingConventions": [],
"schedules": [],
"assetBacked": "",
"assetPoolIdentifier": ""
}
}
}'
Within the definition
object:
The
instrumentType
must beComplexBond
.The
calculationType
defaults toStandard
. More information.The
roundingConventions
array can contain one or more rounding conventions. If you omit this field, no rounding is applied. More information.The
assetBacked
andassetPoolIdentifier
fields are only applicable to MBS and can otherwise be omitted or set to empty strings. More information.The
schedules
array must contain at least one schedule. Depending on the type of bond, you may need to specify multiple schedules, of the same type or a mix of different ones. For example, a callable fixed rate bond:Must have at least one
FixedSchedule
Cannot have a
FloatSchedule
Can have a
StepSchedule
(or more than one)Must have at least one
OptionalitySchedule
Type of LUSID schedule
Type of bond
Rate fixing
Fixed rate
Floating rate
Fixed-to-floating rate
All
1 or more
0
1 or more
All
0
1 or more
1 or more
Callable
0 or more
0 or more
0 or more
Puttable
0 or more
0 or more
0 or more
Sinkable
1 or more
1 or more
1 or more
Convertible
0 or more
0 or more
0 or more
Municipal
0 or more
0 or more
0 or more
Callable
1 or more
1 or more
1 or more
Puttable
1 or more
1 or more
1 or more
Sinkable
0 or more
0 or more
0 or more
Convertible
0 or more
0 or more
0 or more
Municipal
0 or more
0 or more
0 or more
Specifying a fixed schedule
You must specify a fixed schedule in the schedules
array if a bond uses a fixed rate to calculate coupon payments for at least part of its lifetime.
You may need to specify more than one fixed schedule if some parameter of the bond other than the coupon rate changes, for example the payment frequency switches from semi-annually to quarterly. Note if only the coupon rate changes it may be easier to add a step schedule instead of another fixed schedule.
For more information on the fields in a fixed schedule, select FixedSchedule from the definition > schedules dropdown in the API documentation:
Consider the following example of a single fixed schedule in the schedules
array; note the fields specified below are the minimum required:
"schedules": [
{
"scheduleType": "FixedSchedule",
"startDate": "2021-10-22T00:00:00+00:00",
"maturityDate": "2028-10-22T00:00:00+00:00",
"paymentCurrency": "GBP",
"notional": 100000,
"couponRate": 0.025,
"flowConventions": {
"paymentFrequency": "6M",
"dayCountConvention": "ActActIsma",
"rollConvention": "22",
"businessDayConvention": "Following",
"currency": "GBP",
}
}
]
Note the following:
The
scheduleType
must beFixedSchedule
.The
startDate
should be the accrual start date; that is, the date from which interest is calculated.The maximum
maturityDate
is 31 December 2140.The
couponRate
should be expressed as a decimal rather than a percentage, so a bond paying:10% should have a
couponRate
of0.1
2.5% should have a
couponRate
of0.025
0.375% should have a
couponRate
of0.00375
.
The
flowConventions
object stores all the information necessary to determine coupon periods, accrued interest amounts and payment dates:The
paymentFrequency
can be any tenor, in this case6M
to signify twice yearly. Supported day count conventions.The
rollConvention
field should count back from maturity, so in this case22
for a bond maturing on 22 October, which means the coupon dates are 22 October and 22 April each year. We also recommend setting abusinessDayConvention
to determine what should happen if this is not a good business day. More information on roll and business day conventions. Note business days in LUSID are determined by holiday calendars.The
accrualDateAdjustment
field is optional and defaults toAdjusted
. This is suitable for European treasury bonds but for US treasury bonds we recommendUnadjusted
.The
settleDays
field in a flow convention is deprecated, andresetDays
is ignored for fixed schedules. Thescope
andcode
fields can be ignored unless you are loading a flow convention from a library.
If you do not specify an
exDividendConfiguration
object, a bond has no ex-dividend period. More information.If you do not specify a
stubType
, the first and last coupon periods are expected to be regular. More information.
Specifying a floating schedule
You must specify a floating schedule in the schedules
array if a bond uses a floating rate to calculate coupon payments for at least part of its lifetime.
Note: You must load reference rate observations (fixings) into the LUSID Quote Store and provide a recipe that can locate these fixings in order to calculate accrued interest. More information.
For more information on the fields in a floating schedule, select FloatSchedule from the definition > schedules dropdown in the API documentation:
Note that floating rate bonds can be grouped into three categories based on the nature of the underlying reference index and how it is used in coupon payment calculations:
Category A: The reference rate is observed once per coupon period. The observation can be made in advance of the interest rate period, or towards the end 'in arrears'. Older and LIBOR-referencing bonds are examples of this group.
Category B: The reference rate is observed more than once per coupon period, up to daily for overnight indices like SONIA or SOFR, with the implication that the final coupon payment can be calculated only at the end of the period.
Category C: The reference rate is a compounded index like the compounding SOFR index. These indices are published daily and they remove the necessity to capture daily fixings needed for a coupon amount calculation. The compounding indices are built from the daily SOFR fixings so the final coupon amount can be calculated only at the end of the coupon period.
Note: For all three categories, the basic principle of specifying a floating rate schedule is the same, but note these important differences.
Consider the following example, of a single floating schedule for a bond in Category A above; note the fields specified below are the minimum required:
"schedules": [
{
"scheduleType": "FloatSchedule",
"startDate": "2021-10-22T00:00:00+00:00",
"maturityDate": "2028-10-22T00:00:00+00:00",
"paymentCurrency": "GBP",
"notional": 100000,
"indexConventions": {
"fixingReference": "GBP1YBMK",
"publicationDayLag": 1,
"paymentTenor": "12M",
"dayCountConvention": "ActActIsma",
"currency": "GBP"
},
"flowConventions": {
"paymentFrequency": "6M",
"dayCountConvention": "ActActIsma",
"rollConvention": "22",
"businessDayConvention": "Following",
"currency": "GBP",
},
}
]
Note the following:
The
scheduleType
must beFloatSchedule
.The
startDate
should be the accrual start date; that is, the date from which interest is calculated.The maximum
maturityDate
is 31 December 2140.Unlike a fixed schedule, a
couponRate
is not required. Instead, you specify anindexConvention
object that identifies a reference index to look up rates and fixings:The
fixingReference
should be an intuitive string that enables LUSID to look up fixing(s) in the Quote Store each time an accrued interest calculation is required. More information.The
indexName
defaults toINDEX
but you can change this to a more intuitive description, for exampleLIBOR
orSOFR
.The
paymentTenor
must be a tenor specifying the length of the interest rate period, in this case12M
. For OIS, specify1D
. Supported day count conventions.
The
spread
field defaults to0
but you can specify a percentage as a decimal, for example0.01
to record a spread of 1%.The
resetConvention
field defaults toInAdvance
. You can change this toInArrears
.The
flowConventions
object stores all the information necessary to determine coupon periods, accrued interest amounts and payment dates:The
paymentFrequency
can be any tenor, in this case6M
to signify twice yearly. Supported day count conventions.The
rollConvention
field should count back from maturity, so in this case22
for a bond maturing on 22 October, which means the coupon dates are 22 October and 22 April each year. We also recommend setting abusinessDayConvention
to determine what should happen if this is not a good business day. More information on roll and business day conventions. Note business days in LUSID are determined by holiday calendars.The
resetDays
field defaults to0
. You can specify a number of reset days if appropriate, and optionally one or moreResetCalendars
to determine whether these are good business days.The
accrualDateAdjustment
field is optional and defaults toAdjusted
. This is suitable for European treasury bonds but for US treasury bonds we recommendUnadjusted
.The
settleDays
field in a flow convention is deprecated. Thescope
andcode
fields can be ignored unless you are loading a flow convention from a library.
If you do not specify an
exDividendConfiguration
object, a bond has no ex-dividend period. More information.If you do not specify a
stubType
, the first and last coupon periods are expected to be regular. More information.
Note the following differences between the three categories:
Parent object in floating schedule | Field in floating schedule | Category A | Category B | Category C |
---|---|---|---|---|
N/A |
| Can be | Must be | Must be |
|
| Can be any tenor. | Must be | Must be |
|
| Do not set. | Can be | Must be |
| Can be | Must be | ||
| Can be | Do not set. | ||
| Can be any tenor. | Must be | ||
| Can be | Can be |
Loading fixings into the LUSID Quote Store
You must load the correct number of fixings into the Quote Store and provide a recipe that enables LUSID to locate these fixings every time an accrued interest calculation is required (which is each time you ask LUSID to value a holding in the bond or generate cashflows):
Category | Number of fixings to load |
---|---|
A | One per coupon period. This should be at the start if |
B | One per day. |
C | Two per calculation period, one at the start of the coupon period and one at the effective at datetime of the valuation or cashflow generation request. Note this means if you make such a request every day you will need to load a fixing every day. |
Consider the example of a Category C bond with a quarterly coupon period and the following fixingReference
:
"indexConventions": {
"fixingReference": "USD-1D-SOFRINDEX",
...
}
The following call to the UpsertQuotes API loads two fixings for this bond for Q1 2023 into a MyFixings
quote scope (in the URL), one on the first day of this period and one on the last day:
curl -X POST "https://<your-domain>.lusid.com/api/api/quotes/MyFixings"
-H "Authorization: Bearer <your-API-access-token>"
-H "Content-Type: application/json-patch+json"
-d '{
"Quote-0001": {
"quoteId": {
"quoteSeriesId": {
"provider": "Lusid",
"instrumentIdType": "RIC",
"instrumentId": "USD-1D-SOFRINDEX",
"quoteType": "Rate",
"field": "mid"
},
"effectiveAt": "2023-01-01T17:00:00Z"
},
"metricValue": {
"value": 1.111648, "unit": "rate"
}
},
"Quote-0002": {
"quoteId": {
"quoteSeriesId": {
"provider": "Lusid",
"instrumentIdType": "RIC",
"instrumentId": "USD-1D-SOFRINDEX",
"quoteType": "Rate",
"field": "mid"
},
"effectiveAt": "2023-03-31T17:00:00Z"
},
"metricValue": {
"value": 1.123209, "unit": "rate"
}
}
}'
For general information on loading quotes into the Quote Store, see this article. Note that a quote for a fixing:
Must have an
instrumentIdType
ofRIC
.Must have an
instrumentId
that is thefixingReference
specified in the bond's index convention.Should be loaded into a quote scope that you only use for fixings, to avoid clashes.
Should have a
provider
ofLusid
, aquoteType
ofRate
and afield
ofmid
, to avoid validation errors.
When you value a holding in this bond or generate cashflows, you must provide a recipe with a market data rule that is able to locate these fixings, for example:
"market": {
"marketRules": [
{
"key": "Quote.RIC.USD-1D-SOFRINDEX",
"dataScope": "MyFixings",
"supplier": "Lusid",
"quoteType": "Rate",
"field": "mid"
},
...
]
},
Note the following:
The
key
must have a prefix ofQuote.RIC.
and a suffix of the bond'sfixingReference
.The
dataScope
must match the quote scope into which fixings were loaded.The other fields must match their respective quote fields exactly (values are case-sensitive).
Specifying a step schedule
You must specify a step schedule in the schedules
array to record notional change for a sinkable fixed rate, floating rate or fixed-to-floating rate bond.
Note: You can specify a step schedule for a bond whose coupon rate or spread changes during its lifetime.
For more information on the fields in a step schedule, select StepSchedule from the definition > schedules dropdown in the API documentation:
Consider the example of a bond whose original notional value of 1000 changes four times according to the following published schedule:
800 on 15 November 2022
500 on 15 November 2023
600 on 15 November 2024
200 on 17 November 2025.
One step is required in the schedule for each date on which the notional value changes.
You can capture notional change using one of four 'level types'. The one to choose depends largely on the information available to you and the convenience of translating it into LUSID:
| How to calculate step quantities | Step quantities for this example | How LUSID calculates notionals from step quantities | |||
---|---|---|---|---|---|---|
15 Nov 2022 | 15 Nov 2023 | 15 Nov 2024 | 17 Nov 2025 | |||
| step quantity = new notional | 800 | 500 | 600 | 200 | new notional = step quantity |
| step quantity = current notional - new notional | 200 | 300 | -100 | 400 | new notional = current notional - step quantity |
| step quantity = ((current notional - new notional) / original notional) * 100 | 20 | 30 | -10 | 40 | new notional = current notional - (step quantity / 100) * original notional |
| step quantity = (new notional / original notional) * 100 | 80 | 50 | 60 | 20 | new notional = (step quantity / 100) * original notional |
A step schedule to capture the notional change in this example using a LevelType
of Absolute
would look like this:
"schedules": [
{
"scheduleType": "StepSchedule",
"levelType": "Absolute",
"stepScheduleType": "Notional",
"steps": [
{"date": "2022-11-15", "quantity": 800},
{"date": "2023-11-15", "quantity": 500},
{"date": "2024-11-15", "quantity": 600},
{"date": "2025-11-17", "quantity": 400}
]
}
]
Note the following:
The
scheduleType
must beStepSchedule
.The
stepScheduleType
in this case isNotional
but it can beCoupon
orSpread
.The
steps
array must contain one step object (consisting of adate
andquantity
) for each change to the notional; that is, one fewer than the total number of coupon periods with different notional amounts.
Specifying an optionality schedule
You must specify an optionality schedule in the schedules
array to capture exercise dates for a callable or puttable fixed rate, floating rate or fixed-to-floating rate bond.
For more information on the fields in an optionality schedule, select OptionalitySchedule from the definition > schedules dropdown in the API documentation:
More information coming soon