{"record":{"id":"63f9e3711fb56f15","repo":"nautechsystems/nautilus_trader","slug":"empty-order-book-no-liquidity-available-for-marke","errorCode":null,"errorMessage":"Empty order book: no liquidity available for market order","messagePattern":"Empty order book: no liquidity available for market order","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/execution/parse.rs","lineNumber":749,"sourceCode":"/// Sorts levels deterministically before walking:\n/// - BUY (asks): ascending by price, best (lowest) ask first\n/// - SELL (bids): descending by price, best (highest) bid first\n///\n/// This ensures correct results regardless of the CLOB API's response ordering.\n///\n/// For BUY: walks asks best-first, accumulates `size * price` (pUSD) until >= amount.\n///          Also accumulates the exact shares at each level for precise base qty.\n/// For SELL: walks bids best-first, accumulates `size` (shares) until >= amount.\n///\n/// Returns the crossing price and expected base quantity. If insufficient liquidity,\n/// uses all available levels. If the book side is empty, returns an error.\npub fn calculate_market_price(\n    book_levels: &[ClobBookLevel],\n    amount: Decimal,\n    side: PolymarketOrderSide,\n) -> anyhow::Result<MarketPriceResult> {\n    if book_levels.is_empty() {\n        anyhow::bail!(\"Empty order book: no liquidity available for market order\");\n    }\n\n    // Parse and sort levels deterministically so we never depend on API ordering.\n    // BUY: asks ascending (best/lowest first). SELL: bids descending (best/highest first).\n    anyhow::ensure!(amount > Decimal::ZERO, \"market amount must be positive\");\n    let mut parsed_levels = Vec::with_capacity(book_levels.len());\n    for level in book_levels {\n        let price = parse_decimal_exact(&level.price).context(\"invalid market-book price\")?;\n        let size = parse_decimal_exact(&level.size).context(\"invalid market-book size\")?;\n        anyhow::ensure!(\n            price > Decimal::ZERO && price < Decimal::ONE,\n            InvalidMarketPriceError(\"market-book price must be in (0, 1)\".to_string())\n        );\n        anyhow::ensure!(\n            size >= Decimal::ZERO,\n            \"market-book size must be non-negative\"\n        );\n","sourceCodeStart":731,"sourceCodeEnd":767,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/execution/parse.rs#L731-L767","documentation":"calculate_market_price walks an order book to price a market order; it rejects the request up front when book_levels is empty, because there is no liquidity at all from which to derive a fill price. This is a fail-fast guard before any level parsing or sorting.","triggerScenarios":"Calling calculate_market_price with an empty slice of ClobBookLevel — e.g. the CLOB API returned an empty book payload, the market just opened/closed, or a fetch bug returned no levels — for either Buy or Sell market orders.","commonSituations":"Polling a newly listed or nearly-closed market whose book has been cleared; an upstream API outage returning empty book snapshots; a symbol/token-id mix-up querying a book that has no levels.","solutions":["Check the book is non-empty before calling, and surface 'no liquidity' to the user instead of attempting the order.","Re-fetch the book — an empty snapshot may be transient; add a short retry with backoff.","Verify the correct asset_id/token_id is being used to fetch the book for the intended outcome.","Halt trading on that market if empty books persist; it may be delisted or paused."],"exampleFix":"// before\nlet mp = calculate_market_price(&book.levels, amount, side)?;\n// after\nif book.levels.is_empty() {\n    eprintln!(\"no liquidity for {symbol:?}; skipping market order\");\n    return Ok(None);\n}\nlet mp = calculate_market_price(&book.levels, amount, side)?;","handlingStrategy":"try-catch","validationCode":"if book_levels.is_empty() {\n    return Ok(None); // no liquidity — skip instead of erroring\n}","typeGuard":null,"tryCatchPattern":"match calculate_market_price(&book.levels, amount, side) {\n    Ok(mp) => mp,\n    Err(e) if e.to_string().contains(\"Empty order book\") => {\n        // no liquidity: back off and retry later\n        schedule_refetch();\n        return Ok(None);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Verify the book is non-empty right after fetching it","Retry empty snapshots with short backoff — they can be transient","Confirm the asset_id/token_id maps to an active market","Alert on persistently empty books; the market may be paused or delisted"],"tags":["polymarket","order-book","liquidity","market-order"],"backgroundTag":"empty-result-set","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"}