Handling premium, credit and maturity events for CDX instruments

Prev Next

You can model a credit default swap index (CDX) contract as an instrument of type CdsIndex in LUSID. See how to do this.

LUSID emits the following instrument lifecycle events for a CdsIndex, which you can handle to reduce workload and improve efficiency:

  • CreditPremiumCashFlowEvent. This event is automatically emitted by LUSID each time a premium payment is due. More information.

  • ProtectionPayoutCashFlowEvent. This event is not automatically emitted by LUSID, but can be manually triggered if you are informed that a credit event has occurred. More information.

  • MaturityEvent. This event is automatically emitted by LUSID on the maturity date in the instrument definition. More information.

Note: The information in this article also applies to a single name CDS contract mastered as an instrument of type CreditDefaultSwap.

Imagine we have a Markit-iTraxx-Crossover contract modelled as a CdsIndex with the following economic definition:

"definition": {
  "instrumentType": "CdsIndex",
  "startDate": "2024-03-20T00:00:00.0000000+00:00",
  "maturityDate": "2029-06-20T00:00:00.0000000+00:00",
  "notional": 1,
  "couponRate": 0.05,
  "identifiers": {},
  "flowConventions": {
    "currency": "EUR",
    "paymentFrequency": "6M",
    "dayCountConvention": "Actual360",
    "rollConvention": "20",
    "businessDayConvention": "F",
    "paymentCalendars": ["EUR"]
  }
}
JSON

For much more information on modelling instruments of type CdsIndex, see this article. Note with regard to instrument events:

  • The maturityDate of 20 June 2029 and paymentFrequency of 6M combine to mean premium payments are due on 20 June and 20 December each year.

  • The rollConvention is 20, which means premium payments are taken on the 20th day of the month.

  • The businessDayConvention is F, so the premium payment is taken on the following day if the 20th is not a good business day.

  • The paymentCalendars array specifies that good business days are determined by the EUR Copp Clark holiday calendar.

We can now establish a position by booking a transaction in this instrument in a suitable portfolio, in this case trading on 20 September 2024 and settling 5 days later:

{
  "transactionId": "cdx_purchase_001",
  "type": "BuyProtection",
  "instrumentIdentifiers": {"Instrument/default/ClientInternal": "MarkitiTraxxCrossoverSeries415Y"},
  "transactionDate": "2024-09-20T00:00:00.0000000+00:00",
  "settlementDate": "2024-09-25T00:00:00.0000000+00:00",
  "units": 100000,
  "transactionPrice": {
    "price": -0.02,
    "type": "Price"
  },
  "totalConsideration": {
    "currency": "EUR",
    "amount": -2000
  },
  "properties": {
    "Transaction/default/BondInterest": {
      "key": "Transaction/default/BondInterest",
      "value": {
        "metricValue": {
          "value": -1270.00,
          "unit": "EUR"
        }
      }
    }
  }
}
JSON

For much more information on booking transactions in CdsIndex instruments, including details of a BuyProtection transaction type, how to record accrued interest using the Transaction/default/BondInterest system property, specifying prices and total consideration, and how LUSID calculates holding cost, see this article.

LUSID automatically emits a CreditPremiumCashFlowEvent each time a premium payment is due. You should handle this event to reduce an appropriate cash balance in a portfolio by the premium amount.

LUSID provides a default transaction template for every type of event. In this tutorial we’ll use the default template for CreditPremiumCashFlowEvent, but note you can create a custom transaction template to configure the process if you wish.

We can call the GetTransactionTemplate API to examine this default template, which at the time of writing is as follows:

