You can model an exchange-traded options contract as an instrument of type ExchangeTradedOption
. See all supported instruments.
Mastering an instrument
There are numerous tools you can use to master an ExchangeTradedOption
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 ExchangeTradedOption
. For more information on these fields, select ExchangeTradedOption from the definition dropdown in the API Reference:
Specifying an underlying instrument
If the underlying of an ExchangeTradedOption
is:
An equity or an exchange-traded future, the recommended approach is to master that as a separate instrument in LUSID and provide a reference to a
MasteredInstrument
. If you do this, instrument events are available. See below for more information.A bond, interest rate, index, commodity or any other type of asset, the only option is to provide an inline definition as part of the
ExchangeTradedOption
. Instrument events are not available.
Mastering an ExchangeTradedOption instrument
The following call to the UpsertInstruments API masters an option on AAPL that are already mastered as an instrument of type Equity
in LUSID:
curl -X POST 'https://mydomain.lusid.com/api/api/instruments?scope=MyCustomInstrScope'
-H 'Content-Type: application/json-patch+json'
-H 'Authorization: Bearer <my-API-access-token>'
-d '{"upsert-request-1": {
"name": "OptionOnAPPL",
"identifiers": {"ClientInternal": {"value": "OptionOnAPPL"}},
"definition": {
"instrumentType": "ExchangeTradedOption",
"startDate": "2024-09-21T00:00:00.0000000+00:00",
"contractDetails": {
"domCcy": "USD",
"strike": 250,
"contractSize": 100,
"country": "US",
"deliveryType": "Physical",
"description": "Option on APPL equity",
"exchangeCode": "CME",
"exerciseDate": "2024-12-21T00:00:00.0000000+00:00",
"exerciseType": "American",
"optionCode": "ZQF4C",
"optionType": "Call",
"underlying": {
"instrumentType": "MasteredInstrument",
"identifiers": {"Instrument/default/Figi": "US0378331005"}
},
"underlyingCode": "MyIDForAPPLQuotes"
},
"contracts": 1,
"refSpotPrice": 0
}
}
}'
Note the following:
The
ExchangeTradedOption
instrument is mastered in a custom instrument scope (specified in the URL).The
identifiers
object is set to reference aClientInternal
unique identifier.startDate
is a mandatory field but note is not subsequently used by LUSID.deliveryType
can bePhysical
(if you intend to take delivery of the underlying) orCash
.exerciseType
can beAmerican
,European
orBermudan
.optionType
can bePut
orCall
.The
underlying
object must either:Have the
underlying.instrumentType
field set toMasteredInstrument
if the underlying is already mastered as anEquity
orFuture
in LUSID, and theunderlying.identifiers
object set to reference a unique identifier for that instrument, in this case a FIGI. Note the underlying must reside in the same instrument scope as theExchangeTradedOption
, or else in thedefault
instrument scope.Be populated with a full inline economic definition if the underlying is any other type of instrument.
underlyingCode
can be set to any intuitive string that represents a market data identifier for the underlying instrument loaded into the LUSID Quote Store.contracts
should be set to1
and the amount bought or sold specified on the transaction.
Providing the request is successful, the response:
Confirms the globally-unique LUID of the
ExchangeTradedOption
instrument (in this caseLUID_00003E8D
) and also that of theMasteredInstrument
if LUSID is able to resolve it correctly (in this caseLUID_00003E8E
). If not, the unknown instrument is returned.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": {
"upsert-request-1": {
"scope": "MyCustomInstrScope",
"lusidInstrumentId": "LUID_00003E8D",
"name": "OptionOnAPPL",
"identifiers": {
"ClientInternal": "OptionOnAPPL",
"LusidInstrumentId": "LUID_00003E8D"
},
"properties": [],
"instrumentDefinition": {
"startDate": "2024-09-21T00:00:00.0000000+00:00",
"contractDetails": {
"domCcy": "USD",
"strike": 250,
"contractSize": 100,
"country": "US",
"deliveryType": "Physical",
"description": "Option on APPL",
"exchangeCode": "CME",
"exerciseDate": "2024-12-21T00:00:00.0000000+00:00",
"exerciseType": "American",
"optionCode": "ZQF4C",
"optionType": "Call",
"underlying": {
"identifiers": {
"Instrument/default/Figi": "US0378331005"
},
"masteredDomCcy": "USD",
"masteredInstrumentType": "Equity",
"masteredLusidInstrumentId": "LUID_00003E8E",
"masteredName": "Apple",
"masteredScope": "MyCustomInstrScope",
"masteredAssetClass": "Equities",
"instrumentType": "MasteredInstrument"
},
"underlyingCode": "MyIDForAPPLQuotes",
"deliveryDays": 0,
"businessDayConvention": "F",
"settlementCalendars": []
},
"contracts": 1,
"refSpotPrice": 0,
"tradingConventions": {
"priceScaleFactor": 1,
"minimumOrderSize": 0,
"minimumOrderIncrement": 0
},
"instrumentType": "ExchangeTradedOption"
},
"state": "Active",
"assetClass": "Unknown",
"domCcy": "USD",
"relationships": []
}
},
...
}
Booking a transaction to establish a position
Once an instrument is mastered, you can book a transaction in an ExchangeTradedOption
instrument to record the acquisition of a quantity in a particular transaction portfolio, for example:
curl -X POST 'https://mydomain.lusid.com/api/api/transactionportfolios/MyPortfolioScope/MyPortfolioCode/transactions/$batchUpsert?successMode=Partial&preserveProperties=true'
-H 'Content-Type: application/json-patch+json'
-H 'Authorization: Bearer <API-access-token>'
-d '{
"transactionRequest-1": {
"transactionId": "my_option_purchase_001",
"type": "BuyETO",
"instrumentIdentifiers": {"Instrument/default/LusidInstrumentId": "LUID_00003E8D"},
"transactionDate": "2024-10-01T09:00:00.0000000+00:00",
"settlementDate": "2024-10-03T09:00:00.0000000+00:00",
"units": 1,
"transactionPrice": {
"price": 100,
"type": "Price"
},
"totalConsideration": {
"amount": 0,
"currency": "USD"
},
"properties": {
"Transaction/MyProperties/TradeCommission": {
"key": "Transaction/MyProperties/TradeCommission",
"value": {
"metricValue": {
"value": 50,
"unit": "USD"
}
}
}
}
}
}'
Note the following:
The
type
field invokes a customBuyETO
transaction type to confer a particular economic impact (see below).The
units
field specifies the number of contracts.The
transactionPrice
object records the market price of the options contract (not the underlying). 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 enable LUSID to automatically derive total consideration (see below).
The cost of entering into the contract is recorded as a custom property.
Note: This example assumes the transaction, settlement and portfolio currencies are all the same. If not, you can specify exchange rates.
You might create a BuyETO
transaction type as follows:
curl -X PUT 'https://mydomain.lusid.com/api/api/transactionconfiguration/types/default/BuyETO?scope=default'
-H 'Content-Type: application/json-patch+json'
-H 'Authorization: Bearer <API-access-token>'
-d '{
"aliases": [
{
"type": "BuyETO",
"description": "Transaction type for option purchases",
"transactionClass": "Basic",
"transactionRoles": "AllRoles",
"isDefault": false
}
],
"movements": [
{
"name": "Increase units by number purchased",
"movementTypes": "StockMovement",
"side": "Side1",
"direction": 1
},
{
"name": "Decrease cash by cost of trade commission",
"movementTypes": "CashCommitment",
"side": "BuyETOCashCustomSide",
"direction": -1
}
],
"calculations": [
{
"type": "Txn:GrossConsideration"
},
{
"type": "DeriveTotalConsideration",
"formula": "Txn:GrossConsideration + Properties[Transaction/MyProperties/TradeCommission]"
}
]
}'
Note the following:
The
StockMovement
movement sets the units of the holding to the number purchased in the transaction.The
CashCommitment
movement decreases a cash balance by the trade commission (see the custom side below).The
Txn:GrossConsideration
transaction type calculation automatically calculates gross consideration (amount before fees) asprice * units * contractSize
, and stores the result in theTransaction/default/GrossConsideration
system property.The
DeriveTotalConsideration
transaction type calculation automatically calculates thetotalConsideration.amount
field according to the given formula, which in this case sums gross consideration and commission.
You might create a MyBuyETOCashCustomSide
as follows:
curl -X PUT 'https://mydomain.lusid.com/api/api/transactionconfiguration/sides/MyBuyCashETOCustomSide?scope=default'
-H 'Content-Type: application/json-patch+json'
-H 'Authorization: Bearer <my-API-access-token>'
-d '{
"security": "Txn:SettleCcy",
"currency": "Txn:SettlementCurrency",
"rate": "SettledToPortfolioRate",
"units": "Transaction/MyProperties/TotalCapitalisedFees",
"amount": "Transaction/MyProperties/TotalCapitalisedFees"
}'
Loading market data and confirming positions
It is mandatory to load market data for the underlying instrument into the LUSID Quote Store before you can audit your position in a portfolio holding an ExchangeTradedOption
instrument.
Loading market data
You must load a market price for the underlying (in this case AAPL) on the settlement date (in this case 3 October 2024) of a transaction in a ExchangeTradedOption
, for example:
curl -X POST 'https://mydomain.lusid.com/api/api/quotes/MyEquityQuotes'
-H 'Authorization: Bearer <my-API-access-token>'
-H 'Content-Type: application/json-patch+json'
-d '{
"Quote-0001": {
"quoteId": {
"quoteSeriesId": {
"provider": "Lusid",
"instrumentIdType": "LusidInstrumentId",
"instrumentId": "MyIDForAPPLQuotes",
"quoteType": "Price",
"field": "mid"
},
"effectiveAt": "2024-10-03T00:00:00Z"
},
"metricValue": {
"value": 240, "unit": "USD"
}
}
}'
Note the following:
This price is encapsulated in a
MyEquityQuotes
quote scope (specified in the URL).The
instrumentIdType
must beLusidInstrumentId
.The
instrumentId
must be theunderlyingCode
specified in theExchangeTradedOption
instrument definition, in this caseMyIDForAPPLQuotes
.The
provider
,quoteType
andfield
fields should be set as above, to avoid validation errors.
Creating a recipe to locate this market data
You must create a recipe that is able to locate this market data, for example:
curl -X POST 'https://mydomain.lusid.com/api/api/recipes'
-H 'Content-Type: application/json-patch+json'
-H 'Authorization: Bearer <API-access-token>'
-d '{
"configurationRecipe": {
"scope": "MyRecipes",
"code": "MyBasicPortfolioRecipe",
"market": {
"marketRules": [
{
"key": "Quote.LusidInstrumentId.MyIDForAPPLQuotes",
"dataScope": "MyEquityQuotes",
"supplier": "Lusid",
"quoteType": "Price",
"field": "mid"
}
]
}
}
}'
Note the following:
The
key
must have a prefix ofQuote.LusidInstrumentId.
and suffix of theunderlyingCode
, in this caseMyIDForAPPLQuotes
.The
dataScope
must match the quote scope in which prices are encapsulated in the LUSID Quote Store, in this caseMyEquityQuotes
.The other fields must match their respective quote fields exactly (values are case-sensitive).
Registering the recipe with the parent portfolio
You must register the recipe with the portfolio holding the ExchangeTradedOption
, for example:
curl -X POST 'https://mydomain.lusid.com/api/api/transactionportfolios/MyPortfolioScope/MyPortfolioCode/details'
-H 'Content-Type: application/json-patch+json'
-H 'Authorization: Bearer <API-access-token>'
-d '[
{
"value": {
"scope": "MyRecipes",
"code": "MyBasicPortfolioRecipe"
},
"path": "/instrumentEventConfiguration/recipeId",
"op": "add"
}
]'
Confirming positions
With market data in place, you can generate a holdings report to see the impact of the transaction on security and cash holdings, for example:
Auditing LUSID’s transaction type calculations
You can examine the output transaction generated by LUSID in reponse to the upserted input transaction, for example: