a
    ’>wj\  ã                   @   s¦   d Z ddlZddlZddlZddlZddlZddlmZ ddlm	Z	 ej
 dd¡ ej
 dd¡ ddlZe	dƒZe	dƒZd	Zd
d„ Zdd„ Zdd„ Zedkr¢eƒ  dS )aí  Which Pinnacle feed is more ACCURATE: pinnapi's live line or API-Football's relay?

WHY THIS TEST AND NOT THE OBVIOUS ONE. The instinctive test is "do pinnapi's
signals win more bets". Measured 2026-08-08, that needs ~3,100 scored signals --
about eight months -- because the signals the two feeds disagree on sit at ~0.11
implied, where per-bet ROI stdev is ~2.84 units.

This instead scores each feed's devigged fair value against the realised result
with a Brier score, PAIRED per fixture. Two properties make it ~50x cheaper:

  1. It uses EVERY fixture (~100-200 resolve daily), not just the ~13/day where
     the signals disagree.
  2. The feeds agree most of the time, so the paired DIFFERENCE has far less
     variance than either feed's raw accuracy. Measured stdev 0.1186, so ~580
     fixtures resolves a 0.01 effect -- roughly a week.

WHAT A POSITIVE RESULT DOES AND DOES NOT MEAN. `fresh_better > 0` means pinnapi's
line predicts outcomes better. It does NOT mean switching the feed makes money:
pinnapi shifts xlow's signals toward ~0.11 long shots, and the 2026-05-23 audit
found the rule bled there (hence EDGE_UPPER_CAP at 12%). A win here justifies
RECALIBRATING the band against the fresh line and re-testing -- not flipping the
live path, which stays on API-Football so the frozen forward test keeps running.

Results are cached in research/pin_accuracy_cache.json so repeated runs do not
re-query Kalshi for fixtures already settled.

Usage:  python research\pin_accuracy_test.py [--target N]
é    N)Údefaultdict)ÚPathzE:\soccer\mainzE:\soccer\researchz(E:\soccer\research\pin_fresh_capture.csvz*E:\soccer\research\pin_accuracy_cache.jsoniD  c              	   C   s(   z
t | ƒW S  ttfy"   Y d S 0 d S )N)ÚfloatÚ	TypeErrorÚ
ValueError©Úx© r	   ú'E:\soccer\research\pin_accuracy_test.pyÚ_f/   s    
r   c                   C   s0   zt  tjdd�¡W S  ty*   i  Y S 0 d S )Núutf-8©Úencoding)ÚjsonÚloadsÚCACHEÚ	read_textÚ	Exceptionr	   r	   r	   r
   Ú
load_cache6   s    r   c            #   
   C   sf  t } dtjv rDzttjtj d¡d  ƒ} W n ttfyB   Y n0 t ¡ sZt	dt› �ƒ‚i }t
tdd��n}t |¡D ]R}|d › d|d › d|d	 › d|d
 › �}||vsÀ|d || d krv|||< qvW d   ƒ n1 sÞ0    Y  tƒ }g ttƒd  }}}d }	}
| ¡ D �]0\}}t|d ƒt|d ƒ }}t|d ƒt|d ƒ }}d ||||fv �rf�q| |¡}|d u �r²| d¡\}}}}t ||||dœ¡\}}|�r²|||< |�sÄ|d7 }�qd|dk d|dk  }}|| d || d  }|| d || d  }|	|7 }	|
|7 }
| || ¡ ||d   || ¡ �qztjtj|dd�dd� W n t�yv   Y n0 t|ƒ}tdƒ td|› d| › d�ƒ td|› �ƒ |dk �rÂtdƒ d S t |¡}t  |¡�pÚd}|t! "|¡ }|�rø|| nd}td |	| d!›�ƒ td"|
| d!›�ƒ td#|d$›d%|d!›d&|d'›d�ƒ |d(|  |d(|   }}td)|d$›d*|d$›d+�ƒ tƒ  || k �rÀd(| t#t$|ƒd,ƒ d } td-| | › d.| d/›�ƒ n4t$|ƒd(k �rØtd0ƒ n|dk�rìtd1ƒ ntd2ƒ tƒ  td3ƒ t%| ¡ d4d5„ d6�d d7… D ]B\}!}"t|"ƒd8k�rtd9|!d:›d;t|"ƒd<›d=t |"¡d$›�ƒ �qd S )>Nz--targeté   zno capture at r   r   Úlcú|ÚhomeÚawayZ	game_dateZtsr   g        Zfair_fresh_hZfair_fresh_aZfair_stale_hZfair_stale_a)Zdivr   r   Údateg      ð?ÚHÚAé   )Úindentz7PINNACLE FEED ACCURACY -- paired Brier, lower is betterz  fixtures resolved : z   (target ú)z  still unresolved  : é
   z  too few to reportg•Ö&è.>z  mean Brier (pinnapi) : z.5fz  mean Brier (API-Ftbl): z  paired difference    : z+.5fz  (SE z, z z+.2fg\�Âõ(\ÿ?z  95% CI               : [z, ú]g-Cëâ6?z  NOT YET CONCLUSIVE -- z7 more fixtures to target; observed effect would need n=z,.0fz}  VERDICT: no significant accuracy difference at n>=target. The relay is good enough; staleness is not distorting fair value.zÄ  VERDICT: pinnapi is significantly MORE accurate. Next step is to RECALIBRATE the xlow band against the fresh line and re-test -- not to switch the live feed, which would break the frozen series.zE  VERDICT: pinnapi is significantly LESS accurate. Keep API-Football.z3  by league (paired difference, + favours pinnapi):c                 S   s   t | d ƒ S )Nr   )Úlenr   r	   r	   r
   Ú<lambda>‘   ó    zmain.<locals>.<lambda>)Úkeyé   é   z    Z6sz n=Z4dz  )&ÚTARGETÚsysÚargvÚintÚindexÚ
IndexErrorr   ÚSRCÚexistsÚ
SystemExitÚopenÚcsvZ
DictReaderr   r   ÚlistÚitemsr   ÚgetÚsplitÚDSZfetch_result_kalshiÚappendr   Z
write_textr   ÚdumpsÚOSErrorr"   ÚprintÚ
statisticsZmeanZpstdevÚmathZsqrtÚmaxÚabsÚsorted)#ÚtargetZlastZfhÚrÚkÚcacheZdiffsZby_lgZ
unresolvedZ	fresh_totZ	stale_totZfh_Zfa_Zsh_Zsa_Zftrr   r   r   ÚgdÚ_ZyhZyaZbfZbsÚnÚmZsdZseÚzÚloÚhiZneedZlgZdsr	   r	   r
   Úmain=   s˜    
*(

ÿ

"
ÿ



$rL   Ú__main__)Ú__doc__r2   r   r=   r<   r)   Úcollectionsr   Úpathlibr   ÚpathÚinsertZdaily_signalsr7   r.   r   r(   r   r   rL   Ú__name__r	   r	   r	   r
   Ú<module>   s$   Y