{
  "instrumentType": "CdsIndex",
  "instrumentEventType": "CreditPremiumCashFlowEvent",
  "description": "LUSID default template for automatically generated transactions in respect of CreditDefaultSwapIndex Cashflow instrument events.",
  "scope": "default",
  "componentTransactions": [
    {
      "displayName": "Credit Premium",
      "transactionFieldMap": {
        "transactionId": "{{instrumentEventId}}-{{holdingId}}",
        "type": "CreditPremiumCashFlow",
        "source": "default",
        "instrument": "{{instrument}}",
        "transactionDate": "{{CreditPremiumCashFlowEvent.exDate}}",
        "settlementDate": "{{CreditPremiumCashFlowEvent.paymentDate}}",
        "units": "{{eligibleBalance}}",
        "transactionPrice": {
          "price": "{{CreditPremiumCashFlowEvent.cashFlowPerUnit}}",
          "type": "CashFlowPerUnit"
        },
        "transactionCurrency": "{{CreditPremiumCashFlowEvent.currency}}",
        "exchangeRate": "1",
        "totalConsideration": {
          "currency": "{{CreditPremiumCashFlowEvent.currency}}",
          "amount": "{{CreditPremiumCashFlowEvent.cashFlowAmount}}"
        }
      },
      "transactionPropertyMap": []
    }
  ],
  ...
}
JSON

Note the following:

  • This template handles instrument events of type CreditPremiumCashFlowEvent emitted by instruments of type CdsIndex.

  • It is domiciled in the default (that is, system) transaction template scope.

  • It contains instructions for automatically generating a single output transaction in every portfolio with a holding in the CDX instrument.

  • The generated transaction belongs to a CreditPremiumCashFlow transaction type grouped in the default transaction type source.

Note: This template does not add the Transaction/default/TradeToPortfolioRate system property to the generated transaction. If the portfolio base currency is different to the transaction currency we recommend specifying the Txn:TradeToPortfolioRate calculation in the transaction type to look up a spot rate dynamically in the LUSID Quote Store. See how to do this.

The default transaction template mandates a CreditPremiumCashFlow transaction type grouped in the default transaction type source. We must create this transaction type if it does not exist.

Note: Transaction types are grouped in sources and reside in scopes. For more information on the difference, see this article.

We can call the SetTransactionType API as follows:

curl -X PUT 'https://<your-domain>.lusid.com/api/api/transactionconfiguration/types/default/CreditPremiumCashFlow?scope=default'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "aliases": [
    {
      "type": "CreditPremiumCashFlow",
      "description": "Transaction type for credit premium cash flow event",
      "transactionClass": "Basic",
      "transactionRoles": "AllRoles",
      "isDefault": false
    }
  ],
  "movements": [
    {
      "name": "Premium payments",
      "movementTypes": "CashCommitment",
      "side": "Side2",
      "direction": 1,
      "mappings": [
        {
          "propertyKey": "Transaction/SHKs/CdxPremiumPayments",
          "setTo": "Premium payments"
        }
      ],
    },
    {
      "name": "Record as a flow of value out of the security",
      "movementTypes": "Carry",
      "side": "Side1",
      "direction": 1,
    }
  ]
}'
JSON

Note the following:

  • The transaction type alias is CreditPremiumCashFlow, to comply with the default transaction template.

  • The transaction type source is default (specified in the URL), to comply with the default transaction template.

  • You can design a transaction type to have any economic impact you like. This recommendation has:

    • A CashCommitment movement that increases a currency holding by the premium amount. Note the direction is positive but premium payment amounts are signed negative. This is mapped to a sub-holding key (SHK) to report this currency holding separately.

    • A Carry movement reporting a flow of value out of the security in an A2B report.

You can trigger LUSID to emit a ProtectionPayoutCashFlowEvent if you are notified that a credit event has occured (note this event is not emitted automatically). You can handle this event to increase an appropriate cash balance in a portfolio by the protection payout amount.

To do this:

  1. If a portfolio does not already have a corporate action source (CAS), create one and subscribe the portfolio to it. See how to do this.

  2. Create a transaction type to determine the economic impact of protection payout transactions automatically generated by ProtectionPayoutCashFlowEvent. More information.

  3. Load a CdxCreditEvent into the CAS to trigger ProtectionPayoutCashFlowEvent on a particular date. More information.

We can call the GetTransactionTemplate API to examine the default transaction template for ProtectionPayoutCashFlowEvent, which at the time of writing is as follows:

