You can model:
An exchange-traded options contract as an instrument of type
ExchangeTradedOptionin LUSID. See how to do this. Note instrument events are only available for ETOs with an underlying ofEquityorFuture. Other underlyings do not support instrument events.An OTC equity options contract as an instrument of type
EquityOption. See how to do this.
Note: This tutorial uses an
ExchangeTradedOptioninstrument as an example but the information applies equally toEquityOption.
LUSID can emit the following instrument lifecycle events for ExchangeTradedOption and EquityOption, which you can handle to reduce workload and improve efficiency:
OptionExercisePhysicalEvent. This event is not automatically emitted by LUSID, but can be manually triggered to exercise an in-the-money physically-settled option at the strike price. More information.OptionExerciseCashEvent. This event is not automatically emitted by LUSID, but can be manually triggered to exercise an in-the-money cash-settled option, providing an exercise price for the underlying has been loaded into the LUSID Quote Store. More information.ExpiryEvent. This event is automatically emitted by LUSID on the expiry date, but only if you have chosen not to exercise. More information.
Mastering instruments and establishing positions
Imagine we have a options contract on BMW shares trading on the Eurex exchange with the following characteristics. See how to set this scenario up.
| Purchase transaction |
|---|---|
|
|
Exercising a physically-settled option
If the deliveryType of the ExchangeTradedOption is Physical, we can choose to exercise an in-the-money option by triggering LUSID to emit OptionExercisePhysicalEvent.
Note: No market data is required to exercise a physically-settled option. LUSID exercises at the strike price specified in the instrument definition.
To do this:
Create a corporate action source and subscribe the portfolio to it. See how to do this.
Create transaction types for the transactions automatically generated by
OptionExercisePhysicalEvent. More information.Load an event instruction (not the event itself) into the portfolio to trigger
OptionExercisePhysicalEventon a particular date. More information.
Note: For an implementation using the Python SDK, see this Jupyter Notebook.
Creating suitable transaction types
To handle OptionExercisePhysicalEvent we must create at least two transaction types:
For any
ExchangeTradedOption, we must createPhysicallySettledOptionExerciseto reduce the units and cost of the exercised instrument down to zero, so it drops out of holding and valuation reports. See our recommendation.If the
optionTypeof theExchangeTradedOptionisCall, we must createCallOptionPhysicalExerciseto buy the underlying instrument at the strike price. See our recommendation.If the
optionTypeof theExchangeTradedOptionisPut, we must createPutOptionPhysicalExerciseto sell the underlying instrument at the strike price. See our recommendation.
Loading an event instruction to trigger OptionExercisePhysicalEvent
We can call the UpsertInstrumentEventInstructions API to load an event instruction (not the event itself) into the portfolio and trigger OptionExercisePhysicalEvent:
If the
exerciseTypeof our option isAmerican, we can exercise earlier than the expiry date of the option (21 March 2025) by specifying theentitlementDateInstructedfield with an exercise date of (for example) 28 February 2025.If the
exerciseTypeisEuropean, we can only exercise on the expiry date so theentitlementDateInstructedfield is disabled.
{
"instrumentEventInstructionId": "ExerciseAmericanCallOptionOnBMW-2025-02-28",
"instrumentEventId": "LUID_00003EB8_OptionExercisePhysicalEvent_American",
"instructionType": "ElectForHolding",
"holdingId": 75498862,
"electionKey": "exercise",
"entitlementDateInstructed": "2025-02-28T00:00:00.0000000+00:00"
}For more information on event instructions, see this article. Note the following:
The
instrumentEventInstructionIdcan be any intuitive string that uniquely identifies this event instruction in this portfolio.The
instrumentEventIdmust be the unique identifier of theOptionExercisePhysicalEvent(see below for how to find this out).The
instructionTypeisElectForHoldingto apply the event to our option holding in the portfolio.The
holdingIdmust be the unique identifier for this holding (see below).The
electionKeymust beexerciseto trigger LUSID to emit the event.The
entitlementDateInstructedfield is set to the date we wish to exercise (American options only).
To discover the instrumentEventId and holdingId, call the QueryApplicableInstrumentEvents API for the portfolio, for example:
{
"values": [
{
"portfolioId": {"scope": "UKEquities", "code": "MyPortfolio"},
"lusidInstrumentId": "LUID_00003EB8",
"instrumentType": "ExchangeTradedOption",
"instrumentEventType": "OptionExercisePhysicalEvent",
"instrumentEventId": "LUID_00003EB8_OptionExercisePhysicalEvent_American"
"holdingId": 75498862,
...Examining the impact of OptionExercisePhysicalEvent on the portfolio
This example demonstrates exercising an in-the-money American call option early.
15 January
We can use the Portfolio Management > Holdings dashboard in the LUSID web app to call the GetHoldings API on the settlement date of the option purchase to see that we start with:
An option holding for 1000 units at a cost of 313,710
A currency holding for -€313,710:
.png?sv=2026-02-06&spr=https&st=2026-07-05T01%3A20%3A27Z&se=2026-07-05T01%3A39%3A27Z&sr=c&sp=r&sig=GtISxxD6pxTN5zJfCsFQqcoYDgjPCkFU3bkliallZyE%3D)
28 February
On 28 February we load the event instruction to exercise our option early and then examine holdings again:
The option holding has been removed since units and cost are now zero. Note there is no P&L associated with this movement.
A holding in the underlying BMW equity instrument has been established, with the units set to the number of BMW shares purchased (
1000 × 100 = 100,000) and the cost to those shares at the strike price plus the cost of the option:(100,000 × 80) + 313,170 = 8,313,170.The currency holding reflects the total cost of establishing the BMW holding: -€8,313,710:
.png?sv=2026-02-06&spr=https&st=2026-07-05T01%3A20%3A27Z&se=2026-07-05T01%3A39%3A27Z&sr=c&sp=r&sig=GtISxxD6pxTN5zJfCsFQqcoYDgjPCkFU3bkliallZyE%3D)
We can use the Portfolio Management > Transactions dashboard in Output mode to call the BuildTransactions API with a suitable window to examine the output transactions generated by this event:
.png?sv=2026-02-06&spr=https&st=2026-07-05T01%3A20%3A27Z&se=2026-07-05T01%3A39%3A27Z&sr=c&sp=r&sig=GtISxxD6pxTN5zJfCsFQqcoYDgjPCkFU3bkliallZyE%3D)
Exercising a cash-settled option
If the deliveryType of the ExchangeTradedOption is Cash, we can choose to exercise an in-the-money option by triggering LUSID to emit OptionExerciseCashEvent. To do this:
Create a corporate action source and subscribe the portfolio to it. See how to do this.
Create a
CashSettledOptionExercisetransaction type for the transaction automatically generated byOptionExerciseCashEventto reduce the position of the option instrument down to zero and increase cash. See our recommendation.Load an event instruction (not the event itself) into the portfolio to trigger
OptionExerciseCashEventon a particular date. More information.Load an exercise price for the underlying instrument on that date into the LUSID Quote Store. More information.
Note: For an implementation using the Python SDK, see this Jupyter Notebook.
Loading an event instruction to trigger OptionExerciseCashEvent
We can call the UpsertInstrumentEventInstructions API to load an event instruction (not the event itself) into the portfolio and trigger OptionExerciseCashEvent:
If the
exerciseTypeof our option isAmerican, we can exercise earlier than the expiry date of the option (21 March 2025) by specifying theentitlementDateInstructedfield with an exercise date of (for example) 28 February 2025.If the
exerciseTypeisEuropean, we can only exercise on the expiry date so theentitlementDateInstructedfield is disabled.
{
"instrumentEventInstructionId": "ExerciseAmericanCallOptionOnBMW-2025-02-28",
"instrumentEventId": "LUID_00003EB8_OptionExerciseCashEvent_American",
"instructionType": "ElectForHolding",
"holdingId": 75498862,
"electionKey": "exercise",
"entitlementDateInstructed": "2025-02-28T00:00:00.0000000+00:00"
}For more information on event instructions, see this article. Note the following:
The
instrumentEventInstructionIdcan be any intuitive string that uniquely identifies this event instruction in this portfolio.The
instrumentEventIdmust be the unique identifier of theOptionExerciseCashEvent(see below for how to find this out).The
instructionTypeisElectForHoldingto apply the event to our option holding in the portfolio.The
holdingIdmust be the unique identifier for this holding (see below).The
electionKeymust beexerciseto trigger LUSID to emit the event.The
entitlementDateInstructedfield is set to the date we wish to exercise (American options only).
To discover the instrumentEventId and holdingId, call the QueryApplicableInstrumentEvents API for the portfolio, for example:
{
"values": [
{
"portfolioId": {"scope": "UKEquities", "code": "MyPortfolio"},
"lusidInstrumentId": "LUID_00003EB8",
"instrumentType": "ExchangeTradedOption",
"instrumentEventType": "OptionExerciseCashEvent",
"instrumentEventId": "LUID_00003EB8_OptionExerciseCashEvent_American"
"holdingId": 75498862,
...Loading an exercise price for the underlying instrument on the exercise date
We must call the UpsertQuotes API to load an exercise price for the underlying BMW equity instrument into the LUSID Quote Store:
If the
optionTypeof our option isCall, we must load an exercise price greater than the strike price specified in the option instrument definition (in our case 80), for example 85.If the
optionTypeisPut, we must load an exercise price lower than the strike price.
curl -X POST 'https://<your-domain>.lusid.com/api/api/quotes/MyOptionExercisePricesScope'
-H 'Authorization: Bearer <your-API-access-token>'
-H 'Content-Type: application/json-patch+json'
-d '{
"Quote-0001": {
"quoteId": {
"quoteSeriesId": {
"provider": "Lusid",
"instrumentIdType": "Isin",
"instrumentId": "DE0005190003",
"quoteType": "Price",
"field": "mid"
},
"effectiveAt": "2025-02-28T00:00:00Z"
},
"metricValue": {
"value": 85, "unit": "EUR"
}
},Note the following:
We recommend exercise prices are loaded into a dedicated quote scope, for example
MyOptionExercisePricesScope(specified in the URL).The
instrumentIdTypemust beIsin.The
instrumentIdmust be registered as an ISIN identifier for the underlying instrument.The
effectiveAtmust be the exercise date, so 28 February 2025 for our American option. Note this must be the expiry date for a European option.
In order to locate this exercise price, the portfolio recipe must have a market rule with:
The
keyfield set toQuote.Isin.*to look up quotes loaded with an ISIN identifier.The
dataScopefield set toMyOptionExercisePricesScopeto search the correct quote scope, for example:
"market": {
"marketRules": [
{
"key": "Quote.Isin.*",
"supplier": "Lusid",
"dataScope": "MyOptionExercisePricesScope",
"quoteType": "Price",
"field": "mid",
"quoteInterval": "1D.0D"
},
...
]
}Examining the impact of OptionExerciseCashEvent on the portfolio
This example demonstrates exercising an in-the-money American call option early.
15 January
We can use the Portfolio Management > Holdings dashboard in the LUSID web app to call the GetHoldings API on the settlement date of the option purchase to see that we start with:
An option holding for 1000 units at a cost of 313,710
A currency holding of -€313,710:
.png?sv=2026-02-06&spr=https&st=2026-07-05T01%3A20%3A27Z&se=2026-07-05T01%3A39%3A27Z&sr=c&sp=r&sig=GtISxxD6pxTN5zJfCsFQqcoYDgjPCkFU3bkliallZyE%3D)
28 February
On 28 February we load the event instruction to exercise our option early and then examine holdings again:
The option holding has been removed since units are now zero.
The currency holding reflects the total consideration (
1000 × 100 × 5 = 500000) added to the original negative cost:
.png?sv=2026-02-06&spr=https&st=2026-07-05T01%3A20%3A27Z&se=2026-07-05T01%3A39%3A27Z&sr=c&sp=r&sig=GtISxxD6pxTN5zJfCsFQqcoYDgjPCkFU3bkliallZyE%3D)
We can use the Portfolio Management > Transactions dashboard in Output mode to call the BuildTransactions API with a suitable window to examine the output transaction generated by this event:
.png?sv=2026-02-06&spr=https&st=2026-07-05T01%3A20%3A27Z&se=2026-07-05T01%3A39%3A27Z&sr=c&sp=r&sig=GtISxxD6pxTN5zJfCsFQqcoYDgjPCkFU3bkliallZyE%3D)
To audit P&L associated with this transaction, click the button at the end of the row (highlighted in yellow above):
.png?sv=2026-02-06&spr=https&st=2026-07-05T01%3A20%3A27Z&se=2026-07-05T01%3A39%3A27Z&sr=c&sp=r&sig=GtISxxD6pxTN5zJfCsFQqcoYDgjPCkFU3bkliallZyE%3D)
Expiring an unexercised option
If we do not exercise an option before the maturity date specified in the instrument definition, LUSID automatically emits an ExpiryEvent. Note this event is not emitted if we do exercise.
To handle this event, we must create an Expiry transaction type. See our recommendation.
Examining the impact of ExpiryEvent on the portfolio
15 January
We can use the Portfolio Management > Holdings dashboard in the LUSID web app to call the GetHoldings API on the settlement date of the option purchase transaction to see that we start with:
An option holding for 1000 units at a cost of 313,710
A currency holding for -€313,710:
.png?sv=2026-02-06&spr=https&st=2026-07-05T01%3A20%3A27Z&se=2026-07-05T01%3A39%3A27Z&sr=c&sp=r&sig=GtISxxD6pxTN5zJfCsFQqcoYDgjPCkFU3bkliallZyE%3D)
21 March
If we fast-forward to the expiry date we can see that the option holding has been removed (units set to zero) and the currency holding is unchanged:
.png?sv=2026-02-06&spr=https&st=2026-07-05T01%3A20%3A27Z&se=2026-07-05T01%3A39%3A27Z&sr=c&sp=r&sig=GtISxxD6pxTN5zJfCsFQqcoYDgjPCkFU3bkliallZyE%3D)
We can use the Portfolio Management > Transactions dashboard in Output mode to call the BuildTransactions API with a suitable window to examine the output transaction generated by this event:
.png?sv=2026-02-06&spr=https&st=2026-07-05T01%3A20%3A27Z&se=2026-07-05T01%3A39%3A27Z&sr=c&sp=r&sig=GtISxxD6pxTN5zJfCsFQqcoYDgjPCkFU3bkliallZyE%3D)
To audit P&L associated with this transaction, click the button at the end of the row (highlighted in yellow above):
.png?sv=2026-02-06&spr=https&st=2026-07-05T01%3A20%3A27Z&se=2026-07-05T01%3A39%3A27Z&sr=c&sp=r&sig=GtISxxD6pxTN5zJfCsFQqcoYDgjPCkFU3bkliallZyE%3D)