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, select CdsIndex from the definition dropdown in the UpsertInstruments API reference:
.png?sv=2022-11-02&spr=https&st=2025-11-02T03%3A37%3A57Z&se=2025-11-02T03%3A58%3A57Z&sr=c&sp=r&sig=iZ9%2FWnMD68i%2Fztk3o3JLTqXpWxrua5lA89dskFiCppU%3D)
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
identifiersfield uniquely identifies the instrument using aClientInternalidentifier.In the economic
definitionobject:The
instrumentTypemust beCdsIndex.The nested
identifiersobject should be empty:{}.The
notionalshould be unitised (set to1) and the amount bought or sold specified on the transaction.The
couponRaterepresenting the premium payment should be expressed as a decimal rather than a percentage, so:5% should have a
couponRateof0.051% should have a
couponRateof0.01, and so on.
The
flowConventionsfield must reference aCdsFlowConventionsobject storing all the information necessary to determine premium payment periods and dates:The
paymentFrequencyfield can be any tenor, in this case6Mto signify twice yearly. Supported day count conventions.The
rollConventionfield can specify a fixed day (for exampleIMMorEndOfMonth) or alternatively a number representing a day of the month. We also recommend setting abusinessDayConventionto 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
settleDaysandresetDaysfields are optional. Thescopeandcodefields can be ignored unless you are loading a CDS flow convention from a library.
The
basketfield 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
CdsLookupPricerpricing model does not yet value 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": -0.02,
"type": "Price"
},
"totalConsideration": {
"currency": "EUR",
"amount": -2000
},
"properties": {
"Transaction/default/BondInterest": {
"key": "Transaction/default/BondInterest",
"value": {
"metricValue": {
"value": -1270.00,
"unit": "EUR"
}
}
}
}
}
}'Note the following:
The
instrumentIdentifiersfield uses theClientInternalidentifier to resolve the transaction to the correct CDX instrument (but it could use the LUID).The
typefield invokes a customBuyProtectiontransaction type to confer a particular economic impact on the transaction (see below).The
unitsfield specifies the purchase amount, in this case100000.The
transactionPriceobject records the market price as a rate, calculated from a par-like Markit price as(100 - price) / 100. For example:For an above-par price of 102, the rate would be
(100 - 102) / 100 = -0.02. Note the impact of a transaction for an above-par price is to both receive cash and accrued interest (that is, a rebate on the premium for purchasing part-way through a period).For a below-par price of 98, the rate would be
(100 - 98) / 100 = 0.02. Note the impact of a transaction for a below-par price is to pay cash but receive accrued interest.
The
totalConsiderationobject:Sets the settlement currency to
EUR.Records a total consideration for the transaction of
100000 * -0.02 = -2000. LUSID uses this amount in the calculation of holding cost.
Currently, we must calculate the accrued interest manually and record a negative amount using the
Transaction/default/BondInterestsystem property, in this case-1270. In future, LUSID may automate this calculation.
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": "Basic",
"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 as a flow of value out of the security",
"movementTypes": "Carry",
"side": "Side1",
"direction": 1
}
]
}'Note the following:
The
StockMovementuses aProtectioncustom side (see below) to establish a holding in the CDX instrument with a number of units at a particular cost.The
CashCommitmentmovement uses the built-inSide2to decrease a currency holding by the total consideration.The
Carrymovement uses the built-inSide1to record a flow of value out of the CDX instrument in an A2B report.
We can call the SetSideDefinition API to create a Protection custom side as follows:
curl -X PUT 'https://<your-domain>.lusid.com/api/api/transactionconfiguration/sides/Protection?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": "BaseOnSeparateBondInterest"
}'This is the same as the built-in Side1 except the amount field is set to BaseOnSeparateBondInterest instead of Txn:TradeAmount.
Note this means that LUSID calculates holding cost as total consideration minus Transaction/default/BondInterest. If this latter amount is signed negative then LUSID decreases the cost of the CDX instrument, to reflect the recipt of accrued interest.
Confirming positions on the settlement date
We can mavigate to Portfolio Management > Holdings in the LUSID web app to call the GetHoldings API on the settlement date and, since we bought for an above-par price of 102, see that we have:
100,000 units of the CDX instrument holding with a negative cost calculated as total consideration minus accrued interest:
-2000 - (-1270) = -730A EUR currency holding with a positive amount reflecting cash received (because we bought above par):
.png?sv=2022-11-02&spr=https&st=2025-11-02T03%3A37%3A57Z&se=2025-11-02T03%3A58%3A57Z&sr=c&sp=r&sig=iZ9%2FWnMD68i%2Fztk3o3JLTqXpWxrua5lA89dskFiCppU%3D)
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:
2000 - (-1270) = 3270A EUR currency holding with a negative amount reflecting cash paid (because we bought below par):
.png?sv=2022-11-02&spr=https&st=2025-11-02T03%3A37%3A57Z&se=2025-11-02T03%3A58%3A57Z&sr=c&sp=r&sig=iZ9%2FWnMD68i%2Fztk3o3JLTqXpWxrua5lA89dskFiCppU%3D)
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, for example:
.png?sv=2022-11-02&spr=https&st=2025-11-02T03%3A37%3A57Z&se=2025-11-02T03%3A58%3A57Z&sr=c&sp=r&sig=iZ9%2FWnMD68i%2Fztk3o3JLTqXpWxrua5lA89dskFiCppU%3D)
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 |
|---|---|
| Recommended. This pricing model extends |
| This is currently the default. We recommend changing it to |
For example, to value our holding using CdsLookupPricer on 1 October 2024:
Load a Markit price into a particular quote scope (specified in the URL) with
effectiveAtas the valuation date (note there is no need to specify a scale factor):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": "2024-10-01T00:00:00Z" }, "metricValue": { "value": 104, "unit": "EUR" } } }'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" } ] } } }'Generate a valuation report with appropriate metrics, for example:
.png?sv=2022-11-02&spr=https&st=2025-11-02T03%3A37%3A57Z&se=2025-11-02T03%3A58%3A57Z&sr=c&sp=r&sig=iZ9%2FWnMD68i%2Fztk3o3JLTqXpWxrua5lA89dskFiCppU%3D)
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 ‘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. 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 CdsIndex:
Instrument event type | Event emission criteria | If emitted, default transaction template generates… | Recommendations for transaction types |
|---|---|---|---|
| This event is automatically emitted by LUSID each time a premium is due. | A transaction for the premium payment amount. | |
| This event is not automatically emitted by LUSID. It can be triggered by manually loading a | A transaction for the protection payout amount. | |
| 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 API directly.
You can call the GetUpsertablePortfolioCashFlows API to  return imminent cashflows as upsertable DTOs ready to manually load into LUSID as input transactions.