{"record":{"id":"47bf31b07351f330","repo":"nautechsystems/nautilus_trader","slug":"price-must-be-positive-for-inverse-notional-valuat","errorCode":null,"errorMessage":"price must be positive for inverse notional valuation","messagePattern":"price must be positive for inverse notional valuation","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/instruments/mod.rs","lineNumber":712,"sourceCode":"            } else {\n                break;\n            }\n        }\n\n        prices\n    }\n}\n\npub(crate) fn try_notional_value(\n    quantity: Quantity,\n    price: Price,\n    multiplier: Quantity,\n    is_inverse: bool,\n    use_quote_for_inverse: bool,\n    currency: Currency,\n) -> anyhow::Result<Money> {\n    let amount = if is_inverse && !use_quote_for_inverse {\n        anyhow::ensure!(\n            price.is_positive(),\n            \"price must be positive for inverse notional valuation\"\n        );\n        quantity\n            .as_decimal()\n            .checked_mul(multiplier.as_decimal())\n            .and_then(|value| value.checked_div(price.as_decimal()))\n            .ok_or_else(|| anyhow::anyhow!(\"inverse notional calculation overflow\"))?\n    } else if is_inverse {\n        quantity.as_decimal()\n    } else {\n        quantity\n            .as_decimal()\n            .checked_mul(multiplier.as_decimal())\n            .and_then(|value| value.checked_mul(price.as_decimal()))\n            .ok_or_else(|| anyhow::anyhow!(\"notional calculation overflow\"))?\n    };\n","sourceCodeStart":694,"sourceCodeEnd":730,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/instruments/mod.rs#L694-L730","documentation":"In the inverse notional formula, quantity*multiplier is divided by the price; dividing by zero or a non-positive price is mathematically invalid, so try_notional_value ensures price.is_positive() before the division and raises this error otherwise.","triggerScenarios":"Calling try_calculate_notional_value (via calculate_notional_value's Result path) on an inverse instrument with use_quote_for_inverse=false and a price of zero or negative, typically a mid/last price computed as 0 from empty market data.","commonSituations":"Startup before any quotes arrive (price initialized to 0), a stale/zero last trade price in backtests, or a division-derived price that collapsed to zero.","solutions":["Guard price.is_positive() before computing inverse notional and skip/wait until a real price is available.","Use use_quote_for_inverse=true if quote-denominated notional is acceptable and avoids the division.","Fix the price source so zero/negative prices never reach valuation (e.g. reject zero ticks at ingestion)."],"exampleFix":"// before\nlet notional = instrument.calculate_notional_value(price, qty, None)?;\n// after\nif !price.is_positive() { return Ok(None); } // or wait for valid price\nlet notional = instrument.calculate_notional_value(price, qty, None)?;","handlingStrategy":"validation","validationCode":"if !price.is_positive() { return Ok(None); } // wait for a valid market price","typeGuard":null,"tryCatchPattern":"// Rust\nlet notional = instrument\n    .try_calculate_notional_value(price, qty, None)\n    .ok(); // None until a positive price exists","preventionTips":["Skip valuation until at least one positive quote/trade price exists","Reject zero/negative prices at data ingestion","Use the try_ notional API so a bad price degrades gracefully"],"tags":["notional","inverse-instrument","division-by-zero","price"],"backgroundTag":"argument-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}