From 8e331f9f34d89d97cadf4b9a0f1ea4e94188bd2f Mon Sep 17 00:00:00 2001 From: proerror Date: Fri, 17 Jul 2026 18:22:30 +0800 Subject: [PATCH] fix(polymarket): reject non-positive research strikes --- .../src/polymarket_research_select.rs | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/rust_hft/tools/collector/src/polymarket_research_select.rs b/rust_hft/tools/collector/src/polymarket_research_select.rs index 0e0adfdf9..a2b0769cd 100644 --- a/rust_hft/tools/collector/src/polymarket_research_select.rs +++ b/rust_hft/tools/collector/src/polymarket_research_select.rs @@ -210,6 +210,10 @@ fn discover( if up_token == down_token { bail!("line {line}: discovery has duplicate outcome tokens"); } + let price_to_beat = decimal_text(update.get("price_to_beat"), "price_to_beat")?; + if Decimal::from_str(&price_to_beat)? <= Decimal::ZERO { + bail!("line {line}: price_to_beat must be positive"); + } let contract = SelectedContract { market_id: market_id.clone(), symbol: symbol.to_owned(), @@ -217,7 +221,7 @@ fn discover( event_end, up_token, down_token, - price_to_beat: decimal_text(update.get("price_to_beat"), "price_to_beat")?, + price_to_beat, discovery_recorded_at: recorded_at.to_owned(), discovery_sequence: sequence, metadata: None, @@ -548,6 +552,56 @@ mod tests { .is_err()); } + #[test] + fn discovery_rejects_non_positive_price_to_beat() { + let temp = tempfile::tempdir().unwrap(); + let path = temp.path().join("market.ndjson"); + let rows = [ + json!({ + "sequence": 0, + "recorded_at": "2026-07-17T05:29:00Z", + "update": { + "kind": "event_discovered", + "window_secs": 300, + "symbol": "BTCUSDT", + "end_time": "2026-07-17T05:35:00Z", + "event_id": "btc-market", + "up_token": "btc-up", + "down_token": "btc-down", + "price_to_beat": "0" + } + }), + json!({ + "sequence": 1, + "recorded_at": "2026-07-17T05:29:01Z", + "update": { + "kind": "event_discovered", + "window_secs": 300, + "symbol": "SOLUSDT", + "end_time": "2026-07-17T05:35:00Z", + "event_id": "sol-market", + "up_token": "sol-up", + "down_token": "sol-down", + "price_to_beat": "100" + } + }), + ]; + let tape = rows + .iter() + .map(serde_json::to_string) + .collect::, _>>() + .unwrap() + .join("\n") + + "\n"; + std::fs::write(&path, tape).unwrap(); + let start = timestamp("2026-07-17T05:30:00Z", "start").unwrap(); + let error = match discover(&path, start, start + Duration::seconds(WINDOW_SECS)) { + Ok(_) => panic!("non-positive price_to_beat should fail"), + Err(error) => error, + }; + assert!(error.to_string().contains("price_to_beat must be positive")); + } + #[test] fn metadata_rejects_invalid_retrieved_at() { let event_start = timestamp("2026-07-17T05:30:00Z", "start").unwrap();