Modelling fixed rate vanilla bonds in LUSID

You can model a simple fixed rate bond as an instrument of type Bond in LUSID. See all supported instruments.

Note LUSID has multiple instrument types for different kinds of bond:

Kind of bond

LUSID instrument type

More information

Fixed rate with regular coupons (only the first can be irregular)
Zero coupon

Bond

Continue reading this article.

Fixed rate with irregular coupons (other than the first)
Floating rate
Fixed-to-floating rate
Municipal
Callable
Puttable
Sinkable
Convertible

ComplexBond

Read this dedicated article.

Mortgage-backed security (MBS)

Read this dedicated article.

Inflation-linked

InflationLinkedBond

Read this dedicated article.

The rest of this article explains the lifecycle of a vanilla government bond issue with a regular coupon schedule and fixed principal. There is also an accompanying Jupyter Notebook that further demonstrates many of the operations and concepts.

Note: You should use the ComplexBond instrument type if your coupon schedule is irregular. The Bond instrument type can only accept an irregular first coupon period; all other coupons must be regular.

There are numerous tools you can use to master an instrument of type Bond 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 Bond. For more information on these fields, select Bond from the definition dropdown in the API documentation:

For example, the following call to the UpsertInstruments API masters a UK gilt in a custom instrument scope using a FIGI unique identifier. Note the fields specified below are the minimum required to master an instrument of type Bond:

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": "BBG00ZF1T9P5"}},
    "definition": {
      "instrumentType": "Bond",
      "startDate": "2016-10-22T10:00:00.0000000+00:00",
      "maturityDate": "2026-10-22T10:00:00.0000000+00:00",
      "domCcy": "GBP",
      "couponRate": 0.00375,
      "principal": 1,
      "flowConventions": {
        "currency": "GBP",
        "paymentFrequency": "6M",
        "dayCountConvention": "Actual365",
        "rollConvention": "22",
        "businessDayConvention": "Following"
      }
    }
  }
}'
JSON

Note the following:

  • The instrumentType must be Bond.

  • 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 principal can be any number, but we advise setting it to 1 to unitise the security and specifying the face or purchase amount on the transaction.

  • The flowConventions object stores all the information necessary to determine coupon periods, accrued interest amounts and payment dates:

    • The paymentFrequency field can be any tenor, in this case 6M to signify twice yearly. Supported day count conventions.

    • The rollConvention field should count back from the maturity date, 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-rate bonds. The scope and code fields can be ignored unless you are loading a flow convention from a library.

  • If you omit the exDividendConfiguration field, a bond has no ex-dividend period.

  • If you omit the roundingConventions array, no rounding conventions are applied at the instrument level.

  • If the first coupon payment is irregular, specify the firstCouponPayDate field.

Providing the request is successful, the response:

  • Confirms the globally-unique LUID for the instrument

  • Generates extra fields that are stored as part of the instrument definition and can be filtered on

  • Supplies default values for fields not explicitly specified in the request:

{
  "values": {
    "request_id_1": {
      "scope": "mycustominstrscope",
      "lusidInstrumentId": "LUID_00003DS1",
      "name": "UKT 0 ⅜ 10/22/26",
      "identifiers": {
        "LusidInstrumentId": "LUID_00003DS1",
        "Figi": "BBG00ZF1T9P5"
      },
      "properties": [],
      "instrumentDefinition": {
        "startDate": "2016-10-22T10:00:00.0000000+00:00",
        "maturityDate": "2026-10-22T10:00:00.0000000+00:00",
        "domCcy": "GBP",
        "flowConventions": {
          "currency": "GBP",
          "paymentFrequency": "6M",
          "dayCountConvention": "Actual365",
          "rollConvention": "22",
          "businessDayConvention": "Following",
          "paymentCalendars": [],
          "resetCalendars": [],
          "settleDays": 0,
          "resetDays": 0,
          "leapDaysIncluded": true,
          "accrualDateAdjustment": "Adjusted",
        },
        "principal": 1,
        "couponRate": 0.00375,
        "identifiers": {},
        "calculationType": "Standard",
        "roundingConventions": [],
        "instrumentType": "Bond"
      },
      "state": "Active",
      "assetClass": "Credit",
      "domCcy": "GBP",
      "relationships": []
    }
  },
  ...
}
JSON

