{"record":{"id":"9383e12d2b21778e","repo":"nautechsystems/nautilus_trader","slug":"invalid-betting-balance-impact","errorCode":null,"errorMessage":"invalid betting balance impact","messagePattern":"invalid betting balance impact","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/accounts/betting.rs","lineNumber":152,"sourceCode":"    /// For `Buy` (lay) the impact is the negative liability (quantity * (price - 1)).\n    ///\n    /// # Panics\n    ///\n    /// Panics if the impact cannot be represented in the quote currency.\n    #[must_use]\n    pub fn balance_impact(\n        &self,\n        instrument: &InstrumentAny,\n        quantity: Quantity,\n        price: Price,\n        order_side: OrderSide,\n    ) -> Money {\n        let currency = instrument.quote_currency();\n        let impact = match order_side {\n            OrderSide::Sell => -quantity.as_decimal(),\n            OrderSide::Buy => -(quantity.as_decimal() * (price.as_decimal() - Decimal::ONE)),\n        };\n        Money::from_decimal(impact, currency).expect(\"invalid betting balance impact\")\n    }\n\n    /// Recalculates the account balance for the specified currency based on per-instrument locks.\n    pub fn recalculate_balance(&mut self, currency: Currency) {\n        base::recalculate_balance(&mut self.base.balances, &self.balances_locked, currency);\n    }\n}\n\nimpl Account for BettingAccount {\n    impl_account_base_members!();\n\n    fn is_cash_account(&self) -> bool {\n        true\n    }\n\n    fn is_margin_account(&self) -> bool {\n        false\n    }","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/accounts/betting.rs#L134-L170","documentation":"This panic comes from an `.expect(\"invalid betting balance impact\")` in `balance_impact` for betting accounts (crates/model/src/accounts/betting.rs:152). The function computes a signed balance impact from order side, quantity, and price: Sell impacts the balance by -quantity, Buy by -(quantity * (price - 1)). The computed decimal is wrapped into a `Money` via `Money::from_decimal`, which fails (and thus panics) when the decimal cannot be represented as a valid Money amount in the instrument's quote currency (e.g. wrong precision or invalid value).","triggerScenarios":"Calling `balance_impact` (or the Python binding `py_balance_impact`) with a quantity/price whose computed impact decimal cannot be converted to a valid `Money` in the instrument's quote currency — e.g. a decimal with more precision than the currency allows, or a malformed/NaN-like decimal produced by extreme price values.","commonSituations":"Betting/exchange adapters computing margin or balance locks with prices carrying more decimal places than the quote currency's precision; custom account code calling `balance_impact` directly with hand-built `Price`/`Quantity` values that violate currency precision; a symbol whose quote currency precision was misconfigured.","solutions":["Round the computed price and quantity to the instrument's price/size precisions (and the currency's precision) before calling balance_impact.","Verify the instrument's quote_currency is correctly configured and its precision can represent the impact decimal.","Check the input Price/Quantity decimals for abnormal magnitude or precision (e.g. from bad feed data) before the call.","If you control the call site, use Money::from_decimal's Result form (or try_from) and handle the error instead of relying on the internal expect."],"exampleFix":"// before\nlet impact = balance_impact(OrderSide::Buy, &price, &quantity, &instrument);\n// after\nlet price = Price::new(raw_price, instrument.price_precision());\nlet quantity = Quantity::new(raw_qty, instrument.size_precision());\nlet impact = balance_impact(OrderSide::Buy, &price, &quantity, &instrument);","handlingStrategy":"validation","validationCode":"// rust\nfn balance_impact_inputs_ok(price: Price, quantity: Quantity, instrument: &Instrument) -> bool {\n    price.precision <= instrument.price_precision()\n        && quantity.precision <= instrument.size_precision()\n        && quantity.as_decimal() > Decimal::ZERO\n        && price.as_decimal() > Decimal::ZERO\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always round price/quantity to the instrument's declared precisions before computing money values.","Confirm the quote currency precision supports the computed impact decimal.","Sanitize market data before using it in balance calculations."],"tags":["rust","panic","money","precision","betting"],"backgroundTag":"internal-invariant-violation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}