a
    �rfj[  ã                   @   sj   d Z ddlZddlZddlZddlZddlmZ dZdZ	dd„ Z
dd	„ Zd
d„ Zdd„ Zedkrfeƒ  dS )aÅ  
Reconstruction of the "early-volume edge" finding, built fresh to verify it
survives the same scrutiny that broke the paper quoter today.

WHAT WENT WRONG TODAY (in mm_quoter.py / mm_settle.py, NOT this data): a
taker/maker mapping that was briefly inverted, a raw-string timestamp
comparison that silently filtered out every trade, and a fill test that
counted IN-PLAY trades as if they were pre-kickoff resting fills. All three
inflated results. This script re-derives the ORIGINAL historical finding from
mm_trades.csv with none of those mechanisms present, and prints explicit sanity
checks rather than asserting the number is right.

METHOD: for every trade on a settled market, compute what SHARE of that
market's total pre-kickoff volume had already traded before this trade (0.0 =
first trade, 1.0 = last). Bucket into deciles. For each decile, compute the
REALISED MAKER P&L using the verified taker_book_side mapping:
    taker_book_side == 'bid' -> taker BOUGHT -> MAKER SOLD at `price`
    taker_book_side == 'ask' -> taker SOLD   -> MAKER BOUGHT at `price`
This uses REAL trades that REALLY happened between REAL counterparties -- it is
not a simulation of our own resting order, so it cannot inherit the fill-timing
bugs that hit the paper quoter. It answers "what did the maker side of this
market earn", not "would WE have gotten that fill" (queue priority is still
unknowable from history -- unchanged caveat).

SANITY CHECKS (printed, not assumed):
  1. takers must be net BUYERS (~3-4:1) -- if not, the mapping is backwards.
  2. total notional and event count should roughly match kalshi_backfill.csv's
     641 events -- if far off, the join or filter is broken.

Usage:  python research\mm_decile_by_volume.py
é    N)Údefaultdictz E:\soccer\research\mm_trades.csvz&E:\soccer\research\kalshi_backfill.csvc                 C   s   d  |  d¡d d… ¡S )Nú-é   )ÚjoinÚsplit©Úticker© r	   ú)E:\soccer\research\mm_decile_by_volume.pyÚevent_of*   s    r   c              	   C   s8   zt j t| ƒ dd¡¡W S  ttfy2   Y dS 0 dS )z“Parse to an aware datetime. Never compare timestamp strings directly --
    that silently dropped every row in an earlier version of this analysis.ÚZz+00:00N)ÚdtÚdatetimeZfromisoformatÚstrÚreplaceÚ
ValueErrorÚ	TypeError)Úsr	   r	   r
   Úpt.   s    r   c                  C   sd   i } t tddd��>}t |¡D ]"}t| d¡ƒ}|r|| |d < qW d   ƒ n1 sV0    Y  | S )NÚ úutf-8©ÚnewlineÚencodingZkickoffZevent)ÚopenÚBACKFILLÚcsvÚ
DictReaderr   Úget)ÚoutZfhÚrÚkr	   r	   r
   Úload_kickoffs7   s    ,r"   c                  C   sÐ  t ƒ } tt ttddd�¡ƒ}dd„ |D ƒ}tt|ƒd›dt|ƒ› d�ƒ td	t| ƒ› d