LUSID uses the information in the flow convention to build a payment schedule. It implicitly assumes the last coupon period is regular, and counts back from the maturity date according to the payment frequency.

Note: Any bond with an irregular last coupon period must be mastered using the ComplexBond instrument type. More information.

If the bond has an irregular first coupon period you can set the optional firstCouponPayDate field to create either a long or short first coupon period.

Once an instrument is mastered, you can book a transaction to record the acquisition of a quantity in a particular transaction portfolio. As mentioned above, we recommend unitising bond instruments and specifying the face or purchase amount on transactions.

For example, the following call to the BatchUpsertTransactions API acquires 75,000,000 units of a UK gilt uniquely identified by its LUID:

curl -X POST 'https://<your-domain>.lusid.com/api/api/transactionportfolios/FixedIncome/UK/transactions/$batchUpsert?successMode=Partial&preserveProperties=true'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "transactionRequest-1": {
    "transactionId": "uk_gilt_purchase_001",
    "type": "BuyBond",
    "instrumentIdentifiers": {"Instrument/default/LusidInstrumentId": "LUID_00003DS1"},
    "transactionDate": "2024-02-22T00:00:00.0000000+00:00",
    "settlementDate": "2024-02-25T00:00:00.0000000+00:00",
    "units": 75000000,
    "transactionPrice": {
      "price": 102,
      "type": "CleanPrice"
    },
    "totalConsideration": {
      "amount": 0,
      "currency": "GBP"
    },
    "properties": {
      "Transaction/MyProperties/TradeCommission": {
        "key": "Transaction/MyProperties/TradeCommission",
        "value": {
          "metricValue": {
            "value": 200.00,
            "unit": "GBP"
          }
        }
      }
    }
  },
}'
JSON

Note the following:

  • The type field invokes a custom BuyBond transaction type to confer a particular economic impact (see below).

  • The units field specifies the face or purchase amount.

  • The transactionPrice object records the clean market price (not including bond interest). This is used by LUSID to automatically calculate the gross consideration (see below).

  • The totalConsideration object:

    • Sets the settlement currency to GBP.

    • Specifies a cost of 0 to enable LUSID to automatically derive the total consideration (see below).

  • The trade commission is recorded using a custom property.

Note: This example assumes the transaction, settlement and portfolio currencies are the same. If not, you can specify exchange rates.

You might create a BuyBond transaction type as follows:

curl -X PUT 'https://<your-domain>.lusid.com/api/api/transactionconfiguration/types/default/BuyBond?scope=default'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "aliases": [
    {
      "type": "BuyBond",
      "description": "Transaction type for bond purchases",
      "transactionClass": "Basic",
      "transactionRoles": "AllRoles",
      "isDefault": false
    }
  ],
  "movements": [
    {
      "name": "Increase units of security",
      "movementTypes": "StockMovement",
      "side": "Side1",
      "direction": 1
    },
    {
      "name": "Decrease cash balance",
      "movementTypes": "CashCommitment",
      "side": "Side2",
      "direction": -1
    },
    {
      "name": "Report bond interest bought as a flow of value out of the security",
      "movementTypes": "Carry",
      "side": "Side1",
      "direction": 1
    }
  ],
  "calculations": [
    {
      "type": "Txn:BondInterest"
    },
    {
      "type": "Txn:GrossConsideration"
    },
    {
      "type": "DeriveTotalConsideration",
      "formula": "Txn:GrossConsideration + Properties[Transaction/MyProperties/TradeCommission]"
    }
  ]
}'
JSON

