a
    Q®jj=  ã                   @   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ZdZddd	„Zd
d„ Zedkrxeƒ  dS )aA  Queue-aware fill model: what happens once you stop ignoring the orders ahead?

WHY. Every fill number this project has produced -- historical replays, the live
paper maker, the 0-5c price ladder -- uses the same test: "did any trade print at
or above our ask?" That ignores QUEUE POSITION. In a FIFO book, a buyer lifting
the ask takes the size already resting there first. With 1,749-44,427 contracts
ahead of us at the touch (measured on Kalshi, 2026-07-28 onward), a print at our
price is very often somebody else's fill, not ours.

The bias is DIRECTIONAL, which is what makes it dangerous rather than merely
imprecise:
  - at +0c we join the touch, so the queue ahead is huge -> fills badly inflated
  - at +3c/+5c we are the only order at that price -> fills roughly honest
So the measured fill curve (steep decline from 100%) is flattered at the bottom
and fair at the top. The TRUE curve must be flatter, which changes the answer to
"should we charge more" and inflates the concede-at-T-60 policy specifically,
since conceding puts us exactly where the inflation is worst.

THE MODEL. When we post at price P with Q contracts already resting at P:
    filled once cumulative volume of trades at price >= P (after we post)
    exceeds Q.
Trades at a HIGHER price than ours mean the book walked up through our level, so
they count too.

Q is taken as the depth at the touch at POST time when we join the touch
(our_ask <= market ask), and 0 when we post above the touch (we are first in line
at a price nobody else is showing).

KNOWN LIMITATIONS, stated rather than buried:
  - Q is pessimistic: makers ahead of us can CANCEL, shrinking the real queue.
    So this is a lower bound on fills, as the optimistic model is an upper bound.
    The truth is between them, and the gap is the honest uncertainty.
  - We only have depth at the BEST ask, not the full ladder. For orders above the
    touch we assume nothing is queued at our level, which is optimistic there.
  - Depth logging only began 2026-07-28 17:17Z, so earlier legs cannot be scored.

Usage:  python research\queue_aware_fill.py [YYYY-MM-DD]
é    N)ÚdefaultdictzE:\soccer\mainzE:\soccer\researchz&E:\soccer\research\mm_paper_quotes.csvé@œ  c              
   C   sF  g d }}t |ƒ|k r¦| ddœ}|r,||d< zt d|¡}W n tyR   Y q¦Y n0 | dg ¡}||7 }| d¡}|r¦|s|q¦tdd„ |D ƒdd	�}|r
|r
||kr
q¦q
g }	|D ]‚}
t |
 d
¡¡}|r®|rÔ||krÔq®z>|	 |t	|
 d¡pêdƒt	|
 d¡�p|
 d¡�pdƒf¡ W q® t
tf�y.   Y q®Y q®0 q®|	jdd„ d� |	S )z>[(ts, price, count)] after `since`, paginated back far enough.NéÈ   )ÚtickerÚlimitÚcursorz/markets/tradesZtradesc                 s   s.   | ]&}t  | d ¡¡rt  | d ¡¡V  qdS )Úcreated_timeN)ÚSÚ_ptÚget)Ú.0Úx© r   ú&E:\soccer\research\queue_aware_fill.pyÚ	<genexpr>D   s   ÿztrades_sized.<locals>.<genexpr>)Údefaultr   Zyes_price_dollarsr   Zcount_fpÚcountc                 S   s   | d S )Nr   r   )Úzr   r   r   Ú<lambda>W   ó    ztrades_sized.<locals>.<lambda>©Úkey)ÚlenÚktZ_getÚ	Exceptionr   Úminr	   r
   ÚappendÚfloatÚ	TypeErrorÚ
ValueErrorÚsort)r   ZsinceZcapÚoutr   ÚpÚdÚtrZoldestÚresr   Útr   r   r   Útrades_sized4   s@    



