---
title: "Modelling mortgage-backed securities in LUSID"
slug: "modelling-mortgage-backed-securities-in-lusid"
updated: 2026-03-01T13:40:04Z
published: 2026-03-01T13:40:04Z
canonical: "support.lusid.com/modelling-mortgage-backed-securities-in-lusid"
---

> ## Documentation Index
> Fetch the complete documentation index at: https://support.lusid.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Modelling mortgage-backed securities in LUSID

You can model a mortgage-backed security (MBS) contract as a special kind of `ComplexBond` in LUSID. [See other uses for this instrument type](/v1/docs/modelling-complex-bonds-in-lusid).

## Mastering an instrument

There are [numerous tools](/v1/docs/how-do-i-master-an-instrument) you can use to master a MBS contract as an instrument as 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](/v1/docs/understanding-instrument-identifiers) of `identifiers`, and the facility to [store extra information](/v1/docs/properties) 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](https://www.lusid.com/docs/api/lusid/endpoints/instruments/UpsertInstruments):

![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/image(162).png)

In this tutorial, we’ll master a simple fixed schedule MBS contract by calling the [UpsertInstruments](https://www.lusid.com/docs/api/lusid/endpoints/instruments/UpsertInstruments/) API as follows:

```json
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": "MBS",
    "identifiers": {"ClientInternal": {"value": "MBS"}},
    "definition": {
      "instrumentType": "ComplexBond",                   
      "assetBacked": true,
      "assetPoolIdentifier": "MyMBSMarketDataIdentifier",
      "schedules": [
        {
          "scheduleType": "FixedSchedule",
          "startDate": "2024-12-01T00:00:00+00:00",
          "maturityDate": "2026-11-20T00:00:00+00:00",
          "paymentCurrency": "USD",
          "notional": 1,
          "couponRate": 0.05,
          "flowConventions": {
            "paymentFrequency": "1M",
            "dayCountConvention": "Act365",
            "rollConvention": "20",
            "businessDayConvention": "Following",
            "paymentCalendars": ["USD"],
            "currency": "USD",
            "accrualDateAdjustment": "Unadjusted",
          },
          "exDividendConfiguration": {
            "exDividendDays": 19,
            "applyThirty360PayDelay": true,
          }
        }
      ]
    }
  }
}'
```

Note the following:

- We’ve chosen to master this instrument in a [custom instrument scope](/v1/docs/understanding-instrument-scopes) (specified in the URL).
- The `identifiers` field uniquely identifies the instrument using a `ClientInternal` [identifier](/v1/docs/what-are-unique-and-non-unique-identifiers).
- In the economic `definition` object:
  - The `instrumentType` must be `ComplexBond`.
  - The `assetBacked` field must be `true` to distinguish a MBS contract from other non-backed instruments mastered as type `ComplexBond`.
  - The `assetPoolIdentifier` should be set to an intuitive string that represents a market data identifier for pool factors loaded into the LUSID Quote Store (required for calculating principal repayments).
  - The `notional` should be unitised (set to `1`) and the amount bought or sold specified on the transaction.
  - The `couponRate` should be expressed as a decimal rather than a percentage, so a bond paying:
    - 10% should have a `couponRate` of `0.1`
    - 5.0% should have a `couponRate` of `0.05`
    - 0.375% should have a `couponRate` of `0.00375` and so on.
  - The `flowConventions` object stores all the information necessary to determine [coupon periods, accrued interest amounts and payment dates](/v1/docs/flow-conventions-and-index-conventions):
    - The `paymentFrequency` can be any [tenor](/v1/docs/specifying-tenors-in-lusid), in this case `1M` to signify once a month. [Supported day count conventions](/v1/docs/day-count-conventions-supported-by-lusid).
    - The `rollConvention` field should count back from maturity, so in this case `20` for a bond maturing on 20 November, which means the coupon dates are the 20th of every month. 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](/v1/docs/roll-conventions-and-business-day-conventions). Note business days in LUSID are determined by [holiday calendars](/v1/docs/using-calendars-in-lusid).
    - The `accrualDateAdjustment` field is optional and defaults to `Adjusted`. This is suitable for European bonds but for US 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.
  - The `exDividendConfiguration` object configures a special ex-div period for a MBS contract:
    - The `exDividendDays` field should record the difference between the coupon day and the first day of the month (when pool factors should be recorded in LUSID), so in this case `20 - 1 = 19`. **Note**: Do not specify the `exDividendDays` field on its own (that is, outside this object).
    - The `applyThirty360PayDelay` field should be set to `true` to delay coupon and principal payments to the following month.
  - If you do not specify a `stubType` object, the first and last coupon periods are expected to be regular. *More information coming soon*.
  - The `tradingConventions.priceScaleFactor` field is set to 100 so market prices can be entered as a percentage of par.
  - If you do not specify a `roundingConventions` object, [no rounding is applied](/v1/docs/how-does-lusid-handle-rounding-conventions) at the instrument level.

Providing the request is successful, the response:

- Confirms the globally-unique [LUID](/v1/docs/what-is-a-lusid-instrument-id-or-luid) for the instrument.
- Generates extra fields that are stored as part of the instrument definition and can be [filtered on](/v1/docs/filtering-information-retrieved-from-lusid).
- Supplies default values for fields not explicitly specified in the request:

```json
{
  "values": {
    "upsert-request-1": {
      "scope": "mycustominstrscope",
      "lusidInstrumentId": "LUID_00003EDZ",
      "version": {
        "asAtCreated": "2025-04-24T11:10:25.8725820+00:00",
        "userIdCreated": "00u91lo2d7X42sdse2p7",
        "requestIdCreated": "2025042411-35bc0fe68ef8414f9766ca62e6613d4b",
        "asAtModified": "2025-04-24T11:20:41.4671350+00:00",
        "userIdModified": "00u91lo2d7X42sdse2p7",
        "requestIdModified": "2025042411-65bd46cf085f4f43899b9d3004a3cff9",
        "asAtVersionNumber": 1,
        "entityUniqueId": "9c64bc2b-fe0b-4e95-b91c-7f8e5b11cc02"
      },
      "name": "MBS",
      "identifiers": {
        "LusidInstrumentId": "LUID_00003EDZ",
        "ClientInternal": "MBS"
      },
      "properties": [],
      "instrumentDefinition": {
        "identifiers": {},
        "calculationType": "Standard",
        "schedules": [
          {
            "startDate": "2024-12-01T00:00:00.0000000+00:00",
            "maturityDate": "2026-11-20T00:00:00.0000000+00:00",
            "flowConventions": {
              "currency": "USD",
              "paymentFrequency": "1M",
              "dayCountConvention": "Actual365",
              "rollConvention": "20",
              "paymentCalendars": [
                "USD"
              ],
              "resetCalendars": [],
              "settleDays": 0,
              "resetDays": 0,
              "leapDaysIncluded": true,
              "accrualDateAdjustment": "Unadjusted",
              "businessDayConvention": "F",
              "accrualDayCountConvention": "Actual365"
            },
            "couponRate": 0.05,
            "notional": 1,
            "paymentCurrency": "USD",
            "stubType": "None",
            "exDividendConfiguration": {
              "useBusinessDays": false,
              "exDividendDays": 19,
              "returnNegativeAccrued": false,
              "applyThirty360PayDelay": true
            },
            "scheduleType": "FixedSchedule"
          }
        ],
        "roundingConventions": [],
        "assetBacked": true,
        "assetPoolIdentifier": "MyMBSMarketDataIdentifier",
        "tradingConventions": {
          "priceScaleFactor": 100,
          "minimumOrderSize": 0,
          "minimumOrderIncrement": 0
        },
        "instrumentType": "ComplexBond"
      },
      "state": "Active",
      "assetClass": "Credit",
      "domCcy": "USD",
      "relationships": []
    }
  },
  ...
}
```

## Loading initial, opening and closing pool factors

LUSID requires pool factors loaded into the LUSID Quote Store in order to calculate the current face each month over the lifetime of the MBS contract.

To start, we must load three pool factors:

A pool factor of `1` for the instrument `startDate`. In our example, this is 1 December 2024.

The published pool factor for the first of the month in which we purchase the MBS contract. In our example, the transaction date 10 January 2025, so let’s imagine the published pool factor on 1 January 2025 is 0.95.

A pool factor of `0` for the first of the month in which the instrument matures, in order to close the positio. In our example, the the maturity_date is 20 November 2025, so this is 1 November 2025. Setting the pool factor to `0` enables LUSID to close the position.

We must also create a recipe that enable both LUSID to locate these pool factors. The following recipe sets the lookback period for pool factors to the recommended maximum of two months. In addition, note it is also suitable for locating market prices, and pool factors for (more on these later), and so can be used as both a valuation and

## Booking a transaction to establish a position

Once an instrument is mastered and initial, there are numerous ways we can [book a transaction](/v1/docs/how-do-i-create-or-update-a-transaction) to record the acquisition of a quantity in a suitable portfolio, for example calling the `BatchUpsertTransactions` API as follows:

```json
curl -X POST 'https://<your-domain>.lusid.com/api/api/transactionportfolios/FixedIncome/US/transactions/$batchUpsert?successMode=Partial&preserveProperties=true'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "transactionRequest-1": {
    "transactionId": "mbs_purchase_001",
    "type": "BuyMBS",
    "instrumentIdentifiers": {"Instrument/default/ClientInternal": "MBS"},
    "transactionDate": "2025-01-10T00:00:00.0000000+00:00",
    "settlementDate": "2025-01-13T00:00:00.0000000+00:00",
    "units": 100000,
    "transactionPrice": {
      "price": 0.98,
      "type": "CleanPrice"
    },
    "totalConsideration": {
      "amount": 0,
      "currency": "USD"
    },
    "properties": {
      "Transaction/MyProperties/TotalCapitalisedFees": {
        "key": "Transaction/MyProperties/TotalCapitalisedFees",
        "value": {
          "metricValue": {
            "value": 200,
            "unit": "USD"
          }
        }
      }
    }
  }
}'
```

Note the following:

- The `instrumentIdentifiers` field uses the `ClientInternal` identifier to [resolve the transaction](/v1/docs/how-does-lusid-resolve-data-to-instruments) to the correct MBS instrument (but it could use the LUID).
- The `type` field invokes a custom `BuyMBS` [transaction type](/v1/docs/what-is-a-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 accrued interest). This is used by LUSID to automatically calculate gross consideration (see below).
- The `totalConsideration` object:
  - Sets the settlement currency to `USD`.
  - Specifies a cost of `0` to trigger LUSID to automatically derive total consideration (see below).
- The trade fee is recorded using a [custom property](/v1/docs/properties).

> **Note**: This example assumes the transaction, settlement and portfolio currencies are the same. If not, you can [specify exchange rates](/v1/docs/transactions-and-exchange-rates).

We can call the [SetTransactionType](https://www.lusid.com/docs/api#operation/SetTransactionType) API to create a `BuyMBS` transaction type as follows:

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

Note the following:

- The `Txn:BondInterest` [calculation](/v1/docs/what-is-a-transaction-type-calculation#txnbondinterest) automatically calculates the amount of accrued interest bought or sold and stores the result in the `Transaction/default/BondInterest` system property.
- As a clean price is specified, the `Txn:GrossConsideration` [calculation](/v1/docs/what-is-a-transaction-type-calculation#txngrossconsideration) automatically calculates gross consideration according to the formula `(units * price * Transaction/default/CurrentFace) + Transaction/default/BondInterest`, and stores the result in the `Transaction/default/GrossConsideration` system property.
- The `DeriveTotalConsideration` [calculation](/v1/docs/what-is-a-transaction-type-calculation#derivetotalconsideration) 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 a `Side1WithCurrentFace` custom side (see below) to establish a holding in the instrument with the specified number of units at a cost derived from the total consideration, and a record of the starting current face.
- The `CashCommitment` movement uses the [built-in](https://support.lusid.com/docs/what-built-in-transaction-types-and-sides-are-provided-with-lusid#builtin-sides) `Side2` to decrease the instrument currency holding by the total consideration.

We can call the [SetSideDefinition](https://www.lusid.com/docs/api/lusid/endpoints/transaction-configuration/SetSideDefinition/) API to create a `Side1WithCurrentFace` custom side as follows:

```json
curl -X PUT 'https://<your-domain>.lusid.com/api/api/transactionconfiguration/sides/Side1WithCurrentFace?scope=default'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "security": "Txn:LusidInstrumentId",
  "currency": "Txn:TradeCurrency",
  "rate": "Txn:TradeToPortfolioRate",
  "units": "Txn:Units",
  "amount": "Txn:TradeAmount",
  "currentFace": "Txn:CurrentFace"
}'
```

Note this is the same as the [built-in](https://support.lusid.com/docs/what-built-in-transaction-types-and-sides-are-provided-with-lusid#builtin-sides) `Side1` except the `currentFace` field is set to `Txn:CurrentFace`, which returns the value of the `Transaction/default/CurrentFace` system property added to the transaction.

### Auditing LUSID’s calculations of transaction amounts

We can navigate to **Portfolio Management > Transactions** in **Output** mode in the LUSID web app to call the [BuildTransactions](https://www.lusid.com/docs/api/lusid/endpoints/transaction-portfolios/BuildTransactions/) API with a suitable window and examine the [output transaction](/v1/docs/input-and-output-transactions) generated by LUSID:

- The gross transaction amount is `units * price * Transaction/default/CurrentFace`, so `100000 × 0.98 × 0.95 = 93100`
- The amount of accrued interest purchased is `164.38`
- Since the price is clean, the gross consideration is the gross transaction amount plus accrued interest: `93100 + 164.38 = 93264.38`
- The total consideration is gross consideration plus fees: `93264.38 + 200 = 93464.38`:

![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/image(795).png)

### Confirming positions on the settlement date

We can navigate to **Portfolio Management > Holdings** to call the [GetHoldings](https://www.lusid.com/docs/api/lusid/endpoints/transaction-portfolios/GetHoldings/) API on the settlement date and see that we have:

- 100,000 units of the MBS instrument with a cost calculated as total consideration minus accrued interest: `93464.38 - 164.38 = 93300`
- A USD currency holding with a negative amount reflecting the total consideration paid: ***change Effective dropdown to show Settlement date…***

![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/image(796).png)

## Valuing your position

To value your position, work through our [valuation checklist](/v1/docs/valuation-checklist).

### Pricing models

The following [pricing models](/v1/docs/what-pricing-models-can-i-use-in-my-valuation) are available for instruments of type `ComplexBond`. Note your choice impacts the market data required and the composition of your recipe:

- [BondLookupPricer](https://support.lusid.com/docs/what-pricing-models-can-i-use-in-my-valuation#instrumentspecific-pricing-models) (strongly recommended)
- [SimpleStatic](https://support.lusid.com/docs/what-pricing-models-can-i-use-in-my-valuation#general-pricing-models)
- [Discounting](https://support.lusid.com/docs/what-pricing-models-can-i-use-in-my-valuation#general-pricing-models)

> **Note**: The default pricing model for bonds is currently `ConstantTimeValueOfMoney`, but we no longer recommend it. You should change this to one of the alternatives above. [See how to do this](/v1/docs/recipes-changing-the-default-pricing-models-for-instrument-types).

### Metrics

LUSID can report many hundreds of [metrics](/v1/docs/what-is-a-metric) in a valuation report. Note the following:

- `Valuation/PV*` metrics [calculate PV](/v1/docs/how-does-lusid-calculate-pv) according to a formula specific to the pricing model.
- `Valuation/Accrued*` metrics [calculate accrual](/v1/docs/how-does-lusid-calculate-accrued-interest) 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.
- `Valuation/Diagnostics/Accrual/*` metrics [diagnose accrual calculations](/v1/docs/how-does-lusid-calculate-accrued-interest#diagnosing-calculations-in-valuation-reports).
- `Valuation/CleanPV*` metrics calculate PV minus accrual.
- `ProfitAndLoss/*` metrics [calculate unrealised profit/loss](/v1/docs/how-does-lusid-calculate-pl) as the difference between the PV and the holding cost at the start and again at the end of the valuation period.
- `Analytic/*` metrics [calculate yield to maturity and duration](/v1/docs/how-does-lusid-calculate-yield-to-maturity-and-duration).

### Market data

To value a MBS instrument position using the recommended `BondLookupPricer` model, load the following market data for the valuation date:

1. A market price. This should be a clean price specified as a percentage of par. The quote can resolve to the MBS instrument using any identifier. The `scaleFactor` should be `100`.
2. A pool factor. This must have a `quoteType` of `PoolFactor` and an `instrumentIdType` of `Isin` but the `instrumentId` should be the `assetPoolIdentifier` value specified in the instrument economic definition. The `scaleFactor` should be `100`.

For example, to value our position on 13 January 2025:

1. [Load two quotes](/v1/docs/how-do-i-upload-a-market-price-or-fx-spot-rate-to-the-quote-store) into a particular quote scope (specified in the URL) with the `effectiveAt` field set to the valuation date:

```json
curl -X POST 'https://<your-domain>.lusid.com/api/api/quotes/MyMBSQuotes'
  -H 'Authorization: Bearer <your-API-access-token>'
  -H 'Content-Type: application/json-patch+json'
  -d '{
    "Quote-0001": {
      "quoteId": {
        "quoteSeriesId": {
          "provider": "Lusid",
          "instrumentIdType": "ClientInternal",
          "instrumentId": "MBS",
          "quoteType": "Price",
          "field": "mid"
        },
        "effectiveAt": "2025-01-13T00:00:00Z"
      },
      "metricValue": {
        "value": 98, "unit": "USD"
      },
      "scaleFactor": 100,
    },
    "Quote-0002": {
      "quoteId": {
        "quoteSeriesId": {
          "provider": "Lusid",
          "instrumentIdType": "Isin",
          "instrumentId": "MyMBSMarketDataIdentifier",
          "quoteType": "PoolFactor",
          "field": "mid"
        },
        "effectiveAt": "2025-01-13T00:00:00Z"
      },
      "metricValue": {
        "value": 95, "unit": "USD"
      },
      "scaleFactor": 100,
    }
  }'
```
2. [Create a recipe](/v1/docs/how-do-i-create-or-generate-a-recipe) to locate this market data and change the default pricing model, for example:

```json
curl -X POST 'https://<your-domain>.lusid.com/api/api/recipes'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "configurationRecipe": {
    "scope": "MyRecipes",
    "code": "MyBasicRecipe",
    "market": {
      "marketRules": [
        {
          "key": "Quote.ClientInternal.*",
          "dataScope": "MyMBSQuotes",
          "supplier": "Lusid",
          "quoteType": "Price",
          "field": "mid"
        },
        {
          "key": "Quote.Isin.*",
          "dataScope": "MyMBSQuotes",
          "supplier": "Lusid",
          "quoteType": "PoolFactor",
          "field": "mid"
        }
      ]
    },
    "pricing": {
      "modelRules": [
        {
          "instrumentType": "ComplexBond",
          "modelName": "BondLookupPricer"
        }
      ]
    }
  }
}'
```
3. [Generate a valuation report](/v1/docs/how-do-i-perform-a-valuation) with appropriate metrics, for example: ![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/image(799).png)

## Assessing risk

LUSID provides an [exposure calculation](/v1/docs/how-does-lusid-calculate-exposure) and supports both analytic and bump and valuation mechanisms for assessing risk.

## Monitoring the lifecycle of the instrument

A MBS instrument ‘expires’ on the maturity date specified in the instrument economic definition.

> **Note**: An instrument in LUSID is still available post-expiry, although the valuation is zero. If you set your holding to zero it no longer appears in reports unless you are deliberately backdating.

### Handling automatic lifecycle events

LUSID is transitioning to a system where it automatically emits [lifecycle events for supported instruments](/v1/docs/understanding-instrument-lifecycle-events-emitted-by-lusid). We provide *default transaction templates* that you can use as-is to automatically generate transactions in portfolios with holdings, and recommendations for *transaction types* that deliver appropriate economic impacts for those generated transactions.

The following events are available for MBS instruments:

| Instrument event type | Event emission criteria | If emitted, default transaction template generates… | Recommendations for transaction types |
| --- | --- | --- | --- |
| `MbsCouponEvent` | This event is automatically emitted by LUSID each time a coupon is due. | A transaction for the coupon amount. | *More information coming soon* |
| `MbsPrincipalEvent` | This event is automatically emitted by LUSID each time a principal repayment is due. | A transaction for the principal amount. |
| `MbsPrincipalWriteOffEvent` |  |  |
| `MbsInterestShortfallEvent` |  |  |
| `MbsInterestDeferralEvent` |  |  |
| `MaturityEvent` | This event is automatically emitted by LUSID on the maturity date of the instrument. | A transaction for all the units in the holding at a cost of zero. |

### Manually loading settlement transactions

If you do not want to turn on automatic instrument lifecycle events you can continue to monitor upcoming cashflows using **Portfolio Management > CashLadder** in the LUSID web app, or by calling the [GetPortfolioCashLadder](https://www.lusid.com/docs/api/lusid/endpoints/transaction-portfolios/GetPortfolioCashLadder.html) API directly.

You can call the [GetUpsertablePortfolioCashFlows](https://www.lusid.com/docs/api/lusid/endpoints/transaction-portfolios/GetUpsertablePortfolioCashFlows.html) API to return imminent cashflows as upsertable DTOs ready to manually load into LUSID as input transactions.