Note the following:

  • The Txn:BondInterest calculation automatically calculates the amount of bond interest bought or sold and stores the result in the Transaction/default/BondInterest system property, available for use in sides.

  • If a clean price is specified, the Txn:GrossConsideration calculation automatically calculates gross consideration according to the formula (price * units) + Txn:BondInterest, and stores the result in the Transaction/default/GrossConsideration system property.

  • The DeriveTotalConsideration calculation automatically calculates total consideration according to the given, user-defined formula, which in this case sums gross consideration and total fees; this is stored as the totalConsideration.amount of the transaction.

  • The StockMovement uses the built-in Side1 side to establish a holding in the instrument with the specified number of units at a cost derived from the total consideration.

  • The CashCommitment movement uses the built-in Side2 to decrease the instrument currency holding by the total consideration.

  • The Carry movement uses the built-in Side1 to record a flow of value out of the instrument in an A2B report.

You can call the GetHoldings API to see the impact of the transaction on security and cash holdings. More coming soon.

You can call the BuildTransactions API to audit LUSID’s bond interest, gross consideration and total consideration calculations. More coming soon.

To value your position, work through our valuation checklist.

The following pricing models are available for instruments of type ComplexBond. Note your choice impacts the market data required and the composition of your recipe:

Note: The default model for bonds is currently ConstantTimeValueOfMoney, but we no longer recommend using it. You should change this to one of the alternatives above. See how to do this.

LUSID can report many hundreds of metrics in a valuation report. Note the following:

  • Valuation/PV* metrics calculate PV according to a formula specific to the pricing model.

  • Valuation/Accrued* metrics calculate accrual according to the flow convention defined in the underlying instrument. In most cases this increases in amount until the payment date, at which point it resets to zero and starts to accrue again the next day; there is no date on which the accrued appears as the full value of the coupon because it is assumed to be paid the day a period completes. You can use the Valuation/Diagnostics/Accrual/* metrics to diagnose accrual calculations.

  • Valuation/CleanPV* metrics calculate PV minus accrual.

  • ProfitAndLoss/* metrics calculate unrealised profit/loss as the difference between the PV at the start and end of the valuation period.

  • Analytic/* metrics calculate yield to maturity and duration.

LUSID provides an exposure calculation and supports both analytic and bump and valuation mechanisms for assessing risk.

Bonds typically produce a regular stream of cashflows and, upon maturity, return the final coupon and principal.

Note: An instrument cannot â€˜expire’ in LUSID; it is still available post-maturity, although the valuation is zero. If you set your holding to zero it no longer appears in reports unless you are deliberately backdating.

LUSID is transitioning to a system where it automatically emits lifecycle events for bonds. We provide default transaction templates that you can use as-is to automatically generate transactions in impacted portfolios, and recommendations for transaction types that deliver appropriate economic impacts. More information.

Contact us to turn this feature on in your environment. The following events are available for instruments of type Bond:

Instrument event type

Effect of LUSID default transaction template

Recommendations for transaction types

BondCouponEvent

A transaction is automatically generated for each bond coupon on its ex-dividend date, settling on its payment date. The total consideration is the coupon rate per unit scaled to the holding in a portfolio at that point in time.

See this tutorial.

BondPrincipalEvent

A single transaction is automatically generated on the bond's maturity date, settling at the same time. The total consideration is set to the number of units held in a portfolio at that point in time. 

MaturityEvent

A single transaction is automatically generated on the bond's maturity date, settling at the same time. The total consideration is set to zero.

In the LUSID web app you can use Dashboard > Transactions in Output mode with a suitable window to monitor historical and future transactions, or alternatively call the BuildTransactions API directly. For example, in the picture below:

  • Transactions in red represent historical bond coupon payments for the UK gilt mastered in this article with respect to a date 'today' of 26 February 2024;

  • Transactions in green represent future bond coupon payments, the return of principal, and close-out of the position upon maturity:

If you do not want to turn on automatic instrument lifecycle events you can continue to monitor upcoming cashflows using Dashboards > CashLadder in the LUSID web app, or by calling the GetPortfolioCashLadder API directly. Note the recipe you specify must currently be set to use the ConstantTimeValueOfMoney pricing model for bonds.

You can call the GetUpsertablePortfolioCashFlows API to  return imminent cashflows as upsertable DTOs ready to manually load into LUSID as input transactions.