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 credit default swap indexes (CDX) in LUSID

Prev Next

You can model an exchange-traded credit default swap index (CDX) contract as an instrument of type CdsIndex in LUSID. See all supported instruments.

Note: Most of the information in this article also applies to a single name CDS contract, except the LUSID instrument type is CreditDefaultSwap.

Mastering an instrument

There are numerous tools you can use to master a CdsIndex 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 CdsIndex. For more information on these fields, examine the CdsIndex schema or select CdsIndex from the definition dropdown in the UpsertInstruments API reference:

In this tutorial, we’ll master a Markit-iTraxx-Crossover contract by calling the UpsertInstruments API as follows:

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 '{
  "request_id_1": {
    "name": "Markit iTraxx Crossover Series 41 5Y",
    "identifiers": {
      "ClientInternal": {"value": "MarkitiTraxxCrossoverSeries415Y"}
    },
    "definition": {
      "instrumentType": "CdsIndex",
      "identifiers": {},
      "startDate": "2024-03-20T00:00:00.0000000+00:00",
      "maturityDate": "2029-06-20T00:00:00.0000000+00:00",
      "notional": 1,
      "couponRate": 0.05,
      "flowConventions": {
        "currency": "EUR",
        "paymentFrequency": "6M",
        "dayCountConvention": "Actual360",
        "rollConvention": "20",
        "businessDayConvention": "F",
        "paymentCalendars": ["EUR"]
      }
    }
  }
}'

Note the following:

  • We’ve chosen to master this instrument in a custom instrument scope (specified in the URL).

  • The identifiers field uniquely identifies the instrument using a ClientInternal identifier.

  • In the economic definition object:

    • The instrumentType must be CdsIndex.

    • The nested identifiers object should be empty: {}.

    • The notional should be unitised (set to 1) and the amount bought or sold specified on the transaction.

    • The couponRate representing the premium payment should be expressed as a decimal rather than a percentage, so:

      • 5% should have a couponRate of 0.05

      • 1% should have a couponRate of 0.01, and so on.

    • The flowConventions field must reference a CdsFlowConventions object storing all the information necessary to determine premium payment periods and dates:

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

      • The rollConvention field can specify a fixed day (for example IMM or EndOfMonth) or alternatively a number representing a day of the 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. Note good business days in LUSID are determined by holiday calendars.

      • The settleDays and resetDays fields are optional. The scope and code fields can be ignored unless you are loading a CDS flow convention from a library.

    • The basket field is now optional and there is no need to identity the underlying CDS trades in the index.

Note: LUSID implicitly creates protection and payment legs for a CDX instrument but note the recommended CdsLookupPricer pricing model does not yet value the legs separately.

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_00003EDB",
      "name": "Markit iTraxx Crossover Series 41 5Y",
      "identifiers": {
        "LusidInstrumentId": "LUID_00003EDB",
        "ClientInternal": "MarkitiTraxxCrossoverSeries415Y"
      },
      "properties": [],
      "instrumentDefinition": {
        "startDate": "2024-03-20T00:00:00.0000000+00:00",
        "maturityDate": "2029-06-20T00:00:00.0000000+00:00",
        "flowConventions": {
          "rollFrequency": "6M",
          "currency": "EUR",
          "paymentFrequency": "6M",
          "dayCountConvention": "Actual360",
          "rollConvention": "20",
          "paymentCalendars": ["EUR"],
          "resetCalendars": [],
          "settleDays": 0,
          "resetDays": 0,
          "businessDayConvention": "F"
        },
        "couponRate": 0.05,
        "identifiers": {},
        "basket": {
          "basketName": {
            "index": "unknown",
            "name": "unknown",
            "region": "unknown",
            "seriesId": 10000000
          },
          "basketType": "Credits",
          "weightedInstruments": {
            "instruments": []
          },
          "instrumentType": "Basket"
        },
        "notional": 1,
        "additionalPayments": [],
        "instrumentType": "CdsIndex"
      },
      "state": "Active",
      "assetClass": "Credit",
      "domCcy": "EUR",
      "relationships": []
    }
  }
  ...
}

