a
    ãij+  ã                   @   sª   d 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ddlZdZdZd	d
„ Zdd„ Zdd„ Zdd„ Zdd„ Zedkr¦eƒ  dS )a'  Is API-Football's "Pinnacle" actually Pinnacle -- and how far behind is it?

We have an INDEPENDENT Pinnacle reference sitting on disk: football-data.co.uk
publishes Pinnacle opening (PSH/PSD/PSA) and CLOSING (PSCH/PSCD/PSCA) odds for
every match. Our live pipeline reads a different source entirely: API-Football's
`/odds` endpoint, bookmaker id 4, labelled "Pinnacle". The two have never been
compared.

TWO QUESTIONS, and they are separable:

  1. IS IT REALLY PINNACLE? If API-Football's line is a genuine Pinnacle feed,
     its last pre-kickoff quote should sit close to Pinnacle's published CLOSE.
     A large systematic gap would mean the label is wrong -- that we have been
     computing "CLV vs Pinnacle" against something else entirely, which would
     undermine every result in this project that references Pinnacle.

  2. WHAT DOES THE STALENESS COST? We measured API-Football's line changing only
     every ~5.8h ([[project-pin-line-staleness]]). Even if the source is genuine,
     a slow relay means our last pre-kickoff read is an OLD Pinnacle price. This
     measures, in cents, how far it lands from the real close -- which is the
     error sitting inside every CLV number we compute.

Question 1 is answered by the shape of the distribution (centred and tight =
genuine), question 2 by its width. A biased centre would indicate a different
book; a wide but unbiased spread indicates lag.

Comparison is on DEVIGGED probabilities so bookmaker margin differences cannot
masquerade as price differences.

Usage:  python research\af_vs_real_pinnacle.py
é    N)Údefaultdict)ÚdatetimezE:\soccer\mainzE:\soccer\researchzE:\soccer\live_data\*.csvzE:\soccer\league_data\*.csvc              	   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\af_vs_real_pinnacle.pyÚ_f0   s    
r
   c                    s(   dd„ | D ƒ}t |ƒ‰ ‡ fdd„|D ƒS )Nc                 S   s   g | ]}d | ‘qS )g      ð?r   ©Ú.0r   r   r   r	   Ú
<listcomp>8   ó    zdevig.<locals>.<listcomp>c                    s   g | ]}|ˆ  ‘qS r   r   r   ©Úsr   r	   r   :   r   )Úsum)ÚoÚrr   r   r	   Údevig7   s    r   c            	         sj  i } t   t¡D �]T}�z4t|dddd���}t |¡D ]ð‰ ‡ fdd„dD ƒ}‡ fdd„d	D ƒ}t|ƒr6td
d„ |D ƒƒszq6ˆ  d¡p†d ¡ }d}dD ]2}zt 	||¡ 
¡ }W  qÈW q” tyÄ   Y q”0 q”|sÎq6|t ˆ  d¡¡t ˆ  d¡¡f}t|ƒ�rtdd„ |D ƒƒ�rt|ƒndt|ƒf| |< q6W d  ƒ n1 �s>0    Y  W q t�yb   Y qY q0 q| S )z6(date, home_fd, away_fd) -> (open_probs, close_probs).Ú úutf-8Úreplace©ÚnewlineÚencodingÚerrorsc                    s   g | ]}t ˆ  |¡ƒ‘qS r   ©r
   Úget©r   Úc©r   r   r	   r   D   r   zload_fd.<locals>.<listcomp>)ZPSHZPSDZPSAc                    s   g | ]}t ˆ  |¡ƒ‘qS r   r   r   r    r   r	   r   E   r   )ZPSCHZPSCDZPSCAc                 s   s   | ]}|d kV  qdS ©é   Nr   ©r   Úvr   r   r	   Ú	<genexpr>F   r   zload_fd.<locals>.<genexpr>ZDateN)z%d/%m/%Yz%d/%m/%yZHomeTeamZAwayTeamc                 s   s   | ]}|d kV  qdS r!   r   r#   r   r   r	   r%   S   r   )ÚglobÚLEAGUEÚopenÚcsvÚ
