a
    *ÙxjÄ,  ã                   @   sŽ   d Z ddlZddlZddlZddlmZ ej dd¡ ej dd¡ ddlZ	ddl
mZ dZe dd	¡Zd
Zdd„ Zdd„ ZedkrŠeƒ  dS )aG  Rebuild the maker's BOOK-level economics under the queue-aware fill model.

WHY. Every maker number reported to date -- completion rate, the P&L split by
legs filled, the liquidity-gate sweep -- comes from mm_settle, which counts any
trade printed at or above our ask as ours. That ignores queue position and its
own docstring calls it a CEILING. Meanwhile the live quoter acts on
paper_filled(), a queue-aware LOWER bound. So we have been choosing policy
against the ceiling while the machine ran on the floor, and the two disagree
badly: the settler scores 59 books as 2-of-3 while the quoter took no action on
39 of them.

This does not need new live data. Everything required is already recorded:
  * mm_paper_quotes.csv  -- our ask over time, plus ask_size (the depth we would
    have queued behind) at post time
  * Kalshi trade history -- fetched per leg by queue_aware_fill.trades_sized
So the pessimistic model can be replayed over the same books the optimistic one
scored, and the gate re-tested against BOTH bounds.

THE MODEL (same as the live quoter): posting at P with Q resting at P, we are
filled once cumulative volume of trades at price >= P after we post exceeds Q.
Q = ask_size at post time if we joined the touch, else 0. Q is pessimistic
because makers ahead of us can cancel unobserved -- hence a lower bound.

READ THE OUTPUT AS A RANGE, not a point. Optimistic is the ceiling, queue-aware
the floor, truth between. A gate that only works under the ceiling is not a
finding; one that holds under both is worth acting on.

Usage:  python research\mm_queue_aware_books.py [--limit N]
é    N)ÚdefaultdictzE:\soccer\mainzE:\soccer\research)Útrades_sizedz&E:\soccer\research\mm_paper_quotes.csvZquotesZresults)r   éd   éú   éô  iè  iÄ	  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\mm_queue_aware_books.pyÚ_f.   s    
r   c            0         sÞ  d } dt jv rDztt jt j d¡d  ƒ} W n ttfyB   Y n0 i }zbttdd��B}t 	|¡D ]&}t
| d¡ƒ}|d urb|||d < qbW d   ƒ n1 sž0    Y  W n ty¼   Y n0 tdt|ƒ› d�ƒ ttƒ}ttdd��P}t 	|¡D ]4}| d	¡rò| d
¡rò| d¡rò||d   |¡ qòW d   ƒ n1 �s>0    Y  |D ]}|| jdd„ d� �qLttƒ}| ¡ D ]4\}}||d  d¡�p | dd¡d   |¡ �qxdd„ | ¡ D ƒ}t|ƒ}	| �rÚ|	d | … }	tt|ƒ› dt|	ƒ› �ƒ g }
t|	dƒD �]B\}}|d dk�r2td|› dt|	ƒ› �ƒ |ddd dddœ}g }|| D �]þ}|| }|d }t |d ¡t |d ¡ }‰t
|d	 ƒ}t
|d
 ƒ}d |ˆ||fv �r²�qPt
| d¡ƒ}|d u�rÔ| |¡ t
| d¡ƒd u �rì�qP‡fdd„t||ƒD ƒ}d }}d }d}d }d }t|ƒD �]|\}}t
| d	¡ƒ}|d u �rJ�q$t |d ¡}|d t|ƒk �r€t ||d  d ¡nˆ}|d u �s˜|ˆk�rž �q¤|d u �s²|ˆk�r¶ˆ}|d u �sÒt|| ƒd k�rt
| d
¡ƒ}t
| d¡ƒ�pòd} |d u�r||d  k�r| nd}d}|}|D ]d\}!}"}#||!  k�rB|k �r n n|"|d  k �rX�q |�sfd!}|}||#7 }||k�r d!} �q†�q |�r$|d u �rš|} �q¤�q$| |¡}$|�p¶|}%|�rô|d"  d7  < |d#  |$d u�rì|%|$ d$ nd7  < |�r0|d%  d7  < |d&  |$d u�r(|%|$ d$ nd7  < |$d u �rP| d'd¡d |d'< �qP|�r`t|ƒnd |d(< g }&|| D ]†}t
|| d  d¡ƒ}'t
|| d  d	¡ƒ}t
|| d  d
¡ƒ}(|'d u �st|d u �st|(d u �rÜ�qt|& ||(d  k�rò|'nd¡ �qt|&�r
t|&ƒnd |d)< |�r2|d) �r2t|ƒ|d)  nd |d*< |
 |¡ �qd+d,„ })tƒ  td-d.›d/d0d1›d2d3d4›d2d5d4›�ƒ td6d.›d/d6d1›d2d7d8›d9d:d;›d9d<d=›d2d7d8›d9d:d;›d9d<d=›�ƒ tD ]¦‰ ‡ fd>d„|