�ƒ tdd„ |D ƒƒ}tdd„ |D ƒƒ}td|d›d|d›d|t	|dƒ d›d||kr´dnd› d�	ƒ g }d }}|D ]„}t
|d ƒ}	|  |	¡}
|
d u rü|d7 }qÐt|d ƒ}|d u �s||
k�r&|d7 }qÐdt|d ƒ  k�rFdk�sJqÐ qÐ| |¡ qÐdd„ }|j|d � |}td!|d›�ƒ td"|d›�ƒ td#t|ƒd›d$td%d„ |D ƒƒ› d&�ƒ ttƒ}|D ]}|t
|d ƒ  |¡ �qÄtd'd(„ ƒ}ttƒ}| ¡ D ]ì\}}td)d„ |D ƒƒ}|dk�r&�qþd*}|D ]¸}t|d+ ƒ}|| }||7 }t|d ƒt|d, ƒ }}|d- d.k�rˆ|| ||  }n|| ||  }tt|d/ ƒd0ƒ}|| d  |7  < || d  || 7  < ||  |¡ �q.�qþtd1d2›d3d4d5›d3d6d7›d3d8d9›�ƒ td/ƒD ]†}|| \}}|d:k �r8�qt|| ƒ}|dk�rRd;nd}t|d/ d<›d=|d/ d/ d<›d>|d?›d@|dA›dB|| dC dD›dE|› �ƒ �qtdFƒ tdGt|d ƒ› dHt|ƒ› dI�ƒ d S )JNr   r   r   c                 S   s   h | ]}t |d  ƒ’qS r   ©r   ©Ú.0r    r	   r	   r
   Ú	<setcomp>D   ó    zmain.<locals>.<setcomp>ú,z trade rows loaded, z distinct eventszkickoffs loaded for z eventsc                 s   s&   | ]}|d  dkrt |d ƒV  qdS )Útaker_book_sideÚbidÚcountN©Úfloatr$   r	   r	   r
   Ú	<genexpr>I   r'   zmain.<locals>.<genexpr>c                 s   s&   | ]}|d  dkrt |d ƒV  qdS )r)   Zaskr+   Nr,   r$   r	   r	   r
   r.   J   r'   zsanity: taker BOUGHT z,.0fz contracts, SOLD z -> buy:sell = é   z.1fz:1 (zOK, retail backs teamszSUSPICIOUS -- check mappingú)r   r   Útsgš™™™™™©?Zpricegffffffî?c                 S   s4   t | d ƒ}t| d ƒ|r|ntjjjtjjd�fS )Nr1   r   )Ztzinfo)r   r   r   r   Úminr   ÚtimezoneZutc)r    Útr	   r	   r
   Úkeyfk   s    zmain.<locals>.keyf)Úkeyz dropped (no kickoff on record): z%dropped (in-play, at/after kickoff): z"PRE-KICKOFF, 5c-95c, TIME-SORTED: z rows, c                 S   s   h | ]}t |d  ƒ’qS r   r#   r$   r	   r	   r
   r&   s   r'   z events
c                   S   s   ddgS )Nç        r	   r	   r	   r	   r
   Ú<lambda>}   r'   zmain.<locals>.<lambda>c                 s   s   | ]}t |d  ƒV  qdS )r+   Nr,   r$   r	   r	   r
   r.   €   r'   r7   r+   Z
result_yesr)   r*   é
   é	   ZdecileZ9sú Úeventsz>7sZnotionalz>13sZROIz>8siè  z  <-- opening tradesZ3dr   z%  Z7dz  $z12,.0fz  éd   z+7.2fú%zB
sanity check 2: decile-0 event count should be close to the totalzK  (every event contributes exactly one opening trade) -> decile-0 events = z vs z total events loaded)r"   Úlistr   r   r   ÚTRADESÚprintÚlenÚsumÚmaxr   r   r   r-   ÚappendÚsortr   ÚsetÚitemsÚintr2   ÚaddÚrange)ZkoZrowsr<   Zbuy_ctZsell_ctZkeptZdropped_no_koZdropped_inplayr    Úer!   r4   r5   Zby_eventZbucketZbucket_eventsZevZtrsÚtotalZcumÚcZfrac_beforeÚpÚresZpnlÚdZnotiZn_evÚflagr	   r	   r
   ÚmainA   sŽ    ÿþ
	
"	ÿ

&
L
ÿÿrS   Ú__main__)Ú__doc__r   ZmathZ
statisticsr   r   Úcollectionsr   r@   r   r   r   r"   rS   Ú__name__r	   r	   r	   r
   Ú<module>   s   	
_