The recommended way to model a foreign exchange or currency forward contract ("FxForward") in LUSID is to create an instrument in the LUSID Security Master with the contract details (size of the forward exchange), and then book a unitised transaction in a portfolio (that is, one unit of the instrument).
You can model either:
A deliverable FxForward: The exchange of two quantities of two different currencies at a specified date and time.
A non-deliverable FxForward (NDF): The payment of a settlement amount based on the exchange rate between two different currencies and amounts at a specified date and time.
This article focuses on modelling a deliverable FxForward. It also references Jupyter Notebooks that demonstrate many of the concepts and operations.
Note: You can choose not to master an instrument and simply book a forward-settled cash transaction directly in a portfolio, but note LUSID's full suite of analytical capability is not currently available. See how to do this.
Mastering an instrument
To create an instrument modelling an FxForward, call the LUSID UpsertInstruments
API and specify a definition with an instrumentType
of FxForward
, a domestic currency amount, a foreign currency amount, and start and maturity dates. For more information on constructing a suitable economic definition, examine the API reference and choose FxForward
from the definition
dropdown:
For example, and providing you have a valid API access token, you could run the following command to create an FxForward representing an obligation to pay/sell 1,000,000 GBP and buy/receive 1,200,000 USD on 15 May 2022 (that is, 6 months from the instrument start date, at an implied strike rate of 1.2):
curl -X POST 'https://<your-domain>.lusid.com/api/api/instruments'
-H 'Authorization: Bearer <your-API-access-token>'
-H 'Content-Type: application/json'
-d '{"upsert-request-1": {
"name": "GBPUSD 6M FxForward 20211115",
"identifiers": {
"ClientInternal": {
"value": "FWD-GBPUSD-20211115",
}
},
"definition": {
"instrumentType": "FxForward",
"startDate": "2021-11-15T10:00:00.0000000+00:00",
"maturityDate": "2022-05-15T10:00:00.0000000+00:00",
"domAmount": 1200000,
"domCcy": "USD",
"fgnAmount": -1000000,
"fgnCcy": "GBP",
"isNdf": false
}
}
}'
Note the following:
The
startDate
is 15 November 2021 andmaturityDate
is 15 May 2022, signifying a six month contract.The
domCcy
must be the currency in which you want your holding in this instrument to be valued. It could be GBP, but in this example it is USD.The
domAmount
is the amount ofdomCcy
. It could be negative, but in this example it is positive since USD is being bought/received.The
fgnCcy
is the other currency, in this case GBP. Note your holding will not be valued in this currency.The
fgnAmount
is the amount offgnCcy
. It must have the opposite sign todomAmount
, so in this example negative sincedomAmount
is positive.isNdf
is false (the default) to signify this is a deliverable contract.
Providing the request is valid, the response contains an automatically-generated LUID (in this case LUID_00003D58
) that is guaranteed to be unique and never change. You can use the LUID to reference the instrument in subsequent API calls:
{
"values": {
"upsert-request-1": {
"lusidInstrumentId": "LUID_00003D58",
"version": {
"effectiveFrom": "0001-01-01T00:00:00.0000000+00:00",
"asAtDate": "2021-11-13T14:12:12.3335390+00:00"
},
"name": "GBPUSD 6M FxForward 20211115",
"identifiers": {
"LusidInstrumentId": "LUID_00003D58",
"ClientInternal": "FWD-GBPUSD-20211115"
},
"properties": [],
"instrumentDefinition": {
"startDate": "2021-11-15T10:00:00.0000000+00:00",
"maturityDate": "2022-05-15T10:00:00.0000000+00:00",
"domAmount": 1200000.0,
"domCcy": "USD",
"fgnAmount": -1000000.0,
"fgnCcy": "GBP",
"refSpotRate": 0.0,
"isNdf": false,
"fixingDate": "0001-01-01T00:00:00.0000000+00:00",
"instrumentType": "FxForward"
},
"state": "Active",
"assetClass": "FX",
"domCcy": "GBP"
}
},
...
}
Booking a transaction to establish a position
Once the instrument is mastered, you can call the LUSID UpsertTransactions API to record a purchase of the contract in a particular portfolio.
As mentioned above, FxForwards should be created with the currency amounts encapsulated in the instrument, and the transaction itself unitised (that is, with the units
set to 1). Note also:
The
totalConsideration.amount
(cost) should be 0.The
transactionCurrency
and thetotalConsideration.currency
(settlement currency) should be thedomCcy
of the instrument, in this example USD.The
transactionDate
and thesettlementDate
should mark the start of the contract, in this example 15 November 2021 (the instrument defines the length):
curl -X POST "https://<your-domain>.lusid.com/api/api/transactionportfolios/<scope>/<code>/transactions"
-H "Authorization: Bearer <your-API-access-token>"
-H "Content-Type: application/json"
-d '[ {
"transactionId": "fxfwd-gbp-usd-6m-01",
"type": "StockIn",
"instrumentIdentifiers": {
"instrument/default/LusidInstrumentId": "LUID_00003D58"
},
"transactionDate": "2021-11-15T00:00:00.0000000+00:00",
"settlementDate": "2021-11-15T00:00:00.0000000+00:00",
"units": 1,
"transactionPrice": {
"price": 0,
"type": "Price"
},
"totalConsideration": {
"amount": 0,
"currency": "USD"
},
"transactionCurrency": "USD",
"exchangeRate": 1
}
]'
Note this transaction uses the built-in StockIn
transaction type rather the built-in Buy
, since there is no cash outlay. However, you could define your own custom transaction type to represent FxForward purchases if you wish.
You can confirm your position at any time by calling the LUSID GetHoldings API with the appropriate LUID:
curl -X GET "https://<your-domain>.lusid.com/api/api/transactionportfolios/<scope>/<code>/holdings?filter=instrumentUid%20eq%20'LUID_00003D58'"
-H "Authorization: Bearer <your-API-access-token>"
Valuing your position
You can value your position against actual or estimated exchange rates at any time, and calculate the notional profit or loss (that is, the amount you have gained or lost by virtue of having entered into the fixed rate contract, relative to not having done so).
In the example above, we are obliged to buy 1,200,000 USD at a cost of 1,000,000 GBP in 6 months from the instrument start date, which means the implied strike rate is 1.2. If we value the contract after 3 months and the current spot rate has decreased to 1.1, then you would expect LUSID to show your position with a notional profit of 100,000 USD, since you have ‘gained’ this amount by fixing the forward rate. On the other hand, if the spot rate has increased to 1.3, then you would expect LUSID to show a notional loss of 100,000 USD.
The following pricing models are available for FxForwards:
Pricing model | Notes |
---|---|
| This is the default. See how to specify a different model. |
| |
| |
| |
| There is currently an issue with these models. They are available for use but require a market data workaround; see the examples in this Jupyter Notebook, or contact Technical Support for details. In the meantime, the |
| This is not really a model, but rather provides a set of options that enables you to emulate other models. Despite its name, you can emulate undiscounted models. Contact Technical Support for more information. |
The recommended models have different market data requirements and capabilities. Note that, by default:
LUSID values the entire instrument. You can change this for most models to value the domestic and foreign legs separately by setting the
produceSeparateResultForLinearOtcLegs=true
recipe option.LUSID values the instrument in the currency of the domestic leg. You can change this for most models to value in a report currency, which could be the portfolio currency (if different) or even a completely separate currency. More information.
LUSID does not infer missing FX rates. You can change this to infer (for example) USDGBP as 1/GBPUSD by setting the
attemptToInferMissingFx=true
recipe option. For more information on FX inference and triangulation, see this Jupyter Notebook.
The market data required and the valuation results themselves may differ depending on the model chosen and any changes you make to the defaults above. For more information, including worked examples of every model and option, see this Jupyter Notebook.
Pricing model | Discounting performed? | Available valuations | Market data required for valuation date | Market data store | Notes |
---|---|---|---|---|---|
| No | Whole instrument | 1 FX spot rate: | Quote Store | PV is the sum of the two legs with FGN converted to DOM at the spot rate. |
Separate legs | 2 FX spot rates: | ||||
| No | Whole instrument | Quote for the instrument that is a value per unit of the domestic currency. | Quote Store | PV is value per unit of domestic currency multiplied by the absolute value of the domestic amount. |
| Yes | Whole instrument | 1 forward rate curve, 1 discounting curve | Complex Market Data Store | For more information on curve interpolation and extrapolation, see section 5 of this Jupyter Notebook. |
1 FX spot rate: | Quote Store | The FX spot rate is a required dependency but does not impact the valuation. | |||
Separate legs | 1 forward rate curve, 1 discounting curve | Complex Market Data Store | For more information on curve interpolation and extrapolation, see section 5 of this Jupyter Notebook. | ||
2 FX spot rates: | Quote Store | The FX spot rates are used to convert FGN to DOM. | |||
| No | Whole instrument | 1 forward rate curve | Complex Market Data Store | For more information on curve interpolation and extrapolation, see section 5 of this Jupyter Notebook. |
1 FX spot rate: | Quote Store | The FX spot rate is a required dependency but does not impact the valuation. | |||
Separate legs | 1 forward rate curve | Complex Market Data Store | For more information on curve interpolation and extrapolation, see section 5 of this Jupyter Notebook. | ||
2 FX spot rates: | Quote Store | The FX spot rates are used to convert FGN to DOM. |
Valuing in report currency
By default, the whole FxForward instrument is valued in the domestic currency, which you can report using the Valuation/PV
metric. If the domestic and portfolio currencies are different, you can also specify the Valuation/PvInPortfolioCcy
metric to convert to the portfolio currency using forward and spot rates (depending on the model).
You can provide a more sophisticated reporting configuration but note that the results are not interchangeable. For example, to report in a completely separate currency that is neither that of the domestic leg nor the portfolio currency you can set the convertToReportCcy=true
model option and then specify the reportCurrency
parameter in your call to the GetValuation API.
For more information on the implications of this, see section 3 of this Jupyter Notebook.
Assessing risk
LUSID provides an exposure calculation and supports both analytic and bump and valuation mechanisms for assessing risk.
Monitoring the lifecycle of the instrument
At some point you must decide whether to roll an FxForward contract or hold it until maturity.
Rolling a contract means extending its maturity date; typically, the old contract is closed by setting a holding of zero (with a cash amount booked to reflect the P&L) and a new contract with a longer time to expiry is executed to replace the old. For a demonstration, see section 7.1 of this Jupyter Notebook.
If you choose to hold until maturity then note an instrument does not ‘expire’ in LUSID; it is still available post-maturity, 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 FxForwards. We provide default transaction templates that you can use to automatically generate transactions in impacted portfolios, and recommendations for transaction types that deliver appropriate economic impacts. More information.
Contact us to turn this feature on in your environment. The following events are available for FxForwards:
Instrument event type | Effect of LUSID default transaction template | Recommendations for transaction types |
---|---|---|
| Two transactions are automatically generated for a deliverable FxForward and one for a NDF. The intention is that you handle this event to exchange the two cashflows. | |
| One transaction is automatically generated. The intention is that you handle this event to set your position in the instrument to zero, so it drops out of valuation reports. | |
Manually loading settlement transactions
If you do not want to turn on automatic instrument lifecycle events you can continue to monitor upcoming cashflows using Dashboards > 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. For a demonstration, see sections 7.2 and 7.3 of this Jupyter Notebook.