a
    +õijÎ  ã                   @   sŒ   d Z ddlZddlZddlmZ ddlZej dd¡ ddlZ	ddl
ZddlZddlZdZdd„ Zdd	„ Zd
d„ Zdd„ Zedkrˆeƒ  dS )ac  Cross-venue soccer coverage audit: Kalshi x Poly-US x Poly.com x API-Football.

WHY THIS EXISTS. On 2026-07-29 I made FOUR wrong "not covered" claims in one
session, every one of them a failed lookup rather than a real absence:

  1. "Kalshi has no Swiss match-winner series" -- I queried /series with
     limit=200; KXSWISSLEAGUEGAME was on a later page.
  2. "Poly-US has no Swiss coverage" -- I searched their catalogue for the string
     "swiss"; the league slug is `swsl`, and /v2/leagues returns the same 50 rows
     no matter what limit/offset you pass, so it is never in the response at all.
  3. "Poly-US has no Brazilian events" -- I passed the DIV code 'BSA' to
     league_events(), which wants the SLUG 'bra'. Got 0 and believed it.
  4. "API-Football has a 6-8% Pinnacle coverage tail" -- three of my four
     examples were POSTPONED fixtures, which have no line because they have no
     match.

The common failure: a name-based spot check returning empty, treated as evidence
of absence. The fix is to ENUMERATE each venue's own catalogue and cross-
reference, so "missing" means "absent from a full listing" rather than "my search
string did not match".

METHOD, and its deliberate paranoia:
  - Kalshi: page /series to exhaustion (cursor), keep every *GAME series, then
    count OPEN events per series. A series with no open events is listed but not
    currently tradeable, which is a different fact and reported separately.
  - Poly-US: /v2/leagues is UNRELIABLE (ignores paging), so instead probe each
    candidate slug directly via league_events(slug). Slug guesses come from our
    own map plus the observed pattern (e.g. `swsl`), and anything that returns
    events is real regardless of whether the catalogue admits it exists.
  - Poly.com: probe league tags the same way.
  - API-Football: search /leagues by country, since that is the axis it indexes
    on; a name search misses leagues whose name differs from ours.

NOTHING here is evidence of absence unless the venue returned a full listing.
Where a lookup fails, the output says UNKNOWN, not "no".

Usage:  python research\venue_coverage_audit.py [--full]
é    N)ÚdefaultdictzE:\soccer\mainzhttps://gateway.polymarket.usc               
   C   sÊ   i d } }dddœ}|r ||d< zt  d|¡}W n> tyn } z&td|› �ƒ W Y d}~qÆW Y d}~n
d}~0 0 | dg ¡}|D ].}t| d	d
¡ƒ}| d¡r€| dd
¡| |< q€| d¡}|rÆ|s
qÆq
| S )zAEvery *GAME series, paged to exhaustion. Returns {ticker: title}.NZSportséÈ   )ÚcategoryÚlimitÚcursorz/seriesz  [kalshi] series page failed: ÚseriesÚtickerÚ ZGAMEÚtitle)ÚktÚ_getÚ	ExceptionÚprintÚgetÚstrÚendswith)Úoutr   ÚpÚdÚeZbatchÚsÚt© r   ú*E:\soccer\research\venue_coverage_audit.pyÚkalshi_game_series6   s$    

"

r   c                 C   s@   z&t  d| dddœ¡}t| dg ¡ƒW S  ty:   Y d S 0 d S )Nz/eventsÚopenéd   )Zseries_tickerZstatusr   Zevents)r   r   Úlenr   r   )r   r   r   r   r   Úkalshi_open_eventsM   s
    r   c                 C   s.   zt t | ¡pg ƒW S  ty(   Y dS 0 dS )zAEvents for a Poly-US league slug. None = lookup failed (UNKNOWN).N)r   ÚPUSZleague_eventsr   )Zslugr   r   r   Úpolyus_probeU   s    r    c               
      sª  dt jv } tdƒ tƒ }tdt|ƒ› d�ƒ d}g }t| ¡ ƒD ]2\}‰ | sdt‡ fdd„|D ƒƒsdq@| |ˆ f¡ q@tddd	›d
dd›d�ƒ dd„ t	 
¡ D ƒ}|D ]b\}‰ t|ƒ}||v rÀdnd}|d u rÐdnt|ƒ}td|d	›d
|d›dˆ d d… d›d
|› �ƒ q¤tdƒ tdƒ ttjƒ}	ddi}
t|	 ¡ ƒt|
 ¡ ƒ D ]J\}}t|ƒ}|d u �r`dnt|ƒ}tdt|ƒd›d|d›d|› �ƒ �qBtdƒ tdƒ tdƒ d S )Nz--fulluA   KALSHI â€” every match-winner (*GAME) series, paged to exhaustionz  z *GAME series found
)ZleagueZligaZserieZpremierZsoccerZdivisionZ
eredivisieZ
bundesligaZ	superligaZekstraklasaZallsvenskanZeliteserienZuefaZcupZmlsZprimerac                 3   s   | ]}|ˆ   ¡ v V  qd S )N)Úlower)Ú.0Úh©r
   r   r   Ú	<genexpr>i   ó    zmain.<locals>.<genexpr>r   Z30sú zopen eventsz>11sz  titlec                 S   s   h | ]}t  |¡’qS r   )ÚmapsZleague_kalshi_series)r"   r   r   r   r   Ú	<setcomp>n   r&   zmain.<locals>.<setcomp>ZWIREDr	   ZUNKNOWNé(   Z40suE   
POLY-US â€” probing slugs directly (/v2/leagues ignores paging, so az(          catalogue miss proves nothing)zSWISS?ZswslZ8sz slug=z events=uI   
API-FOOTBALL â€” Pinnacle availability is the binding constraint for thezC               maker; a league with no fair value cannot be quoted.z8  (run with a country to check: /leagues?country=<name>))ÚsysÚargvr   r   r   ÚsortedÚitemsÚanyÚappendr(   Zall_divsr   r   Údictr   ZLEAGUE_SLUGÚlistr    )ZfullZksZSOCCER_HINTZrowsr   ZwiredÚnÚtagÚnsZslugsZextraZlabelr   r   r$   r   Úmain]   s8    
0
 &r6   Ú__main__)Ú__doc__Zjsonr+   Úcollectionsr   ZrequestsÚpathÚinsertZkalshi_traderr   Zpoly_us_pricesr   Zlive_monitorZLMr(   ZGATEWAYr   r   r    r6   Ú__name__r   r   r   r   Ú<module>   s    &&