diff --git a/tests/test_polymarket.py b/tests/test_polymarket.py index 5d06a7563..f83e2ac07 100644 --- a/tests/test_polymarket.py +++ b/tests/test_polymarket.py @@ -78,6 +78,19 @@ class PolymarketFormatTests(unittest.TestCase): self.assertIn("resolves 2030-12-31", out) self.assertIn("1-week -4.5pp", out) # -0.045 -> -4.5pp + def test_a_long_shot_is_not_shown_as_impossible_or_certain(self): + search = {"events": [{"markets": [ + _market("Long shot?", 0.003, volume=2_000, end_date="2030-12-31T00:00:00Z"), + _market("Near certain?", 0.997, volume=1_000, end_date="2030-12-31T00:00:00Z"), + _market("Tick from zero?", 0.0005, volume=900, end_date="2030-12-31T00:00:00Z"), + _market("Tick from one?", 0.9995, volume=800, end_date="2030-12-31T00:00:00Z"), + _market("All but settled?", 0.9999999, volume=700, end_date="2030-12-31T00:00:00Z"), + ]}]} + with mock.patch.object(polymarket, "_request", return_value=search): + out = polymarket.get_prediction_markets("anything", limit=10) + for odds in ("Yes 0.3%", "Yes 99.7%", "Yes 0.05%", "Yes 99.95%", "Yes 99.99999%"): + self.assertIn(odds, out) + def test_weekly_change_omitted_when_absent(self): # "Open small?" has wk=None -> no 1-week clause on its line. with mock.patch.object(polymarket, "_request", return_value=_SEARCH): diff --git a/tradingagents/dataflows/vendors/polymarket.py b/tradingagents/dataflows/vendors/polymarket.py index 69e27e6ff..b6aa4e9da 100644 --- a/tradingagents/dataflows/vendors/polymarket.py +++ b/tradingagents/dataflows/vendors/polymarket.py @@ -11,6 +11,7 @@ outcomes (a "Yes" at 0.76 means the market prices a 76% chance). """ import json import logging +import math from datetime import UTC, datetime import requests @@ -67,6 +68,21 @@ def _is_forward_looking(market: dict, now: datetime) -> bool: ) +def _odds(prob: float) -> str: + """A probability as a percentage; within 1% of 0 or 100 its distance from + there keeps two significant digits, so 0.05% is not 0% and 99.95% not 100%.""" + def decimals(distance: float) -> int: + return 1 - math.floor(math.log10(distance)) + + if 0 < prob < 0.01: + percent = prob * 100 + return f"{percent:.{decimals(percent)}f}".rstrip("0").rstrip(".") + "%" + if 0.99 < prob < 1: + distance = (1 - prob) * 100 + return f"{100 - distance:.{decimals(distance)}f}".rstrip("0").rstrip(".") + "%" + return f"{prob:.0%}" + + def get_prediction_markets(topic: str, limit: int | None = None, as_of_date: str | None = None) -> str: """Return live prediction-market probabilities for an event topic. @@ -142,7 +158,7 @@ def get_prediction_markets(topic: str, limit: int | None = None, as_of_date: str else "" ) lines.append( - f"- **{m.get('question')}** — {label} {prob:.0%} " + f"- **{m.get('question')}** — {label} {_odds(prob)} " f"(${volume:,.0f} volume, resolves {end_date}{wk_str})" )