Booking a transaction to establish a position

Once an instrument is mastered, we can book a transaction to record the acquisition of a quantity in a suitable portfolio, for example by calling the BatchUpsertTransactions API as follows:

curl -X POST 'https://<your-domain>.lusid.com/api/api/transactionportfolios/FixedIncome/EMEA/transactions/$batchUpsert?successMode=Partial&preserveProperties=true'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "transactionRequest-1": {
    "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": 102,
      "type": "Price"
    },
    "totalConsideration": {
      "currency": "EUR",
      "amount": 0
    }
  }
}'

Note the following:

  • The instrumentIdentifiers field uses the ClientInternal identifier to resolve the transaction to the correct CDX instrument (but it could use the LUID).

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

  • The units field specifies the purchase amount, in this case 100000.

  • The transactionPrice object records the market price as a par-like Markit price of 102. LUSID converts this to a rate using (100 - price) / 100, so (100 - 102) / 100 = -0.02. Note you can enter the rate explicitly if you want but the transactionPrice.type should still be Price.  Note also:

    • The impact of a transaction for an above-par price such as 102 is to both receive cash and accrued interest (that is, a rebate on the premium for purchasing part-way through a period).

    • The impact of a transaction for a below par price such as 98 (which as a rate is (100 - 98) / 100 = 0.02) is to pay cash but receive accrued interest.

  • The totalConsideration object:

    • Sets the settlement currency to EUR.

    • Sets the amount to 0 to trigger LUSID’s calculation of total consideration using the BuyProtection transaction type (see below).

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

We can call the SetTransactionType API to create a BuyProtection transaction type as follows:

curl -X PUT 'https://<your-domain>.lusid.com/api/api/transactionconfiguration/types/default/BuyProtection?scope=default'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "aliases": [
    {
      "type": "BuyProtection",
      "description": "Transaction type for CDX purchases",
      "transactionClass": "CreditDefaultSwap",
      "transactionRoles": "Longer",
      "isDefault": false
    }
  ],
  "movements": [
    {
      "name": "Increase units of security",
      "movementTypes": "StockMovement",
      "side": "Protection",
      "direction": 1
    },
    {
      "name": "Decrease cash balance",
      "movementTypes": "CashCommitment",
      "side": "Side2",
      "direction": -1
    },
    {
      "name": "Report bought/sold interest",
      "movementTypes": "Carry",
      "side": "Accrued",
      "direction": -1
    }
  ],
  "calculations": [
    {
      "type": "Txn:BondInterest"
    },
    {
      "type": "Txn:GrossConsideration"
    },
    {
      "type": "DeriveTotalConsideration",
      "formula": "Txn:GrossConsideration"
    }
  ]
}'

Note the following:

  • The StockMovement uses a Protection custom side (see below) to establish a CdsIndex holding with a particular number of units and cost.

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

  • The Carry movement uses an Accrued custom side (see below) to record a flow of value in an A2B report.

  • The transaction type calculations trigger LUSID to calculate accrued interest and gross and total consideration.

Protection custom side

Accrued custom side

{
  "security": "Txn:LusidInstrumentId",
  "currency": "Txn:TradeCurrency",
  "rate": "Txn:TradeToPortfolioRate",
  "units": "Txn:Units",
  "amount": "BaseOnSeparateBondInterest"
}
{
  "security": "Txn:LusidInstrumentId",
  "currency": "Txn:SettlementCurrency",
  "rate": "SettledToPortfolioRate",
  "units": "0",
  "amount": "Txn:BondInterest"
}

This is the same as the built-in Side1 except the amount field is set to BaseOnSeparateBondInterest instead of Txn:TradeAmount.

This is similar to the built-in Side2 except the units field is set to 0 and amount carries just the accrued interest.

Confirming positions on the settlement date

We can navigate to Portfolio Management > Holdings in the LUSID web app to call the GetHoldings API on the settlement date and, since we bought at an above-par price of 102, see that we have:

  • 100,000 units of the CDX instrument holding with a negative cost of -2000

  • A EUR currency holding with a positive amount reflecting both cash (above par) and accrued interest (premium rebate) received: 2000 + 1291.67 = 3291.67

