a
    ômje  ã                   @   s¦   d 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dlmZ dZg d	¢Zg d
¢Zdd„ ZdZdd„ Zdd„ Zdd„ Zedkr¢eƒ  dS )aL  Backtest the GROSS-MARGIN GATE: skip a book entirely unless the market's own
asks already sum to enough to survive a completion.

WHY. Live completions on 2026-07-30/31 showed the mechanism directly: every
completion that collected under ~101c of the payout LOST money once the ~1.3-
1.7c taker fee came off; every one that cleared it WON. "Asks sum above 100c" is
necessary but not sufficient -- a book only pays off if it completes near its
QUOTED price, and most of the time one leg has to be crossed into the BID
instead, giving up the spread on top of the fee. So the gate is applied at
POST TIME, using only information we already have before pricing a single leg:
gross = sum(market asks) - 100c. Skip the whole book below the threshold.

THIS RUNS THE ACTUAL LIVE POLICY (decaying arm + concede at T-60 + complete at
2/3 + flatten at 1/3), scored with the QUEUE-AWARE fill model
(research/queue_aware_fill.py, research/decay_backtest.py): a fill requires
cumulative volume at or above our price, SINCE WE LAST (RE)POSTED, to exceed the
depth resting there when we posted. Reprices reset queue position, matching the
live cancel-replace mechanics. This is a deliberate LOWER bound (assumes nobody
ahead of us ever cancels); see decay_backtest.py for why the optimistic model
(counts any print at our price as a fill) was rejected -- it disagreed with
queue-aware not just in magnitude but in DIRECTION on 2026-07-29's data.

Sweeps GROSS_GATE_C over several days and reports, per threshold: how many books
would have been posted, how many would have completed/flattened/gone empty, and
total P&L -- so the live constant (currently 2.5c) can be checked against
whatever the data actually supports rather than left at a guess.

Usage:  python research\gross_gate_backtest.py [day ...]
        (defaults to every day with queue-depth logging: 07-28, 07-29, 07-30)
é    N)ÚdefaultdictzE:\soccer\mainzE:\soccer\research)Úsimulate)Útrades_sizedz&E:\soccer\research\mm_paper_quotes.csv)z
2026-07-28z
2026-07-29z
2026-07-30)ç        g      ð?g      ø?g       @g      @g      @g      @c                    s>  t tƒ}ttdd��d}t |¡D ]H}|d d d… | kr | d¡r | d¡r | d¡r ||d   |¡ q W d   ƒ n1 s~0    Y  t tƒ}| 	¡ D ]8\}}|j
d	d
„ d� ||f||d d  |d d < q˜dd„ | 	¡ D ƒ}i }| 	¡ D ]D\}}t |d d ¡‰ ‡ fdd„t|t |d d ¡ƒD ƒ||< qð||fS )Nzutf-8)ÚencodingÚtsé
   Zour_askÚk_askZpin_fairZ
leg_tickerc                 S   s   | d S )Nr   © )Úxr
   r
   ú)E:\soccer\research\gross_gate_backtest.pyÚ<lambda>7   ó    zload_day.<locals>.<lambda>)Úkeyr   ZeventZsidec                 S   s"   i | ]\}}t |ƒd kr||“qS )é   ©Úlen©Ú.0ZevÚlegsr
   r
   r   Ú
<dictcomp>9   r   zload_day.<locals>.<dictcomp>Zkickoffc                    s$   g | ]\}}}|ˆ k r|||f‘qS r
   r
   )r   ÚtÚpÚc©Zkor
   r   Ú
