Views:

Related resources:

Explanation

Tutorials

How-to guides

LUSID has a ComplexBond instrument type designed to model certain types of bond.

Type of bondLUSID instrument typeMore information
Fixed rate with irregular coupon schedule
Floating rate
Fixed-to-floating rate
Municipal
Callable
Puttable
Sinkable
Convertible
Mortgage-backed security (MBS)
ComplexBondThis article.
Fixed rate
Zero coupon
BondClick here.
Inflation-linkedInflationLinkedBondClick here.

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 instrumentType dropdown in the API documentation:

Alternatively, consult the SDK class reference documentation (the content is the same).

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 be ComplexBond.
  • The calculationType defaults to Standard. 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 and assetPoolIdentifier 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. Valid combinations are summarised in the table below.

    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 scheduleType of bondRate fixing
    Fixed rateFloating rateFixed-to-floating rate
    FixedScheduleAll1 or more01 or more
    FloatScheduleAll01 or more1 or more
    StepScheduleCallable0 or more0 or more0 or more
    Puttable0 or more0 or more0 or more
    Sinkable1 or more1 or more1 or more
    Convertible0 or more0 or more0 or more
    Municipal0 or more0 or more0 or more
    OptionalityScheduleCallable1 or more1 or more1 or more
    Puttable1 or more1 or more1 or more
    Sinkable0 or more0 or more0 or more
    Convertible0 or more0 or more0 or more
    Municipal0 or more0 or more0 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 scheduleType dropdown in the API documentation:

Alternatively, consult the SDK class reference documentation (the content is the same).

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 be FixedSchedule.
  • 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 of 0.1
    • 2.5% should have a couponRate of 0.025
    • 0.375% should have a couponRate of 0.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 case 6M to signify twice yearly. Supported day count conventions.
    • The rollConvention field should count back from maturity, so in this case 22 for a bond maturing on 22 October, which means the coupon dates are 22 October and 22 April each year. We also recommend setting a businessDayConvention 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 to Adjusted. This is suitable for European treasury bonds but for US treasury bonds we recommend Unadjusted.
    • The settleDays field in a flow convention is deprecated, and resetDays is ignored for fixed schedules. The scope and code 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 observation (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 scheduleType dropdown in the API documentation:

Alternatively, consult the SDK class reference documentation (the content is the same).

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 be FloatSchedule.
  • 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 an indexConvention 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 to INDEX but you can change this to a more intuitive description, for example LIBOR or SOFR.
    • The paymentTenor must be a tenor specifying the length of the interest rate period, in this case 12M. For OIS, specify 1D. Supported day count conventions.
  • The spread field defaults to 0 but you can specify a percentage as a decimal, for example 0.01 to record a spread of 1%.
  • The resetConvention field defaults to InAdvance. You can change this to InArrears.
  • 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 case 6M to signify twice yearly. Supported day count conventions.
    • The rollConvention field should count back from maturity, so in this case 22 for a bond maturing on 22 October, which means the coupon dates are 22 October and 22 April each year. We also recommend setting a businessDayConvention 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 to 0. You can specify a number of reset days if appropriate, and optionally one or more ResetCalendars to determine whether these are good business days.
    • The accrualDateAdjustment field is optional and defaults to Adjusted. This is suitable for European treasury bonds but for US treasury bonds we recommend Unadjusted.
    • The settleDays field in a flow convention is deprecated. The scope and code 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 scheduleField in floating scheduleCategory ACategory BCategory C
N/AresetConventionCan be InAdvance (the default) or InArrears.Must be InArrears.Must be InArrears.
indexConventionspaymentTenorCan be any tenor.Must be 1D.Must be 1D.
compounding
(More information)
compoundingMethodDo not set.Can be Averaging or Compounding.Must be CompoundedIndex.
spreadCompoundingMethodCan be Straight, Flat or SpreadExclusive for Compounding. Do not set for Averaging.Must be SpreadExclusive.
averagingMethodCan be Weighted (the default) or Unweighted for Averaging. Do not set for Compounding.Do not set.
resetFrequencyCan be any tenor.Must be 1D.
calculationShiftMethodCan be NoneLookback, NoShift, ObservationPeriodShift or Lockout.Can be None or ObservationPeriodShift.

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):

CategoryNumber of fixings to load
AOne per coupon period. This should be at the start if resetConvention is set to InAdvance, or at the end if InArrears.
BOne per day.
CTwo 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 (highlighted in green 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": "Price",
              "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": "Price",
              "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 of RIC.
    • Must have an instrumentId that is the fixingReference 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 of Lusid, a quoteType of Price and a field of mid, 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": "Price",
          "field": "mid"
        },
        ...
      ]
    },

    Note the following:

    • The key must have a prefix of Quote.RIC. and a suffix of the bond's fixingReference (highlighted in red above).
    • The dataScope must match the quote scope into which fixings were loaded (highlighted in green above).
    • 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 scheduleType dropdown in the API documentation:

    Alternatively, consult the SDK class reference documentation (the content is the same).

    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:

    LevelType fieldHow to calculate step quantitiesStep quantities for this exampleHow LUSID calculates notionals from step quantities
    15 Nov 202215 Nov 202315 Nov 202417 Nov 2025
    Absolutestep quantity = new notional800500600200new notional = step quantity
    AbsoluteShiftstep quantity = current notional - new notional200300-100400new notional = current notional - step quantity
    Percentagestep quantity = ((current notional - new notional) / original notional) * 1002030-1040new notional = current notional - (step quantity / 100) * original notional
    AbsolutePercentagestep quantity = (new notional / original notional) * 10080506020new 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 be StepSchedule.
    • The stepScheduleType in this case is Notional but it can be Coupon or Spread.
    • The steps array must contain one step object (consisting of a date and quantity) 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 scheduleType dropdown in the API documentation:

    Alternatively, consult the SDK class reference documentation (the content is the same).