a
    6AwjO  ã                   @   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	dƒZ
e	dƒ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#  Does the market move TOWARD our side after xlow fires? The testable question.

WHY THIS EXISTS. Realised P&L cannot validate xlow. Measured 2026-08-08 at
n=234: ROI +1.2%/bet against a per-bet stdev of 1.94u, so the 95% CI runs
[-23.7%, +26.1%] and proving the observed effect needs ~100,000 bets -- about 46
years at 6 bets/day. The forward test is a smoke alarm (it would catch a -25%
disaster), not a scale.

Line DRIFT is the same question with ~1/80th the variance. If the rule finds
genuine mispricing, the market should converge toward our fair value after we
identify it. A first pass over 61 reconstructed bets gave -0.77c with z=-2.46
(95% CI [-1.38c, -0.16c]) -- the market moving AWAY from our side. That is
suggestive but was found by slicing data many ways in one session, so this
script exists to run it as a STANDING, pre-registered metric on bets whose entry
mid was recorded at fire time rather than reconstructed afterwards.

TWO TRAPS THIS AVOIDS.

  1. MID-to-MID only. Comparing our entry ASK to a closing MID is biased by half
     the spread -- median 0.50c here, almost exactly the size of the effect. That
     comparison manufactures a negative result out of nothing.
  2. Exact entry timing. `entry_k_mid`/`entry_p_mid`/`entry_ts` are written by
     live_monitor._log_pending_bets at the instant the signal fires. Bets logged
     before 2026-08-08 lack them and are RECONSTRUCTED from the first pre-kickoff
     snapshot; those are reported separately and never pooled, because the
     reconstruction is a proxy for entry time and the whole point is to stop
     relying on it.

READING THE RESULT. Positive drift = the market moved toward our side = we got a
good price = evidence of edge. Negative = we are buying prices that then revert
against us.

Usage:  python research\clv_realisation.py
é    N)Údefaultdict)ÚPathzE:\soccer\data\bet_history.jsonz E:\soccer\data\pending_bets.jsonzE:\soccer\live_data\*.csvg{®Gázt?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\clv_realisation.pyÚ_f1   s    
r   c               	   C   s€   g } t tfD ]n}zt |jdd�¡}W n ty<   Y qY n0 t|tƒrL|n
| d|¡}|D ]}| d¡dv r\|  	|¡ q\q| S )Núutf-8©ÚencodingZbetsZstrategy)ZxlowZxlow_polyus)
ÚHISTÚPENDÚjsonÚloadsÚ	read_textÚ	ExceptionÚ
isinstanceÚlistÚgetÚappend)ÚoutÚpÚrawZrowsÚbr	   r	   r
   Ú	load_bets8   s    
r   c               	   C   s¬   i } t t t¡ƒD ]”}t|dd��t}t |¡D ]X}| d¡p>ddkrFq.| d¡| d¡| d¡f}|| vs~|d	 | | d	 kr.|| |< q.W d
  ƒ q1 sœ0    Y  q| S )z9(game_date, home, away) -> last PRE-kickoff snapshot row.r   r   ÚstatusÚ ÚPREÚ	game_dateÚhomeÚawayÚ	timestampN)ÚsortedÚglobÚLIVEÚopenÚcsvÚ
DictReaderr   )ÚlastÚfÚfhÚrÚkr	   r	   r
   Úclosing_midsF   s    *r0   c           
   
   C   s:  t |ƒ}td| › d|› d�ƒ |dk r2tdƒ d S t |¡}t |¡pHd}|t |¡ }|| }|d|  |d|   }}tdd	| d
›dd	| d›dd	| d›d|d
›�ƒ tdd	| d
›dd	| d
›d�ƒ d| t d }	|dkròtdƒ nD|dk �rtdƒ n0td|	d›dd	t d›dtd|	| ƒd›d�ƒ d S )NÚ
z  (n=ú)é
   z   too few to reportg•Ö&è.>g\�Âõ(\ÿ?z   mean drift éd   ú+.2fz
c   stdev z.2fzc   SE zc   z z   95% CI [zc, zc]é   r   z@   SIGNIFICANT and POSITIVE -- market converges toward our side.zn   SIGNIFICANT and NEGATIVE -- we are buying prices that revert against us. This is evidence AGAINST the rule.z   not significant; n=z,.0fz needed for a z.1fz
c effect (z more))	ÚlenÚprintÚ
statisticsÚmeanZpstdevÚmathZsqrtÚTARGET_EFFECTÚmax)
ÚnameZdriftsÚnÚmZsdZseÚzÚloÚhiZneedr	   r	   r
   ÚreportT   s(    
4"


ÿrD   c                  C   sÈ  t ƒ } g g  }}ttƒ}tƒ D �]}|  t| d¡ƒd d… | d¡| d¡f¡}|sXqdt| dd¡ƒ ¡ v rtdnd}t| d¡oŒ| d	¡ƒ}|r˜d
nd}t| |› d|› d�¡ƒ}	|	s¼qt|rÌ| d¡n| d¡ƒ}
|
�r| 	|	|
 ¡ || d¡  	|	|
 ¡ qd }t
t t¡ƒD ]ò}t|dd��Î}t |¡D ]²}| d¡�pFddk�rR�q4| d¡| d¡| d¡ft| d¡ƒd d… | d¡| d¡fk�rœ�q4t| |› d|› d�¡ƒ}|�r4|d u �sØ|d |d k �r4|d |f}�q4W d   ƒ n1 �sþ0    Y  �q|r| 	|	|d  ¡ qtdƒ tdƒ td|ƒ td|ƒ t|ƒdk�rÄtdƒ t
| ¡ dd„ d �d d… D ]H\}}t|ƒd!k�rztd"|d#›d$t|ƒd%›d&d't |¡ d(›d)�ƒ �qzd S )*NÚdater3   r"   r#   ZHOMEZbetr   Z
poly_stakeZpoly_askZpolyZkalshiÚ_Z_midZentry_p_midZentry_k_midZdivr   r   r   r    r!   r$   r   é   zICLV REALISATION -- does the market move toward our side after xlow fires?z;positive = toward us (edge)   negative = reverts against usz8EXACT entry mid (logged at fire time, 2026-08-08 onward)z:RECONSTRUCTED entry (pre-2026-08-08, proxy -- do NOT pool)z
   by league (exact only):c                 S   s   t | d ƒ S )NrG   )r7   r   r	   r	   r
   Ú<lambda>•   ó    zmain.<locals>.<lambda>)Úkeyé   z     Z6sz n=Z4dz  r4   r5   Úc)r0   r   r   r   r   ÚstrÚupperÚboolr   r   r%   r&   r'   r(   r)   r*   r8   rD   r7   Úitemsr9   r:   )r+   ÚexactZreconZby_lgr   ÚrowZsideZon_polyZpreÚcloseÚentryÚfirstr,   r-   r.   ÚvZlgZdsr	   r	   r
   Úmainl   sR    
. &ÿ"4

$rW   Ú__main__)Ú__doc__r)   r&   r   r;   r9   Úcollectionsr   Úpathlibr   r   r   r'   r<   r   r   r0   rD   rW   Ú__name__r	   r	   r	   r
   Ú<module>   s$   ".