{
  "instrumentType": "CdsIndex",
  "instrumentEventType": "ProtectionPayoutCashFlowEvent",
  "description": "LUSID default template for automatically generated transactions in respect of CDX Protection Payout Cashflow instrument events.",
  "scope": "default",
  "componentTransactions": [
    {
      "displayName": "Protection Payout",
      "transactionFieldMap": {
        "transactionId": "{{instrumentEventId}}-{{holdingId}}",
        "type": "ProtectionPayoutCashFlow",
        "source": "default",
        "instrument": "{{instrument}}",
        "transactionDate": "{{ProtectionPayoutCashFlowEvent.exDate}}",
        "settlementDate": "{{ProtectionPayoutCashFlowEvent.paymentDate}}",
        "units": "{{eligibleBalance}}",
        "transactionPrice": {
          "price": "{{ProtectionPayoutCashFlowEvent.cashFlowPerUnit}}",
          "type": "CashFlowPerUnit"
        },
        "transactionCurrency": "{{ProtectionPayoutCashFlowEvent.currency}}",
        "exchangeRate": "1",
        "totalConsideration": {
          "currency": "{{ProtectionPayoutCashFlowEvent.currency}}",
          "amount": "{{ProtectionPayoutCashFlowEvent.cashFlowAmount}}"
        }
      },
      "transactionPropertyMap": []
    }
  ],
  ...
}
JSON

Note the following:

  • This template handles instrument events of type ProtectionPayoutCashFlowEvent emitted by instruments of type CdsIndex.

  • It is domiciled in the default (that is, system) transaction template scope.

  • It contains instructions for automatically generating a single output transaction in every portfolio with a holding in the CDX instrument.

  • The generated transaction belongs to a ProtectionPayoutCashFlow transaction type grouped in the default transaction type source.

The default transaction template mandates a ProtectionPayoutCashFlow transaction type grouped in the default transaction type source. We must create this transaction type if it does not exist, for example by calling the SetTransactionType API as follows:

curl -X PUT 'https://<your-domain>.lusid.com/api/api/transactionconfiguration/types/default/ProtectionPayoutCashFlow?scope=default'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "aliases": [
    {
      "type": "ProtectionPayoutCashFlow",
      "description": "Transaction type for protection payout cash flow event",
      "transactionClass": "Basic",
      "transactionRoles": "AllRoles",
      "isDefault": false
    }
  ],
  "movements": [
    {
      "name": "Protection payouts",
      "movementTypes": "CashReceivable",
      "side": "Side2",
      "direction": 1,
      "mappings": [
        {
          "propertyKey": "Transaction/SHKs/CdxProtectionPayouts",
          "setTo": "Protection payouts"
        }
      ],
    }
  ]
}'
JSON

Note the following:

  • The transaction type alias is ProtectionPayoutCashFlow, to comply with the default transaction template.

  • The transaction type source is default (specified in the URL), to comply with the default transaction template.

  • You can design a transaction type to have any economic impact you like. This recommendation has a single CashReceivable movement that increases a currency holding by the protection payout amount. This is mapped to a SHK to report this currency holding separately.

We must manually load a CdxCreditEvent into a CAS in order to trigger LUSID to emit a ProtectionPayoutCashFlowEvent on a particular date.

We can call the UpsertInstrumentEvents API and supply the scope and code of the CAS in the URL as follows:

curl -X POST 'https://<your-domain>.lusid.com/api/api/corporateactionsources/my-CAS-scope/my-CAS-code/instrumentevents'
 -H 'Content-Type: application/json-patch+json'
 -H 'Authorization: Bearer <your-API-access-token>'
 -d '[
  {
    "instrumentEventId": "CdxCreditEvent2025-02-15",
    "instrumentIdentifiers": {"Instrument/default/ClientInternal": "MarkitiTraxxCrossoverSeries415Y"},
    "description": "Credit event 15 Feb 2025",
    "instrumentEvent": {
      "instrumentEventType": "CdxCreditEvent",
      "effectiveDate": "2025-02-15T00:00:00.0000000+00:00",
      "auctionDate": "2025-03-20T00:00:00.0000000+00:00",
      "paymentDate": "2025-03-25T00:00:00.0000000+00:00",
      "recoveryRate": 0.75,
      "constituentWeight": 0.01333,
      "constituentReference": "Intram"
    }
  }
]'
JSON