<listcomp>>   s   ÿzload_day.<locals>.<listcomp>)r   ÚlistÚopenÚQUOTESÚcsvZ
DictReaderÚgetÚappendÚdictÚitemsÚsortÚSZ_ptr   )ÚdayZrowsZfhÚrÚbyZtkÚrsÚtradesr
   r   r   Úload_day.   s&    (ÿ2"
ÿr+   g      .@c                 C   s   t dd„ |  ¡ D ƒƒd d S )zJsum(market ask at FIRST snapshot) - 100c. What the gate sees at post time.c                 s   s"   | ]\}}t |d  d ƒV  qdS ©r   r	   N©Úfloat©r   Ú_r)   r
   r
   r   Ú	<genexpr>H   r   z gross_at_post.<locals>.<genexpr>éd   )ÚsumÚvalues)r   r
   r
   r   Úgross_at_postF   s    r5   c                 C   s@   t dd„ |  ¡ D ƒƒd }t dd„ |  ¡ D ƒƒd }|| tkS )a  Mirrors the live LIQUIDITY CHECK: reject only absurdly wide books, the
    signature of one nobody has quoted. "Botafogo" summed to 10c of bids against
    243c of asks -- a fake +143c overround from pure illiquidity.

    Do NOT also require sum(bids) < 100c. That was the first version and it was
    backwards: sum(bids) >= 100c means all three legs could be sold into the
    bids for more than the payout -- an arbitrage, and empirically our best
    books. Including it removed every book that cleared a 2.5c gate.c                 s   s"   | ]\}}t |d  d ƒV  qdS )r   Zk_bidNr-   r/   r
   r
   r   r1   T   r   z#coherent_at_post.<locals>.<genexpr>r2   c                 s   s"   | ]\}}t |d  d ƒV  qdS r,   r-   r/   r
   r
   r   r1   U   r   )r3   r4   ÚMAX_SPREAD_C)r   Zbid_sumZask_sumr
   r
   r   Úcoherent_at_postK   s    	r7   c                     sÎ  t jdd … pt} i }| D ]4}t|ƒ\}}||f||< t|› dt|ƒ› d�ƒ qtƒ  tddd›ddd	›dd
d›ddd›ddd›ddd›ddd›ddd›�ƒ tD ]ò‰ d } } } }}	d}
| ¡ D ]l\}\}}‡ fdd„| ¡ D ƒ}|t|ƒ7 }t||dƒ\}}}}}||7 }||7 }||7 }|	|7 }	|
|7 }
qÆ|�rB|
| nt	dƒ}tdˆ d›d|d›d|d›d|d›d|d›d|	d›d|
d›d|d ›d!�ƒ q¢td"t
d#d$„ | ¡ D ƒƒ› d%t| ƒ› d&�ƒ td'ƒ d S )(Né   z: z three-leg books loadedz  Úgatez>5sú Zbooksz>6sÚnatz>4sZcmplÚflatÚnonez   zP&Lz>8sz$/bookz>7sr   r   c                    s*   i | ]"\}}t |ƒrt|ƒˆ kr||“qS r
   )r7   r5   r   ©r9   r
   r   r   h   s   ÿzmain.<locals>.<dictcomp>Zdecay_concedeÚnanz5.1fZ6dZ4dZ5dz+8.2fz$ z+7.3fú$z
  (c                 s   s   | ]\}}t |ƒV  qd S )Nr   )r   Úbr0   r
   r
   r   r1   r   r   zmain.<locals>.<genexpr>z total books available across z days before gating)zD  Live gate is set to 2.5c. Compare its row above against the sweep.)ÚsysÚargvÚDEFAULT_DAYSr+   Úprintr   Ú
THRESHOLDSr#   r   r.   r3   r4   )ZdaysZby_dayr&   r(   r*   Ztot_nZtot_natZtot_cZtot_fZtot_zZtot_pnlZgatedr;   Zcompr<   r=   ZpnlZper_bookr
   r>   r   ÚmainY   sF    ,ÿÿÿ 
,ÿÿÿÿ
rG   Ú__main__)Ú__doc__r   rB   Úcollectionsr   ÚpathÚinsertZ	mm_settler%   Zdecay_backtestr   Zqueue_aware_fillr   r   rD   rF   r+   r6   r5   r7   rG   Ú__name__r
   r
   r
   r   Ú<module>   s$   