a
    ¹Ç?jn  ã                   @   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 dZg d¢Z	dd„ Z
d	d
„ Zd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£  
Band sweep under HONEST (power) de-vig: which CLV band is actually +EV, and is it
stable out-of-sample?  Read-only, no betting.

For each candidate band [lo,hi), re-run the frozen selection (first pre-KO snapshot
whose power-de-vig mid-CLV is in band; both-sides dedupe to higher CLV; bet at that
snapshot's ask; settle by ftr). Report n, WR, implied(ask) WR, flat ROIturn, and the
one-sided win-rate-vs-implied z (Poisson-binomial).

Sweeping bands IS multiple testing, so for each band we ALSO show a 60/40 temporal
split (first 60% of fixtures by date = "train", last 40% = "test"). A band whose edge
lives only in the train half is an in-sample mirage, not a real band.
é    N)Údatetime)ÚdefaultdictzE:\soccer\live_data)z%Y-%m-%d %H:%M:%Sz%m/%d/%Y %H:%Mz%m/%d/%Y %H:%M:%Sz%Y-%m-%d %H:%Mc              
   C   s8   t D ].}zt | |¡W   S  ttfy0   Y q0 qd S ©N)Ú_FMTSr   ÚstrptimeÚ
ValueErrorÚ	TypeError)ÚsÚf© r   ú&E:\soccer\research\devig_band_sweep.pyÚ_pts   s    r   c              	   C   s(   z
t | ƒW S  ttfy"   Y d S 0 d S r   )Úfloatr   r   ©Úxr   r   r   Ú_f   s    r   c                 C   s8   t | ƒD ]*}| d¡pd ¡  ¡ }|dv r|  S qd S )NÚftrÚ )ÚHÚDÚA)ÚreversedÚgetÚupperÚstrip)ÚrowsÚrÚvr   r   r   Ú_result   s    r   c                    s�   dd„ | D ƒ}d\}}t dƒD ]8}|| d ‰ t‡ fdd„|D ƒƒ‰ˆdkrRˆ }qˆ }q|| d ‰ ‡ fd	d„|D ƒ}t|ƒ‰‡fd
d„|D ƒS )Nc                 S   s   g | ]}d | ‘qS )ç      ð?r   )Ú.0r   r   r   r   Ú
<listcomp>"   ó    zfair_power.<locals>.<listcomp>)ç      à?g      $@é<   é   c                 3   s   | ]}|ˆ  V  qd S r   r   ©r    Zri©Úkr   r   Ú	<genexpr>&   r"   zfair_power.<locals>.<genexpr>r   c                    s   g | ]}|ˆ  ‘qS r   r   r&   r'   r   r   r!   *   r"   c                    s   g | ]}|ˆ  ‘qS r   r   )r    Zpi)r	   r   r   r!   +   r"   )ÚrangeÚsum)Úor   ÚloÚhiÚ_Úpr   )r(   r	   r   Ú
fair_power!   s    r1   c                  C   sT  t tƒ} t tj td¡¡D ]p}t|ddd��N}t 	|¡D ]2}| | 
d¡| 
d¡| 
d¡| 
d¡f  |¡ q:W d   ƒ q1 s‚0    Y  qg }|  ¡ D �]¢\\}}}}}	|s²qštd	d
„ |	D ƒdd„ d�}
t|
ƒdk rÚqšt|	ƒ}|d u rìqšg }|
D �] \}}t| 
d¡ƒt| 
d¡ƒt| 
d¡ƒ  }}}d |||fv sô|dkrô|dkrô|dk�sVqôt|||fƒ}i }dD ]ž\}}t| 
d|› d�¡ƒ}t| 
d|› d�¡ƒ}|d u �sÎ|d u �sÎd|  k �rÌdk �sÚn d ||< �ql|| �rø|| | ||  nd }||f||< �ql| |¡ qô|rš| t|||||dk|dkd�¡ qš|jdd„ d� |S )Nz*.csvr   zutf-8)ÚnewlineÚencodingZ	game_dateÚleagueÚhomeÚawayc                 S   s>   g | ]6}|  d ¡pd ¡ dkrt|d ƒrt|d ƒ|f‘qS )Zstatusr   ZPREZ	timestamp)r   r   r   )r    r   r   r   r   r!   9   s   "ÿz!load_fixtures.<locals>.<listcomp>c                 S   s   | d S ©Nr   r   ©Útr   r   r   Ú<lambda>;   r"   zload_fixtures.<locals>.<lambda>©Úkeyr%   Zpin_homeZpin_drawZpin_awayé   ))r5   r   )r6   r%   Zkalshi_Z_midZ_askr   r   r   )Úgdr4   r   ÚsnapsÚwon_homeÚwon_awayc                 S   s   | d S ©Nr>   r   r   r   r   r   r:   O   r"   )r   ÚlistÚglobÚosÚpathÚjoinÚLIVE_DIRÚopenÚcsvZ
DictReaderr   ÚappendÚitemsÚsortedÚlenr   r   r1   ÚdictÚsort)ZfixturesrF   Zfhr   Úpreppedr>   r4   r5   r6   r   Zprer   r?   ZtsZphZpd_ZpaZpfÚrowÚsideZsidxZmidÚaskÚclvr   r   r   Úload_fixtures.   sJ    ÿÿ&þ
.*,."ÿ
rV   c                 C   sØ   g }| D ]º}g }dD ]z}|d D ]l}|  |¡}|d u r8q |\}	}
|	d u s ||	  kr\|k s`q  q |dkrp|d n|d }| |	|
|f¡  qq q|rt|dd„ d�\}	}
}| t|d	 |
|d
�¡ q|jdd„ d� |S )N)r5   r6   r?   r5   r@   rA   c                 S   s   | d S r7   r   r8   r   r   r   r:   _   r"   zselect.<locals>.<lambda>r;   r>   )r>   rT   Úwonc                 S   s   | d S rB   r   )Úbr   r   r   r:   a   r"   )r   rK   ÚmaxrO   rP   )rQ   r-   r.   ÚbetsZfxZcandsrS   ZsnapZcellrU   rT   rW   r   r   r   ÚselectR   s     

 r[   c                 C   sº   t | ƒ}|sd S tdd„ | D ƒƒ}tdd„ | D ƒƒ}tdd„ | D ƒƒ}tdd„ | D ƒƒ}|dkrr|| t |¡ nd}dt |t d	¡ ¡ }t||| d
 || d
 || d
 ||d�S )Nc                 s   s   | ]}|d  V  qdS )rW   Nr   ©r    rX   r   r   r   r)   g   r"   zstat.<locals>.<genexpr>c                 s   s.   | ]&}|d  r"d|d  |d  ndV  qdS )rW   r=   rT   g      ð¿Nr   r\   r   r   r   r)   h   r"   c                 s   s   | ]}|d  V  qdS )rT   Nr   r\   r   r   r   r)   i   r"   c                 s   s"   | ]}|d  d|d    V  qdS )rT   r=   Nr   r\   r   r   r   r)   i   r"   r   g        r#   r%   éd   )ÚnÚwrÚiwrÚroiÚzr0   )rN   r+   ÚmathZsqrtZerfcrO   )rZ   r^   ZwinsZnetZmuÚvarrb   r0   r   r   r   Ústatd   s    $re   c            
      C   s˜  t ƒ } tdt| ƒ› d�ƒ g d¢}tdd›ddd›dd	d
›ddd›ddd›ddd›ddd›d�ƒ |D �]\}}t| ||ƒ}t|ƒ}|s¤td|d›d|d›d�ƒ qftt|ƒd ƒ}t|d |… ƒt||d … ƒ }}d|d›d|d›d|d d›d|d d›d|d d›d|d d›d|d d›d|d d ›d!�}	|�rz|�rz|	d"|d d#›d$|d d%›d&|d d#›d$|d d%›d'�	7 }	t|	ƒ qftd(ƒ td)ƒ d S )*NzLoaded z* resolved fixtures with pre-KO snapshots.
))ç{®Gáz”?çš™™™™™©?)g¸…ëQ¸ž?çìQ¸…ë±?)rg   ç¸…ëQ¸¾?)rg   çš™™™™™É?)rh   g333333Ã?)rh   rj   )çš™™™™™¹?rj   )rk   ç333333Ó?)ri   rl   )rg   r   )rk   r   )rf   r   ZbandZ14sú r^   z>4zWR%z>5zimpl%z>6zROIturn%z>9rb   r0   z*   | 60/40 split  trainROI(z)   testROI(z)ú[z.2fú,z)  (no bets)g333333ã?z)  Z4dr_   z5.1fr`   z6.1fra   z+9.1fz+6.2fz6.3fz   | ztr:z+6.1fz%(zz+.2fz) te:ú)zI
Note: lowest-p band here is IN-SAMPLE optimized over 12 bands. Trust thezJ60/40 split (does the edge survive in the test half?) over the headline p.)rV   ÚprintrN   r[   re   Úint)
rQ   Zbandsr-   r.   rZ   r	   ZcutZtrZteÚliner   r   r   Úmainn   s6    @"6ÿÿÿÿÿ

rt   Ú__main__)Ú__doc__rJ   rD   rE   rc   r   Úcollectionsr   rH   r   r   r   r   r1   rV   r[   re   rt   Ú__name__r   r   r   r   Ú<module>   s    $