If instead we had bought at a below-par price of 98, we would have:

  • 100,000 units of the CDX instrument holding with a positive cost

  • A EUR currency holding with a negative amount reflecting the net of cash paid (below par) and accrued interest received (premium rebate): -2000 + 1291.67 = -708.33

Auditing LUSID’s calculations of transaction amounts

We can navigate to Portfolio Management > Transactions in Output mode to call the BuildTransactions API with a suitable window to examine the output transaction that generated the above-par holdings (click to enlarge):

Valuing your position

To value your position, work through our valuation checklist.

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

Pricing model

Notes

CdsLookupPricer

Recommended. This pricing model extends SimpleStatic to consume either a price or a rate, and also projects cashflows. You can load a quotes as either:

  • A par-like Markit price of (for example) 102 or 98 using a quoteType of Price. LUSID calculates clean PV as (units * notional * ((100 - price) / 100)) / scale factor.

  • As a rate of (for example) -0.02 or 0.02 using a quoteType of Rate. LUSID calculates clean PV as (units * notional * rate) / scale factor.

In either case, LUSID calculates PV as clean PV + accrued interest.

SimpleStatic

This is currently the default. We recommend changing it to CdsLookupPricer in your recipe. See how to do this.

For example, to value our holding using CdsLookupPricer on 10 July 2026 using a par-like Markit price:

  1. Load a quote into a particular scope (specified in the URL) with effectiveAt as the valuation date and a scaleFactor of 1:

    curl -X POST 'https://mydomain.lusid.com/api/api/quotes/MyCdxQuotes'
      -H 'Authorization: Bearer myAPIAccessToken'
      -H 'Content-Type: application/json-patch+json'
      -d '{
        "Quote-0001": {
          "quoteId": {
            "quoteSeriesId": {
              "provider": "Lusid",
              "instrumentIdType": "ClientInternal",
              "instrumentId": "MarkitiTraxxCrossoverSeries415Y",
              "quoteType": "Price",
              "field": "mid"
            },
            "effectiveAt": "2026-07-10T00:00:00Z"
          },
          "metricValue": {"value": 102, "unit": "EUR"},
          "scaleFactor": 1
        }
      }'
  2. Create a recipe to locate this market data and change the pricing model, for example:

    curl -X POST 'https://mydomain.lusid.com/api/api/recipes'
      -H 'Content-Type: application/json-patch+json'
      -H 'Authorization: Bearer myAPIAccessToken'
      -d '{
      "configurationRecipe": {
        "scope": "MyRecipes",
        "code": "MyBasicRecipe",
        "market": {
          "marketRules": [
            {
              "key": "Quote.ClientInternal.*",
              "dataScope": "MyCdxQuotes",
              "supplier": "Lusid",
              "quoteType": "Price",
              "field": "mid"
            }
          ]
        },
        "pricing": {
          "modelRules": [
            {
              "instrumentType": "CdsIndex",
              "modelName": "CdsLookupPricer"
            }
          ]
        }
      }
    }'
  3. Generate a valuation report with appropriate metrics, for example:

Assessing risk

For more on how LUSID calculates exposure, see this article.

LUSID supports both analytic and bump and valuation mechanisms for assessing risk; contact Technical Support if you need more information.

Monitoring the lifecycle of the instrument

A CdsIndex instrument is tightly integrated into LUSID’s instrument event framework. To enable this for your domain, you must:

  1. Register a recipe with every portfolio holding a CdsIndex.

  2. Create transaction types to determine the economic impact of the transactions automatically generated by CdsIndex events.

Recommended reading: Handling instrument events for credit default swaps

Instrument event type

Event emission criteria

If emitted, default transaction template generates…

CreditPremiumCashFlowEvent

This event is automatically emitted by LUSID each time a premium is due.

A transaction for the premium payment amount.

ProtectionPayoutCashFlowEvent

This event is not automatically emitted by LUSID. It can be triggered by manually loading a CdxCreditEvent into a suitable corporate action source.

A transaction for the protection payout amount.

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 zero cost of zero.