--- title: "Fine-tuning pricing models using model options" slug: "fine-tuning-pricing-models-with-model-options" updated: 2026-11-01T11:51:00Z published: 2026-11-01T11:51:00Z canonical: "support.lusid.com/fine-tuning-pricing-models-with-model-options" --- > ## 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. # Fine-tuning pricing models using model options Most [pricing models](/v1/docs/understanding-lusid-s-pricing-models) have *model options* that change how they behave: where an FX forward rate comes from, how an equity forward is projected, whether a bond quoted at a market price still reports interest rate risk, and so on. Setting the right options lets you match an external valuation, unlock risk metrics, or reflect how your desk actually thinks about an instrument, without changing the model itself. ## How model options work A [recipe](/v1/docs/what-is-a-recipe) has a `pricing` section that we strongly recommend you use to change the [default pricing models](/v1/docs/what-pricing-models-can-i-use-in-my-valuation). At the same time, you can set model options in the `modelOptions` object of a vendor model rule. Each rule names an instrument type and a pricing model; the options then fine-tune that model for that instrument type, for example: ```json "pricing": {  "modelRules": [    {      "supplier": "Lusid",      "modelName": "BlackScholes",      "instrumentType": "EquityOption",      "modelOptions": {        "modelOptionsType": "EquityModelOptions",        "equityForwardProjectionType": "FlatForwardCurveFromSpot"      }    }  ] } ``` Note the following: - The `modelOptionsType` field identifies the kind of options. It's mandatory, and each kind has its own set of fields. If you include a kind of option, you must set its mandatory fields, or LUSID rejects the recipe. - Options belong to a model, not just an instrument type. For example, `HullWhiteModelOptions` only has an effect when the rule's model is `HullWhite1F`. The tables below show which models read each kind of option. - Omitting `modelOptions` uses the model's defaults. This is the same as setting `"modelOptionsType": "EmptyModelOptions"`, which has no other fields. The defaults are listed for each kind of option below, and they're not always the same across models. - LUSID ignores options that don't match the model. If you set (for example) `EquityModelOptions` on a `BondLookupPricer` rule, LUSID doesn't report an error; it values the instrument using the model's defaults. LUSID does still check that the option values themselves are valid. Check the tables below to make sure your options and model go together. ## Summary of model options | `modelOptionsType` | **Use it to...** | **Pricing models** | **Instrument types** | | --- | --- | --- | --- | | [FxForwardModelOptions](/v1/docs/fine-tuning-pricing-models-with-model-options#fxforwardmodeloptions) | Choose where the forward FX rate comes from, whether to discount, and whether to value in your report currency. | `Discounting`, `ConstantTimeValueOfMoney`, and the `ForwardFromCurve`, `ForwardWithPoints` and `ForwardSpecifiedRate` families | `FxForward` | | [EquityModelOptions](/v1/docs/fine-tuning-pricing-models-with-model-options#equitymodeloptions) | Choose how the forward price of the underlying equity is projected. | `BlackScholes`, `BjerksundStensland1993`, `Bachelier`, `Discounting`, `ConstantTimeValueOfMoney` | `EquityOption`, `ContractForDifference`, `EquitySwap` | | [FundingLegModelOptions](/v1/docs/fine-tuning-pricing-models-with-model-options#fundinglegmodeloptions) | Choose whether to value future funding coupons or just the interest accrued so far. | `Discounting`, `ConstantTimeValueOfMoney` | `FundingLeg` | | [IndexModelOptions](/v1/docs/fine-tuning-pricing-models-with-model-options#indexmodeloptions) | Look through a fund to value its constituents, and choose how they're scaled. | Any model valid for the instrument type (for `SimpleInstrument`: `SimpleStatic`, `InlinedIndex`) | Any instrument with a look-through portfolio, for example a `SimpleInstrument` representing a fund | | [SimpleModelOptions](/v1/docs/fine-tuning-pricing-models-with-model-options#simplemodeloptions) | Value from a price with no accrued interest calculation, or treat a swap price as an offset from par. | `SimpleStatic` | Any instrument valued by `SimpleStatic` | | [BondLookupModelOptions](/v1/docs/fine-tuning-pricing-models-with-model-options#bondlookupmodeloptions) | Get interest rate and credit spread risk for a bond you value at its market price. | `BondLookupPricer` | `Bond`, `ComplexBond`, `InflationLinkedBond` | | [HullWhiteModelOptions](/v1/docs/fine-tuning-pricing-models-with-model-options#hullwhitemodeloptions) | Calibrate the interest rate model used to value callable and puttable bonds, and control its risk measures. | `HullWhite1F` | `Bond`, `ComplexBond` | | [BondForwardModelOptions](/v1/docs/fine-tuning-pricing-models-with-model-options#bondforwardmodeloptions) | Choose whether a bond forward is valued from its quoted price or modelled from the deliverable bond. | `Discounting` | `BondForward` | | [FlexibleLoanPricerOptions](/v1/docs/fine-tuning-pricing-models-with-model-options#flexibleloanpriceroptions) | Report a loan or deposit at its accrued interest only. | `FlexibleLoanPricer` | `FlexibleLoan`, `FlexibleDeposit` | ## `FxForwardModelOptions` Use these options to choose the market data an FX forward is valued from. For example, you can value from an FX forward curve rather than from interest rate curves, value without discounting to match an administrator, or value every forward in a third currency using forward rather than spot rates. | **Field** | **Values** | **Default if** `modelOptions` **is omitted** | **Description** | | --- | --- | --- | --- | | `forwardRateObservableType` | `RatesCurve`, `FxForwardCurve`, `ForwardPoints`, `ForwardRate`, `Invalid` | `Invalid` (treated as `RatesCurve`) | Where the forward rate comes from. See the market data table below. Only has an effect under `Discounting`. | | `discountingMethod` | `Standard`, `ConstantTimeValueOfMoney`, `Invalid` | `Invalid` (treated as `Standard`) | `Standard` discounts the forward's value to the valuation date. `ConstantTimeValueOfMoney` doesn't discount. Only has an effect under `Discounting`, with `FxForwardCurve`, `ForwardPoints` or `ForwardRate`. With `RatesCurve`, LUSID always discounts. | | `convertToReportCcy` | `true`, `false` | `false` | Set to `true` to value the forward directly in your report currency, using forward rates between the report currency and each of the forward's two currencies. Otherwise, LUSID values the forward in its own currency and converts the result to your report currency at the spot rate. You specify the report currency when you value. See [Valuing in a report currency](/docs/fine-tuning-pricing-models-with-model-options#valuing-in-a-report-currency) below. | | `allowSpotFallbackForReportCcy` | `true`, `false` | `false` | Optional. With `convertToReportCcy` set to `true`, set this to `true` to convert at the spot rate when the report currency forward rates aren't available, rather than failing the valuation. Has no effect if the `produceSeparateResultForLinearOtcLegs` pricing option is `true`. | If you include `FxForwardModelOptions` in a rule, you must set `forwardRateObservableType`, `discountingMethod` and `convertToReportCcy`, otherwise LUSID rejects the recipe. Use `Invalid` to keep a field's default. ### Where the forward rate comes from | `forwardRateObservableType` | **Forward rate** | **Market data required (in addition to the spot rate,** `Fx.<DOM>.<FGN>`**)** | | --- | --- | --- | | `RatesCurve` or `Invalid` | Implied from the spot rate and the interest rate curves of the two currencies. | [Discount curves](/v1/docs/categories-of-complex-market-data) for both currencies in the Complex Market Data Store, for example `Rates.GBP.GBPOIS` and `Rates.USD.USDOIS`. | | `FxForwardCurve` | Read from an FX forward curve at the forward's maturity date. | An [FX forward curve](/v1/docs/categories-of-complex-market-data) in the Complex Market Data Store, `FxForwards.<DOM>.<FGN>.FxFwdCurve`. For `Standard` discounting, the domestic currency discount curve. | | `ForwardPoints` | The spot rate plus forward points. One point is 0.0001, or 0.01 for a currency pair involving JPY. | A quote in the Quote Store with an `instrumentIdType` of `LusidInstrumentId`, an `instrumentId` of `<DOM>/<FGN>/Points/<maturity date as yyyyMMdd>`, and a `quoteType` of `Price`. For `Standard` discounting, the domestic currency discount curve. | | `ForwardRate` | Read as an outright forward rate. | A quote in the Quote Store with an `instrumentIdType` of `LusidInstrumentId`, an `instrumentId` of `<DOM>/<FGN>/FxFwdRate/<maturity date as yyyyMMdd>`, and a `quoteType` of `Price`. For `Standard` discounting, the domestic currency discount curve. | > **Note:** Forward points and forward rate quotes are keyed by the forward's exact maturity date. LUSID doesn't interpolate between them, so you need a quote for every maturity date in your portfolio. If you hold forwards with many different maturities, an FX forward curve is usually easier to maintain. ### Using named models instead Under the `Discounting` model, these options give exactly the same results as the named FX forward models: | `forwardRateObservableType` | `discountingMethod`**:** `Standard` | `discountingMethod`**:** `ConstantTimeValueOfMoney` | | --- | --- | --- | | `FxForwardCurve` | `ForwardFromCurve` | `ForwardFromCurveUndiscounted` | | `ForwardPoints` | `ForwardWithPoints` | `ForwardWithPointsUndiscounted` | | `ForwardRate` | `ForwardSpecifiedRate` | `ForwardSpecifiedRateUndiscounted` | The named models fix the forward rate source and the discounting method, so they ignore `forwardRateObservableType` and `discountingMethod`. They still read `convertToReportCcy` and `allowSpotFallbackForReportCcy`. The `ConstantTimeValueOfMoney` model also ignores `forwardRateObservableType` and `discountingMethod`. It values both legs at the spot rate, with no forward rate and no discounting, so it isn't the same as the undiscounted models above. ### Valuing in a report currency How `convertToReportCcy` behaves depends on where the forward rate comes from. Say you hold a GBP/USD forward and report in EUR: - `FxForwardCurve` **or** `ForwardRate`**:** LUSID values the forward using EUR/GBP and EUR/USD forward rates, and discounts on the EUR discount curve. The spot rate doesn't affect the result. You need the EUR/GBP and EUR/USD forward curves or quotes, and the EUR discount curve. - `ForwardPoints`**:** as above, but the EUR/GBP and EUR/USD forward rates are built from spot rates plus points, so spot rates still affect the result. - `RatesCurve` **or** `Invalid`**:** setting `convertToReportCcy` to `true` makes no difference. LUSID converts at the spot rate. If a report currency forward rate is missing, the valuation fails with a market data error naming the missing item, for example `FxForwards.EUR.GBP.FxFwdCurve`. Set `allowSpotFallbackForReportCcy` to `true` to convert at spot instead. ```json {  "supplier": "Lusid",  "modelName": "Discounting",  "instrumentType": "FxForward",  "modelOptions": {    "modelOptionsType": "FxForwardModelOptions",    "forwardRateObservableType": "FxForwardCurve",    "discountingMethod": "ConstantTimeValueOfMoney",    "convertToReportCcy": true  } } ``` For more information on valuing FX forwards, see [Modelling FxForwards in LUSID](/v1/docs/modelling-fxforwards-in-lusid#valuing-your-position). ## `EquityModelOptions` Use these options to choose how LUSID projects the forward price of the underlying equity. Projecting from the interest rate curve is the textbook approach. Keeping the forward flat at spot, or supplying your own curve of forward prices, can match a counterparty's or administrator's valuation, or reflect expected dividends. | **Field** | **Values** | **Description** | | --- | --- | --- | | `equityForwardProjectionType` | `ForwardProjectedFromRatesCurve`, `FlatForwardCurveFromSpot`, `EquityCurveByPrices` | `ForwardProjectedFromRatesCurve` grows the spot price at the rate on the discount curve. `FlatForwardCurveFromSpot` assumes the forward price equals the spot price. `EquityCurveByPrices` reads forward prices from an [equity curve](/v1/docs/categories-of-complex-market-data) you load into the Complex Market Data Store. | The default if you omit `modelOptions` depends on the instrument type and model: | **Instrument type** | **Pricing model** | **Default** | | --- | --- | --- | | `EquityOption` | `BlackScholes`, `BjerksundStensland1993`, `Bachelier`, `Discounting` | `ForwardProjectedFromRatesCurve` | | `EquityOption` | `ConstantTimeValueOfMoney` | `FlatForwardCurveFromSpot` | | `ContractForDifference`, `EquitySwap` | `Discounting`, `ConstantTimeValueOfMoney` | `FlatForwardCurveFromSpot` | > **Note:** The same underlying can therefore have a different forward price in an equity option than in a CFD or equity swap, unless you set this option explicitly. Under `ConstantTimeValueOfMoney`, `ForwardProjectedFromRatesCurve` and `FlatForwardCurveFromSpot` give the same result, because that model doesn't use an interest rate curve. If you include `EquityModelOptions` in a rule, you must set `equityForwardProjectionType`. ```json {  "supplier": "Lusid",  "modelName": "Discounting",  "instrumentType": "ContractForDifference",  "modelOptions": {    "modelOptionsType": "EquityModelOptions",    "equityForwardProjectionType": "ForwardProjectedFromRatesCurve"  } } ``` ## `FundingLegModelOptions` Use this option to choose how much of a funding leg (for example, the funding leg of an equity swap held as a separate position) LUSID values. You can value the full remaining schedule of coupons, or just the interest accrued so far, which some funds prefer for reporting because it doesn't depend on assumptions about future notional. | **Field** | **Values** | **Default if** `modelOptions` **is omitted** | **Description** | | --- | --- | --- | --- | | `expectedFundingLegNotional` | `Constant`, `Zero` | `Constant` | `Constant` assumes the current notional stays the same until maturity, and values the rest of the current coupon plus all future coupons. `Zero` values only the interest accrued so far in the current coupon. | If you include `FundingLegModelOptions` in a rule, you must set `expectedFundingLegNotional`. For example, for a 1,000,000 notional leg paying EURIBOR 3M plus 50bp, valued 45 days into a 3 month coupon with rates at 3%: | **Pricing model** | `Constant` | `Zero` | | --- | --- | --- | | `ConstantTimeValueOfMoney` | 35,486.11 (all remaining coupons) | 4,375.00 (interest accrued to date) | | `Discounting` | 34,732.90 | 4,358.85 (interest accrued to date, discounted from the payment date) | `Valuation/Accrued` is 4,375.00 either way. ```json {  "supplier": "Lusid",  "modelName": "Discounting",  "instrumentType": "FundingLeg",  "modelOptions": {    "modelOptionsType": "FundingLegModelOptions",    "expectedFundingLegNotional": "Zero"  } } ``` > **Note:** A funding leg takes its notional from your holding, so you must value it in a portfolio. Book the transaction with the `Transaction/default/RequiresFundingLegHistory` property set to `true`. ## `IndexModelOptions` Use these options to look through an instrument to the portfolio it represents, for example to value a [‘fund of funds’ portfolio](/v1/docs/setting-up-and-valuing-a-fund-of-funds-portfolio) at the level of the underlying holdings, or to expand an index into its constituents. You can choose how LUSID scales the constituents to the size of your holding. | **Field** | **Values** | **Description** | | --- | --- | --- | | `portfolioScaling` | `Sum`, `AbsoluteSum`, `Unity` | Mandatory. How LUSID scales the child portfolio's holdings to the size of your holding. See the table below. | | `lookthroughPortfolioRelationshipId` | Object with `scope` and `code` | Optional. The scope and code of a relationship definition between instruments and portfolios. Use this to nominate the child portfolio with a relationship, rather than hard-coding it in the instrument's `lookThroughPortfolioId`. If both exist, the relationship takes precedence. If the instrument has no relationship, LUSID uses its `lookThroughPortfolioId`. If it has neither, LUSID values the instrument from its price, without reporting an error. | If you omit `modelOptions`, LUSID doesn't look through the instrument, and values it from its price, unless the rule's model is `InlinedIndex`, which looks through using `Sum`. | `portfolioScaling` | **How LUSID scales the child holdings** | **Example: you hold 10 units of a fund priced at 40 (value 400). The child holds a long position worth +3,000 and a short worth −1,000.** | | --- | --- | --- | | `Sum` | Scales every holding by the same factor, so the child holdings add up to the value of your holding. Short positions stay short. | Factor 400 / 2,000 = 0.2. Long +600, short −200. Total 400. | | `AbsoluteSum` | Scales by the value of your holding divided by the sum of the absolute values of the child holdings. Every holding is reported with a positive value, including short positions. | Factor 400 / 4,000 = 0.1. Long +300, short +100. Total 400. | | `Unity` | Multiplies the child holdings by the number of units you hold, ignoring the fund's price. The total doesn't necessarily equal the value of your holding. | Long +30,000, short −10,000. Total 20,000. | LUSID scales units, PV and accrued interest by the same factor. Note the following: - `Sum` fails if the child portfolio has a net value of zero (for example, longs and shorts that cancel out, or an empty portfolio), with the error "Unable to perform lookthrough scaling for portfolio… with zero net value". `AbsoluteSum` works when longs and shorts cancel out. `Unity` returns no rows at all for an empty child portfolio, so the holding silently disappears from your valuation. - For `Sum` and `AbsoluteSum`, you can choose what LUSID shares out. The `conservedQuantityForLookthroughExpansion` pricing option controls this: `PV` (the default), or `Exposure`. For example, use `Exposure` if the child holds futures, whose exposure is much larger than their PV. See [Recipes: Changing default recipe options](/v1/docs/recipes-changing-default-recipe-options). - `IndexModelOptions` works with any model that's valid for the instrument type. For a `SimpleInstrument`, that's `SimpleStatic` or `InlinedIndex`. For other instrument types with a look-through portfolio, such as a `Bond`, LUSID shares out the value calculated by the rule's model. - LUSID values the child holdings using the same recipe as the parent. ```json {  "supplier": "Lusid",  "modelName": "SimpleStatic",  "instrumentType": "SimpleInstrument",  "modelOptions": {    "modelOptionsType": "IndexModelOptions",    "portfolioScaling": "Sum"  } } ``` ## `SimpleModelOptions` Use these options when you want LUSID to value an instrument purely from the price you supply. You can switch off the accrued interest calculation, so LUSID doesn't ask for fixings it doesn't need. If your swap marks are quoted around par, you can have LUSID read them that way. | **Field** | **Values** | **Default if** `modelOptions` **is omitted** | **Description** | | --- | --- | --- | --- | | `assumeAccruedIsZero` | `true`, `false` | `false` | Set to `true` to skip calculating accrued interest, so the PV is the market price only. LUSID then doesn't need interest rate fixings for a floating-rate instrument. If you supply an accrued interest override in the [Structured Result Store](/v1/docs/what-is-structured-result-data), LUSID still uses it. | | `priceIsParOffset` | `true`, `false` | `false` | Set to `true` to read the price as an offset from par. One unit of notional is then valued at (price − 100) / 100, so a price of 101 on a 1,000,000 swap gives a clean PV of 10,000. If the quote has a scale factor, LUSID uses that instead of 100. The quote type must be `Price`, giving the clean PV (LUSID adds accrued interest to it), or `DirtyPrice`, giving the PV. Available for `InterestRateSwap` under `SimpleStatic` only; LUSID fails the valuation for any other instrument type. | > **Note:** With `priceIsParOffset`, the scale factor is the par value. A price of `101` loaded with a scale factor of `1` is read as 100 times par, and the PV is wrong by a factor of 10,000. Load swap prices quoted per 100 with no scale factor or a scale factor of `100`. > **Note:** The direction of the swap doesn't change the sign of the value LUSID takes from the price. Quote a swap from the point of view of the position you hold. ```json {  "supplier": "Lusid",  "modelName": "SimpleStatic",  "instrumentType": "InterestRateSwap",  "modelOptions": {    "modelOptionsType": "SimpleModelOptions",    "assumeAccruedIsZero": true,    "priceIsParOffset": true  } } ``` For more information, see [Modelling interest rate swaps in LUSID](/v1/docs/modelling-interest-rate-swaps-in-lusid). ## `BondLookupModelOptions` The `BondLookupPricer` pricing model values a bond at its market price. Because the price doesn't depend on any curve, by default LUSID reports interest rate risk such as `Risk/Rates/Pv01` as zero, with an explanation in the `Aggregation/Errors` column, and no credit spread risk. Use these options to get interest rate and credit spread risk, such as `Pv01`, key rate durations and `CS01`, for a bond you value from market data. LUSID does this by valuing the bond off the discount curve at a constant spread over it. | **Field** | **Values** | **Default if** `modelOptions` **is omitted** | **Description** | | --- | --- | --- | --- | | `spreadAnchoredRisk` | `true`, `false` | `false` | Mandatory. Set to `true` to value the bond off the discount curve at a constant spread, and report interest rate and credit spread risk. Requires the discount curve. | | `spreadAnchorSource` | `MarketData`, `SolvedFromPrice` | `MarketData` | Where the spread comes from. See the table below. Only used if `spreadAnchoredRisk` is `true`. | | `spreadTermStructure` | `true`, `false` | `false` | Only used if `spreadAnchoredRisk` is `true`. Set to `true` to discount each cashflow at the spread for its own payment date, rather than the spread at maturity. This splits credit risk by cashflow. On a flat credit spread curve, or with a `ZSpread` quote, the PV is unchanged. On a sloped curve, the PV changes. | | `cs01BumpWidth` | Positive number | `0.0001` (1bp) | The total width of the spread bump used to calculate `Analytic/CS01/Central`. A width of `0.0001` revalues the bond at the spread plus and minus 0.5bp. The result is always reported per 1bp. | | `workout` | `Maturity`, `NextCall` | `Maturity` | For a callable `ComplexBond`, set to `NextCall` to calculate z-spread analytics and risk as if the bond is redeemed at its next call date. LUSID reports the call date in `Valuation/Diagnostics/Model/PricingHorizon`. See the note below for how this affects PV. Has no effect on a bond with no call. | The spread comes from the following sources, in order of preference: | `spreadAnchorSource` | **1. Credit spread curve for the bond** | **2.** `ZSpread` **quote for the bond** | **3. Neither** | | --- | --- | --- | --- | | `MarketData` | Used, but you must also load a `ZSpread` quote. | Used. | The valuation fails. | | `SolvedFromPrice` | Used. | Used. | LUSID works out the spread from the bond's market price, so the PV equals the market value. | > **Note:** With `workout` set to `NextCall`, the PV is unchanged if LUSID works out the spread from the market price. If you load a credit spread curve or `ZSpread` quote, LUSID values the bond's cashflows to the call date at that spread, so the PV changes. > **Note:** LUSID loads a `ZSpread` quote using a market data rule with a quote type of `Rate`. Order this rule **after** the rule for the bond's price (quote type `Price`). If the `Rate` rule comes first, any bond in the same recipe that you value without `spreadAnchoredRisk` fails, because LUSID picks up its `ZSpread` quote as its price. ```json {  "supplier": "Lusid",  "modelName": "BondLookupPricer",  "instrumentType": "Bond",  "modelOptions": {    "modelOptionsType": "BondLookupModelOptions",    "spreadAnchoredRisk": true,    "spreadAnchorSource": "SolvedFromPrice"  } } ``` For more information, see [Modelling vanilla fixed-rate bonds in LUSID](/v1/docs/modelling-fixed-rate-vanilla-bonds-in-lusid) and [How does LUSID assess risk?](/v1/docs/how-does-lusid-assess-risk). ## `HullWhiteModelOptions` The `HullWhite1F` pricing model values callable and puttable bonds on an interest rate lattice, so the value of the call or put is reflected in the PV and risk. Use these options to calibrate the model to your own view of rates volatility, shock that volatility for scenarios, and control how option-adjusted risk measures are calculated. All fields are optional. If you omit `modelOptions`, LUSID uses the defaults below. | **Field** | **Default** | **Description** | | --- | --- | --- | | `meanReversion` | `0.03` | How quickly short-term rates revert to the curve. Must be greater than zero. | | `volatility` | `0.008` | The volatility of short-term rates, as an absolute rate (`0.008` is 80bp a year). Must not be negative. Zero values the bond as if future rates are certain. The higher the volatility, the more a call is worth to the issuer, so the lower the PV of a callable bond. | | `meanReversionByCurrency` | None | Overrides `meanReversion` for particular currencies, for example `{"USD": 0.05}`. | | `volatilityByCurrency` | None | Overrides `volatility` for particular currencies, for example `{"GBP": 0.012}`. | | `volatilityMultiplier` | `1` | Multiplies whichever volatility applies, for example 1.1 for a 10% rise. A scenario can’t shift this option. To shock volatility in a scenario, use a [model option shift](/v1/docs/scenario-reference#model-option-shifts) on `Volatility` instead. | | `latticeSteps` | `200` | The number of time steps in the lattice. More steps are more accurate but slower. | | `latticeStepsPerYear` | None | Sets the lattice density per year instead of a fixed number of steps, so long-dated bonds get more steps. If you set this, LUSID ignores `latticeSteps`. | | `maxLatticeNodes` | None | Caps the size of the lattice for any one bond, to limit calculation time. LUSID declines a bond that would exceed it, with an error giving the size needed. | | `effectiveRateBumpSize` | `0.0025` (25bp) | The parallel curve shift used to calculate `Analytic/EffectiveDuration` and `Analytic/EffectiveConvexity`. Effective convexity of a callable bond can be very sensitive to this. | | `effectiveCs01BumpWidth` | `0.0001` (1bp) | The total width of the spread bump used to calculate `Analytic/EffectiveCS01`. The result is always reported per 1bp. | | `effectiveKeyRateBuckets` | `1Y`, `2Y`, `3Y`, `5Y`, `7Y`, `10Y`, `20Y`, `30Y` | The maturity buckets for `Analytic/EffectiveKeyRateDuration`, such as `["2Y", "5Y", "10Y"]`. Must be in increasing order, otherwise the metric fails. Buckets beyond a bond's maturity report zero. | | `priceAtQuoteImpliedOas` | `false` | Set to `true` to value the bond at a spread over the curve, rather than at no spread. If you load an `OAS` quote for the bond, LUSID uses that spread. Otherwise, it works out the spread from the bond's market price, so the PV matches the market value. | | `ignoreOptionality` | `false` | Set to `true` to value the bond as if it had no call or put dates. Compare with the normal valuation to measure the value of the optionality. | | `priceToFirstReset` | `false` | Set to `true` to value a fixed-to-floating callable bond (such as an AT1) as if it is called at its first reset date. The bond must have one fixed schedule, followed by one floating schedule starting on the call date. LUSID rejects bonds of any other structure. | ```json {  "supplier": "Lusid",  "modelName": "HullWhite1F",  "instrumentType": "ComplexBond",  "modelOptions": {    "modelOptionsType": "HullWhiteModelOptions",    "meanReversion": 0.03,    "volatilityByCurrency": { "USD": 0.01, "EUR": 0.007 }  } } ``` > **Note:** Volatility and mean reversion are model options rather than market data, so LUSID doesn’t report volatility risk for them. To see how a change in volatility affects value, apply a scenario containing a [model option shift](/v1/docs/scenario-reference#model-option-shifts) on `Volatility`. For example, a `relative` shift of 0.1 raises volatility by 10%. > **Note:** `Analytic/OAS` and the effective measures need a market price for the bond. If you request any of them and the price is missing, the whole row fails, including the PV. If you load an `OAS` quote (quote type `Rate`), order its market data rule after the rule for the bond's price. ## `BondForwardModelOptions` Use this option to choose how a bond forward is valued. Valuing from the quoted contract price is simple, but gives no interest rate risk. Modelling the forward from the deliverable bond gives you the full curve risk of the position. | **Field** | **Values** | **Description** | | --- | --- | --- | | `bondForwardProjectionType` | `QuotedContractPrice`, `ForwardProjectedFromFundingCurve`, `DeliverableSpreadAnchoredToQuote` | `QuotedContractPrice` values from the quoted price of the forward contract. `ForwardProjectedFromFundingCurve` takes the deliverable bond's quoted price and carries it forward to settlement on the discount curve. `DeliverableSpreadAnchoredToQuote` does the same, but also values the deliverable bond off the curve at a constant spread, so the forward picks up the bond's own interest rate risk. | | **Projection type** | **What the value depends on** | **Interest rate risk** | | --- | --- | --- | | `QuotedContractPrice` | The forward contract's price quote. | None. LUSID reports that risk can't be calculated. | | `ForwardProjectedFromFundingCurve` | The deliverable bond's market price, the agreed price, and the discount curve up to settlement. | Carry only: curve risk up to the settlement date. | | `DeliverableSpreadAnchoredToQuote` | As above, but the deliverable bond is valued off the curve at its `ZSpread`. If the `ZSpread` is consistent with the bond's price, the PV is the same as `ForwardProjectedFromFundingCurve`. | The bond's own curve risk, which is typically much larger. | Note the following: - A `BondForward` rule using the `Discounting` model must include `BondForwardModelOptions` with `bondForwardProjectionType` set, otherwise LUSID rejects the recipe. Values are case-sensitive. `BondForward` isn't supported by `ConstantTimeValueOfMoney`. Under `SimpleStatic`, LUSID ignores these options and values from the contract's price quote. - The deliverable must be a mastered `Bond` or `ComplexBond` in the same currency as the forward. You must master the `BondForward` too and value it in a portfolio, rather than valuing it on its own. - LUSID looks up the forward contract's own price quote by its LUID, so you need a market data rule for `Quote.LusidInstrumentId.*`. - `DeliverableSpreadAnchoredToQuote` requires a `ZSpread` quote for the deliverable. A credit spread curve doesn't replace it. - Order the `Price` rule before the `Rate` rule for the `ZSpread` quote. If the `Rate` rule comes first, `ForwardProjectedFromFundingCurve` reads the `ZSpread` quote as the deliverable's price, and the valuation is wrong, with no error. ```json {  "supplier": "Lusid",  "modelName": "Discounting",  "instrumentType": "BondForward",  "modelOptions": {    "modelOptionsType": "BondForwardModelOptions",    "bondForwardProjectionType": "ForwardProjectedFromFundingCurve"  } } ``` ## `FlexibleLoanPricerOptions` Use this option to report a standalone loan or deposit at the interest accrued so far, rather than including a clean value. This is common practice for private credit. | **Field** | **Values** | **Default if** `modelOptions` **is omitted** | **Description** | | --- | --- | --- | --- | | `setCleanPVToZero` | `true`, `false` | `false` | Mandatory. Set to `true` to set the clean PV to zero, so `Valuation/PV` is the accrued interest only. Applies to `FlexibleLoan` and `FlexibleDeposit` instruments held on their own, not to loans within a loan facility. | For example, a 1,000,000 loan at 5% drawn on 1 January and valued on 1 July has a PV of 1,024,794.52 by default, and 24,794.52 (the accrued interest) with `setCleanPVToZero` set to `true`. ```json {  "supplier": "Lusid",  "modelName": "FlexibleLoanPricer",  "instrumentType": "FlexibleLoan",  "modelOptions": {    "modelOptionsType": "FlexibleLoanPricerOptions",    "setCleanPVToZero": true  } } ```