a
    æoxjY  ã                   @   s|   d 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ddd	d
œZ	dZ
dd„ Zdd„ Zdd„ Zedkrxe eƒ ¡ dS )a‰  Remove double-booked bets from bet_history.json and rebuild the bankrolls.

THE BUG. Dedupe in both logging paths consulted pending_bets.json only, which
protects a bet just while it is OPEN. A match that kicked off early and settled
between two runs of the job left pending, so the next run logged the same signal
again and booked its P&L twice. Found 2026-08-08 via the nightly email showing
Independiente Rivadavia v Estudiantes de Rio Cuarto twice (baseline, Away,
-1.67 each). Fixed at source in daily_signals._settled_keys and the matching
guard in live_monitor._log_pending_bets.

THE REPAIR. Keyed on (date, home, away, side, strategy): keep the FIRST row,
drop later identical ones. A rematch on a different date is a different key and
is untouched. Nothing is deleted outright -- dropped rows are written to a
sidecar file so the decision stays auditable.

Bankrolls are then replayed from scratch over the deduped ledger, because
_load_kalshi_bankroll feeds Kelly sizing: a wrong bankroll silently mis-sizes
every future bet, so this matters beyond bookkeeping.

Usage:  python research\fix_duplicate_bets.py [--apply]
        (default is a DRY RUN)
é    N)ÚCounter)ÚdatetimezE:\soccer\data\bet_history.jsonz2E:\soccer\data\bet_history_duplicates_removed.jsonzE:\soccer\data\bankroll.jsonz#E:\soccer\data\kalshi_bankroll.jsonz!E:\soccer\data\poly_bankroll.json©Úb365ÚkalshiÚpolyg     @�@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\fix_duplicate_bets.pyÚ_f'   s    
r   c                 C   s@   t |  d¡ƒd d… |  d¡|  d¡t |  d¡ƒ|  d¡p<dfS )NÚdateé
   ÚhomeÚawayÚbetÚstrategyÚbaseline©ÚstrÚget)Úbr   r   r   Úkey.   s    $ÿr   c                  C   s  dt jv } t ttdd�¡}t|tƒr*|n
| d|¡}t	ƒ }g g  }}|D ]6}t
|ƒ}||  d7  < || dkrv|n| |¡ qJtt|ƒ› dt|ƒ› dt|ƒ› �ƒ d}|D ]’}td	| d
¡› d| d¡pÎdd›d| d¡› d| d¡› d| d¡› d�ƒ dD ]<}	t| |	¡ƒ}
|
d u�r||
7 }td|	› d|
d›�ƒ �qq®td|d›�ƒ ddddœ}|D ]>}dD ]2\}}t| |¡ƒ}
|
d u�rj||  |
8  < �qj�qbtdd„ |D ƒƒ}|�rÂ|d nd }|D ]p}|�rÊt| d
¡ƒd d… |k�rÊdD ]B\}}t| |¡ƒ}
|
d u�rô|| �rôt|
||  d ƒ||< �qô�qÊtd!ƒ i }dD ]†}zt tt| dd�¡d" }W n t�y†   d}Y n0 t|||  d ƒ||< td#|d$›d|d%›d&|| d%›d'|| d(›d)�	ƒ �qL| �sætd*ƒ dS t ¡  d+¡}t tt› d,|› �¡ t ¡ D ]6}zt ||› d,|› �¡ W n t�yD   Y n0 �qtj|ttd-dd�d d.d/� t|tƒ�rv|ni |¥d|i¥}tj|ttd-dd�d d.d/� t ¡ D ]>\}}tjt|| d ƒt ¡  d0¡d1œt|d-dd�d d2� �qªtd3|› d4t› �ƒ dS )5Nz--applyzutf-8)ÚencodingZbetsé   z rows -> keep z, drop g        z   DROP r   ú r   r   Z10sr   z v r   z [r   ú])ÚpnlÚ
kalshi_pnlÚpoly_pnlz        z+.2fz
P&L removed from the ledger: r   ))r   r   )r   r    )r   r!   c                 s   s$   | ]}t | d ¡ƒdd… V  qdS )r   Nr   r   )Ú.0r   r   r   r   Ú	<genexpr>\   ó    zmain.<locals>.<genexpr>r   r   ))r   Zbankroll_after)r   Zkalshi_bankroll_after)r   Zpoly_bankroll_afteré   zC
bankroll adjustment (surgical -- backs out the dropped rows only):Úbankrollz   Z7sz>10,.2fz  ->  z   (z+,.2fú)z1
DRY RUN -- nothing written. Re-run with --apply.z%Y%m%d_%H%M%Sz.bak_ÚwF)ÚindentZensure_asciiz%Y-%m-%d %H:%M)r&   Úupdated)r)   z
backups .bak_z; dropped rows -> )ÚsysÚargvÚjsonÚloadÚopenÚHISTÚ
isinstanceÚlistr   r   r   ÚappendÚprintÚlenr   Úsortedr   ÚroundÚ	BANKROLLSÚ	Exceptionr   ZnowÚstrftimeÚshutilZcopy2ÚvaluesÚOSErrorÚdumpÚDROPPEDÚitems)ZapplyÚrawZrowsÚseenZkeepZdroppedr   ÚkZdblÚfÚvZdeltaZvenZpfZdropped_datesZ	first_badÚrZbfÚrunZcurZstampÚpÚoutr   r   r   Úmain3   sŠ    

$"ÿÿÿ


"
6
 ÿþ
rJ   Ú__main__)Ú__doc__r-   r;   r+   Úcollectionsr   r   r0   r?   r8   ZSTARTr   r   rJ   Ú__name__Úexitr   r   r   r   Ú<module>   s"   ýT