a
    žÈ?j  ã                   @   sÌ   d Z ddlZddlZddlZddlZddlmZmZ ddlmZ dZ	dZ
dZdd	d
œZg d¢Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ ZeedœZdd„ Zdd„ Zdd„ Zd"dd„Zdd „ Zed!krÈeƒ  dS )#a  
FORWARD TEST (read-only, trades nothing): honest-de-vig band [0.07,0.20) vs the
current live band [0.05,0.12), on genuinely out-of-sample fixtures.

WHY: the band sweep (research/devig_band_sweep.py, 2026-06-27) found that under
POWER de-vig (which de-biases Pinnacle's longshot over-statement), the signal lives
at honest CLV >= 0.07, not 0.05 -- the marginal [0.05,0.07) bets pay vig with zero
edge (WR==implied) and drag the recent half. A [0.07,0.20) band was +20% ROIturn and
positive in BOTH temporal halves, while the current [0.05,0.12) band's edge had
reverted (test-half +0.9%). BUT that band was selected in-sample over 12 candidates
(p=0.046 -> ~0.55 Bonferroni), so it is a HYPOTHESIS, not proof. This script freezes
the band choice as of FREEZE_DATE and tracks both bands on later fixtures so we get
clean OOS evidence before any live change. NOTHING is traded.

Selection (both bands, NON-look-ahead): first pre-KO snapshot whose mid-CLV is in the
band; both-sides dedupe to the higher-CLV side; bet at that snapshot's ask; settle by
ftr. The de-vig differs per arm:
  - 'live'  : multiplicative pin_fair, band [0.05,0.12)   (what the pipeline ships)
  - 'honest': power pin_fair,          band [0.07,0.20)   (the candidate)
Appends one dated row per run to forward_test_devig_band_log.csv.
é    N)ÚdatetimeÚdate)ÚdefaultdictzE:\soccer\live_dataz2E:\soccer\research\forward_test_devig_band_log.csvz
2026-06-27)Úmultgš™™™™™©?g¸…ëQ¸¾?)ÚpowergìQ¸…ë±?gš™™™™™É?)ZliveZhonest)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\forward_test_devig_band.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 ƒ}t |ƒ‰ ‡ fdd„|D ƒS )Nc                 S   s   g | ]}d | ‘qS ©ç      ð?r   ©Ú.0r   r   r   r   Ú
<listcomp>1   ó    zfair_mult.<locals>.<listcomp>c                    s   g | ]}|ˆ  ‘qS r   r   ©r%   Zri©r   r   r   r&   2   r'   )Úsum)Úor   r   r)   r   Ú	fair_mult0   s    r,   c                    sŒ   dd„ | D ƒ}d\}}t dƒD ]4}|| d ‰ t‡ fdd„|D ƒƒdkrNˆ }qˆ }q|| d ‰ ‡ fd	d„|D ƒ}t|ƒ‰‡fd
d„|D ƒS )Nc                 S   s   g | ]}d | ‘qS r"   r   r$   r   r   r   r&   4   r'   zfair_power.<locals>.<listcomp>)g      à?g      $@é<   é   c                 3   s   | ]}|ˆ  V  qd S r   r   r(   ©Úkr   r   Ú	<genexpr>8   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pir)   r   r   r&   <   r'   )Úranger*   )r+   r   ÚloÚhiÚ_Úpr   )r0   r   r   Ú
fair_power3   s     r7   )r   r   c               
   C   s   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 ]p\\}}}}}	|s°qštd	d
„ |	D ƒdd„ d�}
t|
ƒdk rØqšt|	ƒ}|d u rêqš| t|||dd
„ |
D ƒd�¡ qš|jdd„ d� |S )Nz*.csvr   ú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&   I   s   "ÿz!load_fixtures.<locals>.<listcomp>c                 S   s   | d S ©Nr   r   ©Útr   r   r   Ú<lambda>K   r'   zload_fixtures.<locals>.<lambda>©Úkeyr.   c                 S   s   g | ]\}}|‘qS r   r   )r%   r5   r   r   r   r   r&   O   r'   )Úgdr<   r   Úprec                 S   s   | d S ©NrE   r   r   r   r   r   rB   P   r'   )r   ÚlistÚglobÚosÚpathÚjoinÚLIVE_DIRÚopenÚcsvZ
DictReaderr   ÚappendÚitemsÚsortedÚlenr!   ÚdictÚsort)ZfixturesrK   Úfhr   ÚpreppedrE   r<   r=   r>   r   rF   r   r   r   r   Úload_fixtures?   s*    ÿÿ&þ
"rX   c              	   C   sº  t | }g }| D �]’}g }dD �]P\}}	|d D �]<}
t|
 d¡ƒt|
 d¡ƒt|
 d¡ƒ  }}}d |||fv s0|dkr0|dkr0|dksŒq0t|
 d|› d�¡ƒ}t|
 d|› d	�¡ƒ}|d u s0|d u s0d
|  k rÜdk sàq0 q0||||fƒ|	 }|�r|| | nd }|d u s0||  k�r(|k �s,q0 q0|d dk�rD|dk�pX|d dk�oX|dk}| |||f¡  qq0q|rt|dd„ d�\}}}| t|d ||d�¡ q|jdd„ d� |S )N))r=   r   )r>   r.   rF   Zpin_homeZpin_drawZpin_awayé   Zkalshi_Z_midZ_askr   r   r   r=   r   r>   c                 S   s   | d S r?   r   r@   r   r   r   rB   c   r'   zselect.<locals>.<lambda>rC   rE   )rE   ÚaskÚwonc                 S   s   | d S rG   r   )Úbr   r   r   rB   e   r'   )Ú_DEVIGr   r   rP   ÚmaxrT   rU   )rW   Zdevigr3   r4   ÚfnÚbetsÚfxZcandsZsideZsidxr   ZphZpd_ZpaZmidrZ   ZpfZclvr[   r   r   r   ÚselectS   s&    
.(,($.rb   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}t||| d || d || d |d	�S )
Nc                 s   s   | ]}|d  V  qdS )r[   Nr   ©r%   r\   r   r   r   r1   k   r'   zstat.<locals>.<genexpr>c                 s   s.   | ]&}|d  r"d|d  |d  ndV  qdS )r[   rY   rZ   g      ð¿Nr   rc   r   r   r   r1   l   r'   c                 s   s   | ]}|d  V  qdS )rZ   Nr   rc   r   r   r   r1   m   r'   c                 s   s"   | ]}|d  d|d    V  qdS )rZ   rY   Nr   rc   r   r   r   r1   m   r'   r   g        éd   )ÚnÚwrÚiwrÚroiÚz)rS   r*   ÚmathZsqrtrT   )r`   re   ZwinsZnetZmuÚvarri   r   r   r   Ústath   s    $rl   c                 C   sL  | d u rt ƒ } t ¡  ¡ tdœ}t ¡ D ]°\}\}}}dd„ | D ƒ}|rZtt||||ƒƒnd }|rj|d nd||› d�< |rŠt	|d dƒnd	||› d
�< |rªt	|d dƒnd	||› d�< |rÊt	|d dƒnd	||› d�< q(t
j t¡ }ttdd	dd��>}	tj|	t| ¡ ƒd�}
|�r|
 ¡  |
 |¡ W d   ƒ n1 �s>0    Y  |S )N)Zrun_dateZfreeze_datec                 S   s   g | ]}|d  t kr|‘qS ©rE   ©ÚFREEZE_DATE)r%   ra   r   r   r   r&   u   r'   z log_snapshot.<locals>.<listcomp>re   r   Z_nrf   rY   r   Z_wrrh   Z_roiri   r.   Z_zÚar8   r9   )Z
fieldnames)rX   r   ZtodayZ	isoformatro   ÚARMSrQ   rl   rb   ÚroundrJ   rK   ÚexistsÚLOG_CSVrN   rO   Z
DictWriterrH   ÚkeysZwriteheaderZwriterow)rW   ÚrowÚnameÚdvr3   r4   Zoosr   ÚnewrV   Úwr   r   r   Úlog_snapshotq   s      "*r{   c                  C   s2  t ƒ } tdt› dt| ƒ› d�ƒ ddd„ | D ƒfddd„ | D ƒffD ]Ò\}}td	|› d
�ƒ |sjtdƒ qDt ¡ D ]œ\}\}}}tt||||ƒƒ}|rütd|d›d|d›d|d›d|d›d|d d›d|d d›d|d d›d|d d›d|d d ›�ƒ qrtd|d›d!�ƒ qrtƒ  qDt| ƒ td"t	› �ƒ d S )#NzFREEZE_DATE=z   total resolved fixtures=Ú
zIN-SAMPLE (<=freeze, reference)c                 S   s   g | ]}|d  t kr|‘qS rm   rn   ©r%   r   r   r   r   r&   …   r'   zmain.<locals>.<listcomp>zFORWARD (OOS, >freeze)c                 S   s   g | ]}|d  t kr|‘qS rm   rn   r}   r   r   r   r&   †   r'   z--- z ---z  (no fixtures yet)
z  Z7sú Z5sz [z.2fú,z)  n=re   Z4dz  WR=rf   z4.1fz%  impl=rg   z%  ROIturn=rh   z+6.1fz%  z=ri   z+.2fz
 (no bets)zlogged snapshot -> )
rX   Úprintro   rS   rq   rQ   rl   rb   r{   rt   )rW   ZlabelÚsubrw   rx   r3   r4   r   r   r   r   Úmain‚   s,    ÿ
<ÿÿÿ
r‚   Ú__main__)N)Ú__doc__rO   rI   rJ   rj   r   r   Úcollectionsr   rM   rt   ro   rq   r   r   r   r!   r,   r7   r]   rX   rb   rl   r{   r‚   Ú__name__r   r   r   r   Ú<module>   s.    þ

	
