{"record":{"id":"f7377c34c8ef1ae0","repo":"nautechsystems/nautilus_trader","slug":"closing-quantity-closing-qty-must-be-smaller-tha","errorCode":null,"errorMessage":"closing quantity {closing_qty} must be smaller than fill quantity {}","messagePattern":"closing quantity (.+?) must be smaller than fill quantity (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/events/order/filled.rs","lineNumber":169,"sourceCode":"    pub fn is_sell(&self) -> bool {\n        self.order_side == OrderSide::Sell\n    }\n\n    /// Splits an overfill into the fragment which closes the current position and the\n    /// fragment which opens the flipped position.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error when `closing_qty` is zero, is not smaller than the fill quantity,\n    /// or the proportional commission cannot be represented.\n    pub fn split_for_position_flip(\n        &self,\n        closing_qty: Quantity,\n        opening_position_id: Option<PositionId>,\n        opening_event_id: UUID4,\n    ) -> anyhow::Result<(Self, Self)> {\n        anyhow::ensure!(!closing_qty.is_zero(), \"closing quantity was zero\");\n        anyhow::ensure!(\n            closing_qty.raw < self.last_qty.raw,\n            \"closing quantity {closing_qty} must be smaller than fill quantity {}\",\n            self.last_qty,\n        );\n\n        let opening_qty =\n            Quantity::from_raw(self.last_qty.raw - closing_qty.raw, closing_qty.precision);\n        let closing_fraction = closing_qty.as_decimal() / self.last_qty.as_decimal();\n        let (closing_commission, opening_commission) = match self.commission {\n            Some(commission) => {\n                let closing = Money::from_decimal(\n                    commission.as_decimal() * closing_fraction,\n                    commission.currency,\n                )?;\n                (Some(closing), Some(commission - closing))\n            }\n            None => (None, None),\n        };","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/events/order/filled.rs#L151-L187","documentation":"Position::split_for_position_flip splits a fill into a closing order and an opening order when flipping a position. The closing quantity must be strictly smaller than the fill quantity (some of the fill must remain to open the new side); equal or larger values would leave an empty or inverted split, so the library rejects it via anyhow::ensure!.","triggerScenarios":"Calling split_for_position_flip with closing_qty equal to or greater than self.last_qty of the existing OrderFilled event. Reached indirectly via apply_orderless_flip_fill or flip_position when the flip quantity passed in does not leave a residual opening amount.","commonSituations":"Flattening a position exactly to zero with a flip helper (passing the full position size as closing qty), sizing a flip order from stale position data, or off-by-one/confusion between 'close all' and 'flip' semantics in strategy code.","solutions":["Pass a closing_qty strictly less than the fill quantity; if you want to close the position entirely, use a plain close/flatten path instead of split_for_position_flip.","Check position.qty (net exposure) before flipping and clamp closing_qty to min(position_qty, last_qty.raw - 1) in the instrument's size increment.","If the fill already equals the intended closing amount, treat the flip as a full close: submit the opposite-side order without the split helper."],"exampleFix":"// before\nlet (close_fill, open_fill) = filled\n    .split_for_position_flip(filled.last_qty, None, open_event_id)?;\n// after\nlet closing = Quantity::new(filled.last_qty.as_f64() - instrument.size_increment.as_f64(), filled.last_qty.precision);\nlet (close_fill, open_fill) = filled\n    .split_for_position_flip(closing, None, open_event_id)?;","handlingStrategy":"validation","validationCode":"if closing_qty.raw >= filled.last_qty.raw || closing_qty.is_zero() {\n    // fall back to full close instead of flip split\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always compare closing_qty against position/fill size before flipping","Use plain close paths when the intent is to fully flatten","Derive closing quantities from instrument size increments to avoid residual-zero splits"],"tags":["position","quantity","invalid-argument-value","rust"],"backgroundTag":"invalid-argument-value","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"}