ÿÿ
r'   c                     s´  t tjƒdkrtjd nd} ttƒ}ttdd��Z}t |¡D ]>}|d d d… | kr<| 	d¡r<| 	d¡r<||d	   
|¡ q<W d   ƒ n1 s�0    Y  t| › d
t |ƒ› d�ƒ tdd„ ƒ}| ¡ D �]`\}}|jdd„ d� |d }| 	d¡pôd ¡ süqÆt |d ¡t |d ¡ }‰ t|d ƒ‰t|d ƒ}	tˆd |	d  ƒ}
|
dk �rRqÆˆ|	d k�rlt|d ƒnd}‡ fdd„t||ƒD ƒ}t‡fdd„|D ƒƒ}d}d}|D ]6\}}}|ˆd k�rª||7 }||k�rªd} �qâ�qª||
 }|d  d7  < |d  |7  < |d  |7  < |d   
|¡ qÆtd!ƒ td"d#d$›d%d&d$›d%d'd(›d%d)d*›d%d+d,›�
ƒ d } }}t|ƒD ]º}
||
 }|d }|�r¤t|d  ƒ|d-  nd}td.|
› d/|d0›d%|d › d1|› d%|d | d d2›d3|d › d1|› d%|d | d d4›d3|d5›�ƒ ||7 }||d 7 }||d 7 }�qv|�r td6|d7›d8|› d1|› d9|| d d:›d;|› d1|› d9|| d d:›d<�ƒ td=|| | d d:›d>�ƒ td?ƒ td@ƒ d S )ANé   z
2026-07-29zutf-8)ÚencodingÚtsé
   Zour_askZk_askZ
leg_tickerz: z Kalshi legs with quotes
c                   S   s   dddg dœS )Nr   )ÚnÚoptÚqÚqueuesr   r   r   r   r   r   d   r   zmain.<locals>.<lambda>c                 S   s   | d S )Nr*   r   )r   r   r   r   r   f   r   r   r   Zask_sizeÚ Zkickofféd   ç•Ö&è.>g        c                    s$   g | ]\}}}|ˆ k r|||f‘qS r   r   )r   r&   r"   Úc)Úkor   r   Ú
<listcomp>r   r   zmain.<locals>.<listcomp>c                 3   s    | ]\}}}|ˆ d  kV  qdS )r2   Nr   )r   Ú_r"   )Úourr   r   r   s   r   zmain.<locals>.<genexpr>FTr,   r-   r.   r/   z4FILL RATE: optimistic (ignores queue) vs queue-awarez  Úarmz>5sú ZlegsÚ
optimisticz>11szqueue-awarez>12szmedian queuez>13sé   z  +zc Z5dú/z6.0fz% z7.0fz12.0fz	
  TOTAL Z3dz legs: optimistic z (z.0fz%)  queue-aware z%)z.  => the optimistic model overstates fills by z percentage pointszA
  Optimistic is an UPPER bound; queue-aware is a LOWER bound (itz:  assumes nobody ahead of us cancels). Truth lies between.)r   ÚsysÚargvr   ÚlistÚopenÚQUOTESÚcsvZ
DictReaderr   r   ÚprintÚitemsr    Ústripr	   r
   r   Úroundr'   ÚanyÚsorted)ZdayZrowsZfhÚrZper_armZtkZrsZr0ÚstartZmktr8   Zqueuer$   r:   ZcumZqueued_fillr6   r"   r3   ÚaZtnÚtoZtqr,   Zmedr   )r4   r7   r   Úmain[   sŠ    (2


$ÿ6ÿÿÿÿ(ÿÿÿ
ÿ
rM   Ú__main__)r   )Ú__doc__rB   ZdatetimeZdtr=   Úcollectionsr   ÚpathÚinsertZ	mm_settler	   Zkalshi_traderr   rA   r'   rM   Ú__name__r   r   r   r   Ú<module>   s   &
'>