D ƒ}*t|*ƒd?k �rî�qÆ|)|*d"d#ƒ}|)|*d%d&ƒ}+tˆ d@›d/|dA dB›d2|dC dD›d9|d: dE›dF|dG dH›dI|+dC dD›d9|+d: dE›dF|+dG dH›dJ�ƒ �qÆdKD �]N\},‰}-}.tƒ  t|,› ƒ td/dLdM›d9d0d1›d2dNdO›d9d<dP›d2dQdR›d9d<dP›�ƒ |-D ]ò\‰‰‡‡‡fdSd„|
D ƒ}*t|*ƒdTk �rü�qÌ|)|*d"d#ƒ}|)|*d%d&ƒ}+ˆdUk �r0ˆdV›dˆdV›�n
ˆdV›dW�}/ˆd*k�rnˆdUk �rbˆdX›dˆdX›�n
ˆdX›dW�}/td/|/dM›d9|dA dB›d2|d: dY›dF|dG dZ›dI|+d: d[›dF|+dG dZ›dJ�ƒ �qÌ�qrtƒ  td\ƒ td]ƒ d S )^Nz--limité   zutf-8)ÚencodingÚsettledZ
leg_tickerzsettlements known for z legsZour_askZk_askc                 S   s   | d S )NÚtsr   r   r   r   r   Ú<lambda>P   ó    zmain.<locals>.<lambda>©Úkeyr   Zeventú-c                 S   s"   i | ]\}}t |ƒd kr||“qS )é   )Úlen)Ú.0ÚeZlsr   r   r   Ú
<dictcomp>U   r   zmain.<locals>.<dictcomp>z three-leg books; scoring é   z  ...ú/g        )ÚevÚoptÚqÚvolÚopt_pnlÚq_pnlr   ZkickoffZvolumeZask_sizec                    s$   g | ]\}}}|ˆ k r|||f‘qS r   r   )r   ÚtÚpÚc)Úkor   r   Ú
<listcomp>x   r   zmain.<locals>.<listcomp>Fg•Ö&è.>Tr!   r$   r   r"   r%   Zunscoredr#   ÚqueueÚratioc                    sZ   t | ƒ}|sd S t‡ fdd„| D ƒƒ}t‡fdd„| D ƒƒ}t||d| | ||| d�S )Nc                 3   s   | ]}|ˆ  d krdV  qdS )r   r   Nr   ©r   Úrr   r   r   Ú	<genexpr>Ñ   r   z*main.<locals>.summarise.<locals>.<genexpr>c                 3   s   | ]}|ˆ  V  qd S r   r   r-   )Úpnlkeyr   r   r/   Ò   r   g      Y@)ÚnÚcompÚrateÚpnlÚper)r   ÚsumÚdict)Úselr   r0   r1   r2   r4   r   )r   r0   r   Ú	summariseÍ   s    zmain.<locals>.summariseZgatez>7sz  Úbooksz>5sz | zOPTIMISTIC (ceiling)z>28szQUEUE-AWARE (floor)Ú z3/3z>4sú r3   z>6szc/bookz>9sc                    s(   g | ] }|d  dur|d  ˆ kr|‘qS )r#   Nr   r-   )Úgr   r   r*   Û   r   é   Z7dr1   Z5dr2   Z4dz5.0fz% r5   z+8.2fzc | r(   ))zMAX QUEUE AHEAD (worst leg)r+   ))r   r   )r   éÐ  )r?   é@  )r@   ç   ¢”mBT)zVOLUME / QUEUE ratior,   ))r   ç      Ð?)rB   r   )r   é   )rC   rA   FZbucketz>18szceiling 3/3z>12sz>8sz	floor 3/3z>10sc                    s:   g | ]2}|  ˆ¡d urˆ|ˆ   kr.ˆ k rn q|‘qS r   )Úgetr-   )Úhir   Úlor   r   r*   í   r   é   g   èvH7Bz,.0fú+r=   z11.0fz+7.2fz9.0fzBOptimistic is the CEILING, queue-aware the FLOOR. A gate that onlyzGworks under the ceiling is not a finding; one that holds under both is.)ÚsysÚargvÚintÚindexÚ
IndexErrorr
   ÚopenÚRESULTSÚcsvZ
DictReaderr   rD   ÚOSErrorÚprintr   r   ÚlistÚQUOTESÚappendÚsortÚitemsÚrsplitÚsortedÚ	enumerateÚSZ_ptr   ÚabsÚminÚmaxÚGATES)0Úlimitr   Zfhr.   ÚvZlegsZtkr:   ZrsÚorderÚoutÚir    ZrecZvolsZr0ÚstartZourZmktZtrZopt_hitZq_hitZfill_pxZcumr+   Zprev_askÚjZrqÚaZt0Út1Zmk_askZaszr&   r'   r(   ZsvZpxZqsr"   Zmkr9   r8   ÚbZlabelZbucketsZ
lo_is_goodÚnamer   )r=   rE   r   r)   rF   r   Úmain5   sD   
04.ÿ



, *





&&
 (ÿ*ÿÿÿ.ÿÿÿÿ
$ÿÿ(
(0ÿÿrk   Ú__main__)Ú__doc__rP   Z
statisticsrI   Úcollectionsr   ÚpathÚinsertZ	mm_settler[   Zqueue_aware_fillr   rT   ÚreplacerO   r_   r   rk   Ú__name__r   r   r   r   Ú<module>   s     I