--- title: "Changing recipe settings" slug: "recipes-changing-default-recipe-options" tags: ["zeropv", "zero pv"] updated: 2026-10-26T09:49:23Z published: 2026-10-26T09:49:23Z canonical: "support.lusid.com/recipes-changing-default-recipe-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. # Changing recipe settings A recipe has dozens of settings that fine-tune how LUSID finds market data, prices instruments and adds up the results, most of which default to sensible values out-of-the-box. Note that a recipe is a JSON document organised into four top-level objects: `market`, `pricing`, `aggregation` and `holding`: ```json {  "configurationRecipe": {    "scope": "MyRecipes",    "code": "ValuationRecipe",    "description": "A recipe for valuing multi-asset, multi-region portfolios",    "market": {},    "pricing": {},    "aggregation": {},    "holding": {}  } } ``` ## Market data The `market` object controls how LUSID [locates market data](/v1/docs/recipes-locating-market-data). | **Field** | **Default value** | **Explanation** | | --- | --- | --- | | `market.marketRules` `market.specificRules` `market.groupedMarketRules` | N/A | The market data rules that actually locate market data. [More information](/v1/docs/recipes-locating-market-data). | | `market.suppliers` | N/A | Legacy field. Do not set. | | `market.options.defaultScope` | `default` if you leave out `market.options` altogether; no value if you supply `market.options` without it | When set, LUSID adds a catch-all market data rule for each asset type (for example `Quote.LusidInstrumentId.*` and `Fx.*.*`), pointing at the supplied scope. It tries these rules last, after all of your own rules. If a valuation error names a rule you didn't write, it is one of these catch-all rules, and it means none of your own rules found the data. The catch-all rules look for data on the valuation date only. The catch-all FX rule looks for FX rates stored with a quote type of `Price`, not `Rate`. Catch-all rules match a wide range of data and can be slow. We recommend writing explicit market data rules for the data you need. Either set `defaultScope` on purpose as a safety net, or leave it out. Without it, an error tells you which rule to add, for example `Suggest adding a market data key rule with key Fx.GBP.USD`. Note that supplying `"options": {}` creates no catch-all rules, but leaving out `options` altogether creates them in the `default` scope. | | `market.options.defaultSupplier` | `Lusid` | The supplier used by the catch-all rules. It has no effect on your own rules, which each name their own supplier, or when there is no `defaultScope`. | | `market.options.defaultInstrumentCodeType` | `LusidInstrumentId` | The instrument identifier used by the catch-all rules. For example, if your prices are stored against FIGIs, set this to `Figi`. Otherwise the catch-all rule doesn't find them. Allowed values: `LusidInstrumentId`, `Figi`, `RIC`, `QuotePermId`, `Isin`, `CurrencyPair`, `ClientInternal`, `Cusip`, `Sedol`. | | `market.options.attemptToInferMissingFx` | `false` | Set to `true` to infer missing [FX rates](/v1/docs/how-do-i-load-fx-spot-rates-into-the-quote-store). For example, if a `AUDJPY` rate is required for a valuation but cannot be located in the Quote Store, then: 1. If a `JPYAUD` rate is located, LUSID returns the inverse: `1/JPYAUD`. 2. LUSID triangulates through USD, then GBP, then EUR. It tries USD for every missing rate first, and only tries GBP and then EUR for rates it still can't find. So for example if `USDAUD` and `USDJPY` are located, LUSID returns `USDJPY/USDAUD`. An inferred rate takes the earlier effective date of the two rates it was built from, so one stale rate makes the result stale too. LUSID also infers missing FX forward curves in the same way. LUSID looks up more quotes when this is enabled, so valuations can be slightly slower. See [this article](/v1/docs/modelling-fxforwards-in-lusid) and [this Jupyter Notebook](https://github.com/finbourne/sample-notebooks/blob/master/analytics/FX/fx-inference-triangulation.ipynb). This does not apply to FX fixings for NDFs; use `attemptToInferMissingFxOnFixings` instead (below). | | `market.options.attemptToInferMissingFxOnFixings` | `false` | Set to `true` to apply the same inference (above) to FX fixings, for example the fixing of a [non-deliverable FX forward](/v1/docs/modelling-fxforwards-in-lusid#appendix-modelling-a-ndf). LUSID infers the rate on the fixing date. This is disabled by default because a fixing is a contractual historical rate: without it, LUSID uses a fixing only if it finds the exact currency pair in the right direction. This setting works entirely independently of `attemptToInferMissingFx`. | | `market.options.calendarScope` | `CoppClarkHolidayCalendars` | The scope of the [holiday calendars](/v1/docs/using-calendars-in-lusid) LUSID uses. LUSID looks for every calendar code in this one scope: instrument schedules, flow conventions, curves and business-day valuation schedules. Set it if you maintain your own calendars in your own scope. **Caution:** if LUSID can't find a calendar code that an instrument uses, it uses a weekends-only calendar instead, with no error. If schedule dates look one business day out, check this first. | | `market.options.conventionScope` | `Conventions` | The scope of the [flow conventions and index conventions](/v1/docs/flow-conventions-and-index-conventions) that instruments refer to by name. If a convention isn't found, the valuation fails with `Could not find FlowConventions with code ...`. | | `market.options.pricingBasis` *JSON only* | `Mid` | Set to `Bid` or `Ask` to value on that side of the price quote, for example for a bid-struck or swing-priced NAV. Every instrument price rule then reads the `bid` or `ask` field, whatever field the rule names. You don't need to duplicate your rules. FX, curve, spread, rate and volatility rules are never affected. `Mid` doesn't force mid prices: each rule reads the field it names. To show several sides of the quote side by side, use the `PricingBasis` [metric option](/v1/docs/setting-options-on-metrics#available-options) instead. If your bid and ask prices are stored somewhere different from your mid prices, you can add separate `bidMarketRules` and `offerMarketRules` to `market`. Set `field` on each of those rules, because a rule without `field` reads the mid price. When a NAV is struck on `Bid` or `Ask`, LUSID refuses portfolios that hold short positions. | ## Pricing The `pricing` object determines the [pricing models](/v1/docs/recipes-changing-the-default-pricing-models-for-instrument-types) used by instrument types to calculate PV and other metrics. | **Top-level field** | **Default value** | **Explanation** | | --- | --- | --- | | `pricing.modelRules` | N/A | The vendor model rules that change the default pricing models for all instrument types other than `Equity`, and also set options for those pricing models that fine-tune calculations. [More information](/v1/docs/recipes-changing-the-default-pricing-models-for-instrument-types). | | `pricing.modelChoice` | Legacy field. Do not set. Use `pricing.modelRules` to explicitly set pricing models for instrument types. | | `pricing.options` | See the tables in the rest of this section below. | | `pricing.resultDataRules` | The result data rules that locate external valuation results held in the [Structured Result Store](/v1/docs/what-is-structured-result-data). | | `pricing.holdingPricingInfo` | Despite being located in the `pricing` object, this configures how market data rules in the `market` object fall back to using holding-level pricing data rather than market prices held in the Quote Store. [More information](/v1/docs/recipes-locating-market-data#overriding-market-prices-or-falling-back-to-holding-pricing-data). | ### Configuring pricing models | **Field** | **Default value** | **Explanation** | | --- | --- | --- | | `pricing.options.modelSelection` | `{"library": "Lusid", "model": "SimpleStatic"}` | Legacy field. Do not change. Use `pricing.modelRules` to explicitly set a pricing model for each instrument type. | | `pricing.options.useInstrumentTypeToDeterminePricer` | `false` | Legacy field. Do not change. Use `pricing.modelRules` to explicitly set a pricing model for each instrument type. | | `pricing.options.allowAnyInstrumentsWithSecUidToPriceOffLookup` | `false` | Legacy field. Do not change. | | `pricing.options.enableUseOfCachedUnitResults` | `false` | Legacy field. Do not change. | | `pricing.options.allowFallbackOnModelDecline` *JSON only* | `false` | Under development. Contact technical support for more information. | ### Handling failures, matured and forward-starting instruments | **Field** | **Default value** | **Explanation** | | --- | --- | --- | | `pricing.options.allowPartiallySuccessfulEvaluation` | `false` | Set to `true` so that one failure doesn't fail the whole valuation. Holdings that fail show an error in their PV, exposure and accrued cells instead of a number; the `Valuation/ModelError` [metric](/v1/docs/what-is-a-metric) explains why. Server errors still fail the request. In a cash flow query, an instrument that fails is reported as a placeholder row. **Caution:** In a lookthrough valuation, a constituent that fails counts as zero, so the remaining constituents are weighted more heavily (LUSID adds a warning to each row). Keep disabled for reconciliations, cash flow extracts and lookthrough valuations. See [Troubleshooting valuation](/v1/docs/troubleshooting-valuation-errors). | | `pricing.options.returnZeroPv` | `{"instrumentMatured": false}` | Set to `{"instrumentMatured": true}` to value an instrument after its last payment date with a PV and exposure of zero, instead of returning an error. LUSID still attaches the reason (the instrument has matured) so you can see why the value is zero. Note credit default swaps are never treated as matured. See [Troubleshooting valuation](/v1/docs/troubleshooting-valuation-errors). | | `pricing.options.windowValuationOnInstrumentStartEnd` | `false` | Set to `true` to value an instrument at zero, with no error, before its start date and from its maturity date onwards. LUSID returns only the PV, needs no market data for these instruments, and leaves other metrics blank. Cash flow queries are not affected. | | `pricing.options.removeContingentCashflowsInPaymentDiary` | `false` | Legacy field. Do not change. | The two zero-PV settings behave differently: | | `returnZeroPv.instrumentMatured` | `windowValuationOnInstrumentStartEnd` | | --- | --- | --- | | Before the start date (forward-starting instruments) | Priced as normal | Zero | | On the maturity date | Priced as normal | Zero | | After the last payment date | Zero PV and exposure, with an error explaining why | Zero PV only, with no error | | If both are set | | Takes priority | ### Legs and units | **Field** | **Default value** | **Explanation** | | --- | --- | --- | | `pricing.options.produceSeparateResultForLinearOtcLegs` | `false` | Set to `true` to report each [leg of an instrument](/v1/docs/how-does-lusid-handle-instrument-legs) such as an interest rate swap, FX forward, FX swap or equity swap as a separate row. Each row populates the `Valuation/LegIdentifier` and `Valuation/LegIndex` metrics An option premium is also reported as its own row. When enabled, metrics using the `DateTimeAgo` or benchmark [metric options](/v1/docs/setting-options-on-metrics#available-options) fail for holdings that produce more than one row. An `FxForward` priced with `SimpleStatic` also fails; see [Modelling FxForwards in LUSID](/v1/docs/modelling-fxforwards-in-lusid#valuing-your-position). | | `pricing.options.fxForwardContractsAsUnitsInBothLegs` | `false` | Applies to FxForwards booked as instruments and valued with `produceSeparateResultForLinearOtcLegs` set to `true`. By default, `Holding/Units` on the foreign leg is the number of contracts multiplied by the ratio of the foreign to domestic amount. Set to `true` to report the number of contracts on both legs, so that `Holding/Units` × `Valuation/InstrumentPV` = `Valuation/PV` on each leg. | ### Prices, currencies and accrued interest | **Field** | **Default value** | **Explanation** | | --- | --- | --- | | `pricing.options.validateDomesticAndQuoteCurrenciesAreConsistent` | `false` | Set to `true` to check that a price quote's currency matches the instrument's domestic currency when a model prices the instrument from a quote (for example `SimpleStatic` or `BondLookupPricer`). If the currencies don't match, the valuation fails with an error. When `false`, LUSID uses a quote in the wrong currency as it is, without converting it. Prices in a minor currency unit, such as `GBp` for a GBP instrument, are rescaled either way. We recommend setting this to `true`. | | `pricing.options.useInstrumentScaleFactorAsDefault` | `false` | Set to `true` to use a factor specified at the instrument level to [scale market prices](/v1/docs/scaling-a-market-price) loaded into the LUSID Quote Store. LUSID uses the instrument's factor only when the quote has no scale factor of its own. It doesn't apply to cash flow queries or instrument events. | | `pricing.options.fundingCurveByCurrency` *JSON only* | None (LUSID discounts each currency on `<CCY>OIS`) | Names the [discount curve](/v1/docs/categories-of-complex-market-data) for each currency, for example `{"GBP": "GBPOIS-USDCOLL"}` for a collateral curve. The discount curve key then becomes `Rates.GBP.GBPOIS-USDCOLL`, and rates risk is reported against that curve. Projection curves are not affected. Keep `OIS` in every discount curve name. LUSID doesn't check that the curve exists when you save the recipe. For an example, see [this article](/v1/docs/modelling-interest-rate-swaps-in-lusid#valuing-your-position). | | `pricing.accrualDefinition` (in `pricing`, not `pricing.options`) | `SOD` | Set to `EOD` to include the valuation day in LUSID's [accrued interest calculation](/v1/docs/how-does-lusid-calculate-accrued-interest). The allowed values are `SOD` and `EOD`. LUSID doesn't check the value when you save the recipe. Any other value makes every valuation that calculates accrued interest fail. Credit default swaps and CDS indices always report end-of-day accrued interest. | ### Bonds, asset-backed securities and loans | **Field** | **Default value** | **Explanation** | | --- | --- | --- | | `pricing.options.fixedIncomeValuationsUsingCurrentFace` *JSON only* | `false` | Set to `true` to scale results for `Bond`, `ComplexBond` and `InflationLinkedBond` holdings by the holding's current face, instead of its units. The [PV calculation](/v1/docs/how-does-lusid-calculate-pv) changes only for holdings where you have booked a current face. note PIK bonds always use current face. It doesn't apply to asset-backed bonds, which use `mbsValuationUsingHoldingCurrentFace` (see below). | | `pricing.options.mbsValuationUsingHoldingCurrentFace` | `false` | Set to `true` to value asset-backed `ComplexBond` holdings using a pool factor worked out from the holding's current face, instead of a pool factor from the Quote Store. A holding with no current face is valued at a pool factor of 1. Valuations of large portfolios can be slower with this enabled. | | `pricing.options.defaultPoolFactorsToUnity` *JSON only* | `false` | Set to `true` to treat a missing pool factor for an asset-backed bond valued using the `BondLookupPricer` pricingmodel as 1 (the full original face), for example for a newly issued security before its first factor is published. It has no effect under `ConstantTimeValueOfMoney`. When `false` and LUSID cannot find a pool factor, the holding fails to value; LUSID never uses zero. LUSID looks for the pool factor on the bond's most recent payment date, using the `quoteInterval` of your pool factor rule. | | `pricing.options.suppressAutomaticLoanPrincipalRepayment` *JSON only* | `false` | Set to `true` to stop LUSID generating a `LoanPrincipalRepaymentEvent` at the end of the schedule for `FlexibleLoan` contracts held on a `LoanFacility`. You must then book rollovers or repayment events yourself. Otherwise the contract stays open and may fail to value once it has matured. Stand-alone loans, loans on a `WholeLoanFacility`, interest repayments and repayment events you load yourself are not affected. Set this on the recipe the [portfolio uses for instrument events](/v1/docs/setting-a-portfolio-recipe); setting it on a recipe used purely for valuation has no effect. | ### Structured result data | **Field** | **Default value** | **Explanation** | | --- | --- | --- | | `pricing.options.convertSrsCashFlowsToPortfolioCurrency` | `false` | Set to `true` to convert cash flows you have loaded into the [Structured Result Store](/v1/docs/what-is-structured-result-data) to portfolio currency in [cash flow queries](/v1/docs/how-do-i-query-cash-flows). LUSID uses the spot rate on each cash flow's payment date, so you need FX rates for those dates. If a rate is missing, that instrument's cash flows fail. Cash flows that LUSID calculates itself are not affected. | | `pricing.options.enableLegLevelInferenceForCustomSrsColumns` | `false` | Set to `true` to fill in missing `UnitResult/*` values between an instrument and its legs: - An instrument's value is the sum of its legs' values, and a missing leg counts as zero. - A missing leg's value is the instrument's value less the legs you supplied, split evenly between the missing legs. Values you supply always take priority. | | `pricing.options.scaleInstrumentAccruedOverrideByContractSize` | `false` | By default, LUSID treats a `Valuation/InstrumentAccrued` value from the Structured Result Store as the accrued interest for one unit. Set to `true` to multiply it by the instrument's contract size instead, which was LUSID's earlier behaviour. | ### Risk For more on how LUSID calculates risk, see [How does LUSID assess risk?](/v1/docs/how-does-lusid-assess-risk) | **Field** | **Default value** | **Explanation** | | --- | --- | --- | | `pricing.options.riskEngine` | `Bump` | Set to `Adjoint` to calculate rates deltas analytically where LUSID can. Currently this is for FX forwards and interest rate swaps priced with `Discounting`. Everything else is still calculated by bumping curves. `Parity` calculates both: LUSID reports the bumped number and fails the measure if the two disagree. | | `pricing.options.riskBumpOptions` *JSON only* | None (see below) | Sets the size of the bumps LUSID uses to calculate risk. | | `pricing.options.inflationConvexity` *JSON only* | None (no correction) | Applies a Jarrow-Yildirim convexity correction to projected inflation index values. It affects only the `InflationForward` model, which LUSID uses for risk and scenario analysis, not for book PV. It makes no difference where the instrument's observation lag matches the curve's. You must supply all four parameters: `nominalIndexCorrelation` (between -1 and 1), `indexVolatility`, `nominalVolatility` and `nominalMeanReversion` (each greater than zero, as decimals). LUSID checks them when you save the recipe. | | `pricing.options.findOrCalculate` and `pricing.options.findOrCalculateWriteThrough` | `Off` and `false` | Leave these at their defaults unless FINBOURNE advises otherwise. | #### Changing risk bump sizes Every member of `riskBumpOptions` is optional. Any member you leave out keeps its default. | **Member** | **Default value** | **Explanation** | | --- | --- | --- | | `deltaShift` | `0.0001` (1bp) | The bump size for delta and gamma measures. | | `resultSensitivity` | `0.0001` (1bp) | The move LUSID reports results per. For example, set to `0.01` to report risk per 1% move. Changing `deltaShift` changes how LUSID estimates the result, not the unit it reports in. | | `deltaShiftOverrides` | None | A bump size for a particular asset type, for example `{"Credit": 0.001}`. Keys are asset types, such as `Rates`, `Credit`, `Fx` and `IrVol`. For `Fx`, the bump is an absolute move in the quoted rate, so `0.001` is 10 pips. | | `ladderShiftOverrides` | FX: ±0.5%, ±1%, ±5%, ±10%. Everything else: ±50bp, ±100bp, ±250bp, ±500bp. Both include 0. | The bumps used by ladder measures (for example `Risk/Rates/Difference/Ladder`), by asset type. Each list must be in increasing order. | | `parityRelativeTolerance` | `0.001` | How far apart the two numbers may be when `riskEngine` is `Parity`. | > Ladder measures are currently reported correctly only when `deltaShift` and `resultSensitivity` are at their defaults and there is no `deltaShiftOverrides` entry for the ladder's asset type. Otherwise each rung is scaled by `resultSensitivity` ÷ the bump size. For example, `"deltaShiftOverrides": {"Fx": 0.001}` makes every FX ladder rung one tenth of its true value. If you need ladders, change only `ladderShiftOverrides`. For example: ```json "riskBumpOptions": {  "deltaShiftOverrides": { "Credit": 0.001 },  "ladderShiftOverrides": { "Rates": [-0.02, -0.01, 0, 0.01, 0.02] } } ``` LUSID bumps credit curves by 10bp for credit delta and gamma, and sets a ±100bp/±200bp grid for the rates ladder. The rates ladder is reported correctly, because there is no `Rates` entry in `deltaShiftOverrides`. ### Named prices | **Field** | **Default value** | **Explanation** | | --- | --- | --- | | `pricing.options.namedPrices` *JSON only* | None | Defines names you can use to request a particular kind of price in one column. Each name combines a side of the quote with an optional notional dealing cost. See below. | For example, a fund might define a creation price, a cancellation price and a plain mid price: ```json "namedPrices": [  { "name": "creation", "base": "Offer", "ndc": "AddBuy" },  { "name": "cancellation", "base": "Bid", "ndc": "SubtractSell" },  { "name": "perfRef", "base": "Mid" } ] ``` - `name` must start with a letter and contain only letters and digits. A recipe can have up to 32 names. - `base` is `Bid`, `Mid` or `Offer`. `Mid` reads each price rule's own field, as an ordinary valuation does; it doesn't average bid and offer. - `ndc` is `None` (the default), `AddBuy` or `SubtractSell`. LUSID always calculates the buy cost from the offer-side value and the sell cost from the bid-side value. For `AddBuy` or `SubtractSell`, the valuation needs a notional dealing cost table, either on the request (`notionalDealingCostTableId`) or on the fund's NAV type. To request a named price, add a `NamedPrice` option to a `Valuation/PV`, `Valuation/PvInReportCcy` or `Valuation/PvInPortfolioCcy` metric. Spell the name exactly as it is defined, including capitals: ```json { "key": "Valuation/PV", "op": "Value", "options": { "NamedPrice": "creation" } } ``` You can't combine `NamedPrice` with the `PricingBasis`, `Ndc` or scenario options on the same metric. Request them as separate metrics instead. See [Setting options on metrics](/v1/docs/setting-options-on-metrics). ### Lookthrough portfolios For more on what look lookthrough means in LUSID, see [Setting up and valuing a 'fund of funds' portfolio](/v1/docs/setting-up-and-valuing-a-fund-of-funds-portfolio). | **Field** | **Default value** | **Explanation** | | --- | --- | --- | | `pricing.options.conservedQuantityForLookthroughExpansion` | `PV` | Which quantity LUSID keeps the same when it expands a holding into its lookthrough constituents: `PV` or `Exposure`. | | `pricing.options.useChildSubHoldingKeysForPortfolioExpansion` | `false` | By default, each lookthrough constituent takes the [sub-holding key](/v1/docs/what-is-a-sub-holding-key-shk) values of the parent holding. Set to `true` to keep each constituent's own sub-holding keys from the child portfolio instead. | ## Aggregation Aggregation is the process of deciding which of the many [metrics](/v1/docs/what-is-a-metric) LUSID can calculate to include in your valuation report, and how to group and add them up. Metrics themselves are not specified in a recipe but rather in a call to the [GetValuation](https://www.lusid.com/docs/api#operation/GetValuation) API. However, aggregation settings *are* stored in a recipe. | **Field** | **Default value** | **Explanation** | | --- | --- | --- | | `aggregation.options.useAnsiLikeSyntax` | `false` | Controls how strictly LUSID checks a grouped report. By default, if you request a metric with `"op": "Value"` that isn't in the group-by and has different values within a group, LUSID leaves that cell blank. Set to `true` to reject any grouped request where a metric with `"op": "Value"` isn't in the group-by, whatever its values, with the error `ANSI mode enabled. Found unexpected columns`. **Note:** Currently enabling this setting rejects every grouped request, even one containing only group-by keys and aggregates, because of a column LUSID adds internally (`Lookthrough/ScalingWarning`). We recommend leaving it disabled for now. | | `aggregation.options.allowPartialEntitlementSuccess` | `false` | Applies when you value a [portfolio group](/v1/docs/what-is-a-portfolio-group) and aren't entitled to view some of its portfolios. Set to `true` to value the portfolios you can see, instead of failing the request. The results don't show which portfolios were left out. LUSID ignores this setting when you request group totals or collateral roll-ups, because those would be wrong. | | `aggregation.options.applyIso4217Rounding` | `false` | Set to `true` to round metrics that report currency values to the ISO 4217 standard number of decimal places. LUSID rounds halves away from zero, so JPY 1000.5 becomes 1001. LUSID rounds each holding before adding them up, so totals are sums of rounded values. For example, two holdings each worth GBP 10.125 total 20.26, not 20.25. Per-unit, instrument-level metrics such as `Valuation/InstrumentPV` are never rounded. [More information on rounding](/v1/docs/how-does-lusid-handle-rounding-conventions). | ## Holdings | **Field** | **Default value** | **Explanation** | | --- | --- | --- | | `holding.taxLotLevelHoldings` | `true` | By default, LUSID values each [tax lot](/v1/docs/what-are-taxlots) separately and populates `Holding/TaxLotId`, so an ungrouped report can have several rows per holding. Grouped totals are the same either way. Set to `false` for one row per holding, which is faster and easier to reconcile with your holdings. If the recipe changes during a date range you value, LUSID uses the value at the latest date for the whole range. |