{"record":{"id":"b759478629d219e3","repo":"nautechsystems/nautilus_trader","slug":"polymarket-collateral-sized-limit-buy-price-must-b","errorCode":null,"errorMessage":"Polymarket collateral-sized limit BUY price must be positive","messagePattern":"Polymarket collateral-sized limit BUY price must be positive","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/execution/order_builder.rs","lineNumber":156,"sourceCode":"            neg_risk,\n        )\n    }\n\n    /// Builds and signs a collateral-sized limit BUY for submission.\n    ///\n    /// `amount` is the pUSD collateral to spend. The signed maker amount is the collateral after\n    /// venue-required cent quantization, and the taker amount is the share quantity derived from\n    /// that exact signed amount.\n    pub(crate) fn build_limit_order_from_collateral(\n        &self,\n        token_id: &str,\n        price: Decimal,\n        amount: Decimal,\n        expiration: &str,\n        neg_risk: bool,\n        tick_decimals: u32,\n    ) -> anyhow::Result<PolymarketOrder> {\n        anyhow::ensure!(\n            price > Decimal::ZERO,\n            \"Polymarket collateral-sized limit BUY price must be positive\"\n        );\n\n        let (maker_amount, taker_amount) =\n            compute_quote_buy_maker_taker_amounts(price, amount, tick_decimals);\n        anyhow::ensure!(\n            maker_amount > Decimal::ZERO,\n            \"Polymarket collateral-sized limit BUY amount {} pUSD truncates to zero at {LOT_SIZE_SCALE} decimal places\",\n            amount.normalize(),\n        );\n        anyhow::ensure!(\n            taker_amount > Decimal::ZERO,\n            \"Polymarket collateral-sized limit BUY derives a zero share quantity\"\n        );\n        anyhow::ensure!(\n            taker_amount * price == maker_amount,\n            \"Polymarket collateral-sized limit BUY amount {} pUSD cannot preserve limit price {} after venue quantization\",","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/execution/order_builder.rs#L138-L174","documentation":"`build_limit_order_from_collateral` builds a collateral-sized (quote-amount) limit BUY order for Polymarket. Polymarket CLOB orders are price*amount based, so a non-positive price would produce zero or negative maker/taker amounts. `anyhow::ensure!` rejects any price <= 0 with this message before computing order amounts.","triggerScenarios":"Submitting a market BUY order that internally converts to a limit order when the computed/last price is 0 (e.g. no market data available); passing price=0 or a negative Decimal directly through the order path; a bug or division-by-zero upstream yielding 0 price.","commonSituations":"Trading a thin/illiquid market where best bid/ask is missing so derived price is 0; instrument configured with wrong tick/price precision causing rounded-to-zero prices; feeding a strategy unvalidated prices before adapter submission.","solutions":["Ensure the order price is positive before submission; fetch/refresh market data so a real last/best price is available","Validate the instrument's price precision/tick_decimals config so prices don't round to zero","Guard the strategy to skip the order when no valid price exists","Check Decimal scale/rounding upstream that could reduce a small price to 0"],"exampleFix":"// before\nlet order = client.build_limit_order_from_collateral(\n    OrderSide::Buy, price_from_stale_feed, amount, ...)?;\n// after\nanyhow::ensure!(price_from_stale_feed > Decimal::ZERO, \"no valid price\");\nlet order = client.build_limit_order_from_collateral(\n    OrderSide::Buy, price_from_stale_feed, amount, ...)?;","handlingStrategy":"validation","validationCode":"use rust_decimal::Decimal;\nfn validate_buy_price(price: Decimal) -> Result<(), String> {\n    if price <= Decimal::ZERO { Err(format!(\"price must be positive, got {price}\")) } else { Ok(()) }\n}","typeGuard":null,"tryCatchPattern":"match adapter.submit_order(order).await {\n    Err(e) if e.to_string().contains(\"price must be positive\") => {\n        tracing::warn!(\"skipping order with invalid price\");\n    }\n    other => other?,\n}","preventionTips":["Validate price > 0 in the strategy before submitting orders","Keep market data fresh so derived prices never fall to zero","Check price precision/tick_decimals config to avoid rounding to zero"],"tags":["rust","order-builder","validation","polymarket"],"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-14T00:17:10.932Z"}