DictReaderÚallr   Ústripr   ÚstrptimeÚdater   ÚTÚnormr   Ú	Exception)	ÚoutÚpÚfhÚopZclÚdZdtZfmtÚkeyr   r    r	   Úload_fd=   s4    
"(ÿ.r8   c            
      C   s€  i } t   t¡D �]j}t|dddd���B}t |¡D �]$}| d¡pDd ¡ dkrPq2t| d¡ƒ}|du s2|d	krpq2t| d
¡ƒt| d¡ƒt| d¡ƒg}t|ƒr2tdd„ |D ƒƒs´q2| d¡}zt	 
|dd… d¡ ¡ }W n ttfyô   Y q2Y n0 |t t | d¡¡¡t t | d¡¡¡f}| d }	|| v�sH|	| | d k r2t|ƒ|	f| |< q2W d  ƒ q1 �sp0    Y  q| S )zM(date, home_fd, away_fd) -> (last pre-KO AF pinnacle probs, hours before KO).r   r   r   r   ZstatusZPREÚelapsedNr   Zpin_homeZpin_drawZpin_awayc                 s   s   | ]}|d kV  qdS r!   r   r#   r   r   r	   r%   f   r   zload_af.<locals>.<genexpr>Z	game_dateé
   z%Y-%m-%dÚhomeÚawayg      N@r"   )r&   ÚLIVEr(   r)   r*   r   Úupperr
   r+   r   r-   r.   r   r   r/   r0   ÚDSZ	fdco_namer   )
Zbestr3   r4   r   Zelr   Úgdr6   r7   Úhrsr   r   r	   Úload_afZ   s0    (

ÿ
4rB   c               
   C   s<  t ƒ } tƒ }t| ƒt|ƒ@ }tdt| ƒ› �ƒ tdt|ƒ› �ƒ tdt|ƒ› d�ƒ t|ƒdk rltdƒ d S g g g   }}}ttƒ}|D ]r}| | \}}	|| \}
}| |¡ tdƒD ]B\}}|
| |	|  d }| |¡ | t	|ƒ¡ ||  |¡ q¶qˆ| 
¡  td	ƒ td
t |¡d›dt |¡d›d�ƒ | ¡ D ]*\}}td|d›dt |¡d›d�ƒ �q:tdƒ tdƒ tdt |¡d›d|tt|ƒd ƒ d›d|tt|ƒd ƒ d›dt|ƒd›d�	ƒ tdtdd„ |D ƒƒt|ƒ d d›dtdd„ |D ƒƒt|ƒ d d›d �ƒ td!t |¡d"›d#�ƒ td$ƒ d S )%Nz,football-data fixtures with Pinnacle close: z3live_data fixtures with an API-Football pin quote: zmatched on (date, home, away): Ú
é   z-too few matched fixtures to conclude anything)r;   Zdrawr<   éd   zDQ1 -- IS IT PINNACLE?  (signed: AF minus real Pinnacle close, cents)z    mean bias z+.3fzc   median r   z      Z5sz mean zY    A near-zero centre means the same book. A persistent bias would mean a different one.z5
Q2 -- WHAT DOES THE LAG COST?  (|AF - close|, cents)z    median z.2fzc   p75 g      è?zc   p90 gÍÌÌÌÌÌì?zc   max z    within 1c: c                 s   s   | ]}|d k rd V  qdS r!   r   r   r   r   r	   r%   ™   r   zmain.<locals>.<genexpr>z.0fz%   beyond 3c: c                 s   s   | ]}|d krdV  qdS )é   r"   Nr   r   r   r   r	   r%   š   r   ú%z)    (our last pre-KO read is a median of z.1fzh before kickoff)zŸ
    For scale: the xlow band is 5-12% of fair. On a 25c leg that is 1.25-3.0c,
    so an error of this size is a material fraction of the signal being traded.)r8   rB   ÚsetÚprintÚlenr   ÚlistÚappendÚ	enumerateÚabsÚsortÚ
statisticsZmeanZmedianÚitemsÚintÚmaxr   )ÚfdZafÚkeysZsignedZabsdZlagsZper_sideÚkÚ_ÚcloseZafprA   ÚiZsider6   r   r$   r   r   r	   Úmainv   sN    


ÿ
$*ÿÿ
&ÿ
rZ   Ú__main__)Ú__doc__r)   r&   rP   ÚsysÚcollectionsr   r   ÚpathÚinsertZdaily_signalsr?   Znonprice_edge_testr/   r=   r'   r
   r   r8   rB   rZ   Ú__name__r   r   r   r	   Ú<module>   s&   -