Note the following:

  • The instrumentEventId is a free string field that must uniquely identify this corporate action in the corporate action source.

  • The instrumentIdentifiers field uses a ClientInternal identifier to resolve to the correct CDX instrument in the LUSID Security Master, but you could specify the LUID.

  • If you do not yet know the auctionDate it defaults to seven weeks after effectiveDate.

  • If you do not yet know the paymentDate then the transaction automatically generated by ProtectionPayoutCashFlowEvent trades and settles the day after auctionDate.

  • If you do not yet know the recoveryRate it defaults to 1.

  • The constituentWeight must be a number between 0 and 1.

  • The constituentReference is a free string field enabling you to record the defaulting constituent.

Note you can call the UpsertInstrumentEvents API as many times as you like to update the event as information about the auction date, recovery rate and constituent weight becomes available.

LUSID automatically emits a MaturityEvent on the date specified in the instrument definition. You should handle this event to set your position to zero units, so it drops out of holding and valuation reports.

We can call the GetTransactionTemplate API to examine the default transaction template for MaturityEvent, which at the time of writing is as follows:

{
  "instrumentType": "CdsIndex",
  "instrumentEventType": "MaturityEvent",
  "description": "LUSID default template for automatically generated transactions in respect of instrument maturity events.",
  "scope": "default",
  "componentTransactions": [
    {
      "displayName": "Maturity",
      "transactionFieldMap": {
        "transactionId": "{{instrumentEventId}}-{{holdingId}}",
        "type": "Maturity",
        "source": "default",
        "instrument": "{{instrument}}",
        "transactionDate": "{{MaturityEvent.maturityDate}}",
        "settlementDate": "{{MaturityEvent.maturityDate}}",
        "units": "{{eligibleBalance}}",
        "transactionPrice": {
          "price": "0",
          "type": "Price"
        },
        "transactionCurrency": "{{holdingCurrency}}",
        "exchangeRate": "0",
        "totalConsideration": {
          "currency": "{{holdingCurrency}}",
          "amount": "0"
        }
      },
      "transactionPropertyMap": []
    }
  ],
  ...
}
JSON

Note the following:

  • This template handles instrument events of type MaturityEvent emitted by instruments of type CdsIndex.

  • It is domiciled in the default (that is, system) transaction template scope.

  • It contains instructions for automatically generating a single output transaction in every portfolio with a holding in the CDX instrument.

  • The generated transaction belongs to a Maturity transaction type grouped in the default transaction type source.

The default transaction template mandates a Maturity transaction type grouped in the default transaction type source. We must create this transaction type if it does not exist, for example by calling the SetTransactionType API as follows:

curl -X PUT 'https://<your-domain>.lusid.com/api/api/transactionconfiguration/types/default/Maturity?scope=default'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "aliases": [
    {
      "type": "Maturity",
      "description": "Transaction type for instrument maturity event",
      "transactionClass": "Basic",
      "transactionRoles": "AllRoles",
      "isDefault": false
    }
  ],
  "movements": [
    "name": "Set units to zero",
    "movementTypes": "StockMovement",
    "side": "Side1",
    "direction": -1
  ]
}'
JSON

Note the following:

  • The transaction type alias is Maturity, to comply with the default transaction template.

  • The transaction type source is default (specified in the URL), to comply with the default transaction template.

  • You can design a transaction type to have any economic impact you like. This recommendation reduces the number of units to zero.

We can use Portfolio Management > Holdings in the LUSID web app to call the GetHoldings API on the settlement date and see that we have:

  • 100,000 units of the CDX instrument holding with a negative cost of -730 (see this article for the calculation)

  • A EUR currency holding with a positive amount reflecting cash received (because we purchased above par):

If we move the Effective date to the first premium payment date we see that CreditPremiumCashFlowEvent has posted a negative amount to a separate EUR currency holding:

If we move the Effective date to the payment date of the credit event we can see that ProtectionPayoutCashFlowEvent has posted a positive amount to a separate EUR currency holding:

If we move the Effective date to the maturity date of the instrument we can see that MaturityEvent has removed the CDX instrument position (set units to zero):

We can use Portfolio Management > Transactions in Output mode to call the BuildTransactions API with a suitable window to examine the record of output transactions generated over the lifetime of the instrument: