a
    ·ÈAjr  ã                   @   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dZ	g d¢Z
dd	„ Zd
d„ Zdd„ Zdd„ Zdd„ Zd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±  
WHY do the "unique" (one-book-only) bets win?  Decompose by the OTHER book's CLV
on the SAME side at the SAME snapshot.

A unique bet = book A fired side S (CLV_A(S) in [0.05,0.12)) while book B did NOT
fire (B has NO side in band -> so B's CLV on S is OUTSIDE the band, i.e. either):
  (i)  B_clv(S) >= 0.12  -> the other book is EVEN CHEAPER. If the edge lives here,
       "unique" is just disguised HIGH-CLV (a repackaging of "raise the band ceiling"),
       NOT a cross-book signal.
  (ii) B_clv(S) <  0.05  -> the other book sees ~NO edge / is efficient. If the edge
       lives here, it's a GENUINE disagreement signal: one venue mispriced, the other
       corrected, and the mispriced one still wins.

Also compares OWN-CLV of unique vs overlap bets (if similar, the unique edge is NOT
just higher own-CLV). Reports n / WR / ROIturn / z per sub-bucket.
Multiplicative de-vig, shared-price fixtures, Kalshi@ask / Poly@mid. Read-only.
é    N)Údatetime)ÚdefaultdictzE:\soccer\poly_backfill)gš™™™™™©?g¸…ëQ¸¾?)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   ú2E:\soccer\research\kalshi_poly_unique_mechanism.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 )g      ð?r   ©Ú.0r   r   r   r   Ú
<listcomp>'   ó    zfair_mult.<locals>.<listcomp>c                    s   g | ]}|ˆ  ‘qS r   r   )r   Zri©r	   r   r   r    '   r!   )Úsum)Úor   r   r"   r   Ú	fair_mult&   s    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 ]l\}}|\}}}	}
|s´qštd	d
„ |D ƒdd„ d�}|sÔqšt|ƒ}|d u ræqš| t|||dd
„ |D ƒd�¡ qš|S )Nz*_polybackfill.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    4   s   "ÿzload.<locals>.<listcomp>c                 S   s   | d S )Nr   r   )Útr   r   r   Ú<lambda>6   r!   zload.<locals>.<lambda>©Úkeyc                 S   s   g | ]\}}|‘qS r   r   )r   Ú_r   r   r   r   r    :   r!   )Úgdr(   r   Úpre)r   ÚlistÚglobÚosÚpathÚjoinÚDIRÚopenÚcsvZ
DictReaderr   ÚappendÚitemsÚsortedr   Údict)Zfixturesr5   Zfhr   Úfxr.   r   r0   r(   r)   r*   r1   r   r   r   r   Úload)   s*    ÿÿ&þ
"r?   é   )r)   r*   c                 C   s`   |dkr4t |  d|› d�¡ƒt |  d|› d�¡ƒfS t |  d|› d�¡ƒt |  d|› d�¡ƒfS )NÚkalshiZkalshi_Z_midZ_askZpoly_Z_price)r   r   )r   ÚbookÚsider   r   r   Úbook_mid_ask>   s    ,rD   c                 C   s–  g }d}t  ¡ D �]`\}}| d D �]L}t| d¡ƒt| d¡ƒt| d¡ƒ  }}}	d|||	fv s"|dkr"|dkr"|	dks~q"t|||ƒ\}
}|
du s"|du s"d|
  k r²dk r"n q"d|  k rÊdk sÎq" q"d	}t|||	fƒ| }|rô||
 | nd}|du s"td |  k�r td k �s$q" q"| d
 dk�r<|dk�pP| d
 dk�oP|dk}| t||||||d�¡  qq"q|�s‚d|fS t	|dd„ d�|fS )zKReturn bet dict (incl the firing ROW + pin fair on side) + have_price flag.Fr1   Zpin_homeZpin_drawZpin_awayNé   r   Tr   r   r)   r   r*   )ÚclvrC   ÚpxÚwonÚrowÚpfc                 S   s   | d S )NrF   r   )Údr   r   r   r,   S   r!   zfire.<locals>.<lambda>r-   )
ÚSIDXr;   r   r   rD   r%   ÚBANDr:   r=   Úmax)r>   rB   ZcandsZhaverC   Zsidxr   ÚphZpd_ZpaÚmidrG   rJ   rF   rH   r   r   r   ÚfireC   s    .(@,."rQ   c                 C   s`   | d | d | d   }}}t |||ƒ\}}|du sPd|  k rHdk rPn n|sTdS || | S )z=Other book's CLV on the SAME side at the firing snapshot row.rI   rC   rJ   Nr   rE   )rD   )ZbetZ
other_bookr   rC   rJ   rP   r/   r   r   r   Ú	other_clvU   s    (rR   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d	„ | D ƒ}t||| d
 || d
 |dt |t d¡ ¡ |rÌt|ƒt |ƒ d
 ntdƒd�S )Nc                 s   s   | ]}|d  V  qdS )rH   Nr   ©r   Úbr   r   r   Ú	<genexpr>_   r!   zstat.<locals>.<genexpr>c                 s   s.   | ]&}|d  r"d|d  |d  ndV  qdS )rH   rE   rG   g      ð¿Nr   rS   r   r   r   rU   `   r!   c                 s   s   | ]}|d  V  qdS )rG   Nr   rS   r   r   r   rU   a   r!   c                 s   s"   | ]}|d  d|d    V  qdS )rG   rE   Nr   rS   r   r   r   rU   a   r!   r   g        c                 S   s"   g | ]}|  d ¡dur|d  ‘qS )ÚownclvN©r   rS   r   r   r   r    c   r!   zstat.<locals>.<listcomp>éd   g      à?r@   Únan)ÚnÚwrÚroiÚzÚprV   )Úlenr#   ÚmathZsqrtr=   Zerfcr   )ZbetsrZ   ZwinsZnetZmuÚvarr]   Úocr   r   r   Ústat\   s    $0ÿrc   c                 C   sx   |st d| d›d�ƒ d S t d| d›d|d d›d|d d	›d
|d d›d|d d›d|d d›d|d d	›d�ƒ d S )Nz  Z38sz (none)z n=rZ   Z3dz  WR=r[   z4.1fz%  ROIturn=r\   z+6.1fz%  z=r]   z+.2fz  p=r^   z.3fz	  ownCLV=rV   ú%)Úprint)Útagr	   r   r   r   Úlineg   s    0ÿÿÿrg   c                  C   s@  t ƒ } g }g }| D ]¬}t|dƒ\}}t|dƒ\}}|r|s<q|r\|r\|d |d< | |¡ q|rŽ|sŽt|dƒ}|d |d< ||d< | |¡ q|r|st|dƒ}|d |d< ||d< | |¡ qtdt|ƒ› dt|ƒ› d�ƒ td	ƒ td
t|ƒƒ tdt|ƒƒ dd„ |D ƒ}	dd„ |D ƒ}
dd„ |	D ƒ}dd„ |	D ƒ}dd„ |	D ƒ}tdt|	ƒ› dt|
ƒ› d�ƒ tdt|ƒƒ tdt|ƒƒ tdt|ƒƒ tdt|
ƒƒ |	�r$tdd„ |	D ƒƒ}t	dd„ |D ƒƒ}tdt|ƒ› d|d d d ›d!|t|ƒd"  d d ›d#|d$ d d ›d%|› d&t|ƒ› d'�ƒ td(ƒ td)ƒ td*ƒ d S )+NrA   ZpolyrF   rV   Úotherclvzunique=z
  overlap=Ú
z/OWN-CLV check (is unique just higher own-CLV?):zUNIQUE betszOVERLAP betsc                 S   s   g | ]}|  d ¡dur|‘qS ©rh   NrW   rS   r   r   r   r    �   r!   zmain.<locals>.<listcomp>c                 S   s   g | ]}|  d ¡du r|‘qS rj   rW   rS   r   r   r   r    ‚   r!   c                 S   s    g | ]}|d  t d kr|‘qS )rh   rE   ©rM   rS   r   r   r   r    ƒ   r!   c                 S   s    g | ]}|d  t d k r|‘qS )rh   r   rk   rS   r   r   r   r    „   r!   c                 S   s4   g | ],}t d  |d   kr(t d k rn q|‘qS )r   rh   rE   rk   rS   r   r   r   r    …   r!   zH
Decompose UNIQUE by OTHER book's CLV on the bet side (have_other_price=z, no_other_price=z):z$(i)  other EVEN CHEAPER (oclv>=0.12)z!(ii) other EFFICIENT  (oclv<0.05)z     other in-band [0.05,0.12)z     other price MISSING at rowc                 s   s   | ]}|d  V  qdS rj   r   rS   r   r   r   rU   �   r!   zmain.<locals>.<genexpr>c                 s   s   | ]}|d k rdV  qdS )r   rE   Nr   r   r   r   r   rU   �   r!   z!
  other-book CLV on bet side: n=z  min=r   rX   z+.1fz
%  median=r@   z%  max=éÿÿÿÿz%  (z of z" NEGATIVE = other book ABOVE fair)z
Interpretation key:zL  edge in (i)  -> 'unique' = disguised HIGH-CLV (raise band ceiling instead)z8  edge in (ii) -> GENUINE cross-book disagreement signal)
r?   rQ   r:   rR   re   r_   rg   rc   r<   r#   )r>   ZuniqZoverlapr
   ÚkZkhr^   rO   rb   Zhave_ocZno_ocZcheaperZefficZinbandZocsÚnegr   r   r   Úmainl   s\    
**ÿÿ
ÿÿÿþþ
ro   Ú__main__)Ú__doc__r9   r3   r4   r`   r   Úcollectionsr   r7   rM   r   r   r   r   r%   r?   rL   rD   rQ   rR   rc   rg   ro   Ú__name__r   r   r   r   Ú<module>   s(    
-