a
    ðêžj˜  ã                   @   s  d Z ddlZddlZddlZddlZddlZddlZddlmZ ej	 
ej	 e¡¡Zej	 de¡ ej	 ed¡Zej	 ed¡Zg d¢Ze d¡Zdd	„ Zd
d„ eD ƒZdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zd"dd „Z e!d!k�re "e ƒ ¡ dS )#aX  Book-level dataset: what makes a BOOK complete, rather than a leg fill.

WHY BOOK LEVEL. project_mm_completion_arithmetic reduces the maker to one
number -- the completion rate -- because a complete book is near-deterministic
(+1.78c on Kalshi, SD 1.69) while a partial one is a coin flip at ~25x the SD.
Leg fill rate is an input to that; it is not the thing being decided. A model
fitted on legs answers "will this order fill", which is the wrong question:
three legs filling INDEPENDENTLY is not the same event as a book completing,
because the legs of one book share a market, a moment and a budget.

BUILT FROM mm_fill_dataset.csv, not from the raw log, so it inherits that
file's two corrections: one row per resting order (not per re-post), and rows
dropped before features existed. Run mm_fill_dataset.py first, or just run this
-- it rebuilds automatically.

THE UNIT IS A BOOK WE QUOTED. Features are taken AT OPEN (the first resting
order on each leg), because the question is what could have been known when the
decision to open the book was made. Anything measured later is contaminated by
the outcome: a book that fills one leg gets re-priced by the budget rule, so
its later above_touch and scale are consequences of filling, not causes.

WATCH OUT FOR legs_quoted. A book where only two legs were ever offered CANNOT
complete, and including those in a completion rate silently understates it.
`complete` is defined against 3 legs; filter on legs_quoted==3 when the
question is "given a full book was offered, did it complete".

Usage:  python research\mm_book_dataset.py
Writes: research\mm_book_dataset.csv
é    N)Údefaultdictzmm_fill_dataset.csvzmm_book_dataset.csv)")Úvenuea  'kalshi' or 'polyus'. Both makers quote the same fixtures on different venues with different economics -- Kalshi CHARGES the maker 0.0175*p(1-p), Poly-US CREDITS 0.0125*p(1-p) -- so break-even completion differs and the two must never be pooled without splitting on this.)Úeventz.Event/market identifier -- one match, one row.)ÚleaguezDivision code.)Úts_openz1When the first leg of this book was first posted.)Úhrs_to_ko_opena  Hours to kickoff when the book was opened. LEG fill rate climbs into kickoff (26.1% inside 30min vs 6.8% beyond 24h) but BOOK completion moves the other way: among books that took a leg, with the entry gate held fixed, strand rate is ~17% under 6h against ~9% over it. A late book fills a leg and runs out of time to finish, which is the expensive half. MIN_OPEN_H=6 exists for this.)Úlegs_quotedz~How many of the three legs were ever offered. A book with <3 CANNOT complete -- filter on ==3 for a clean completion question.)Úgross_c_openzªSum of the three asks at open, minus 1.00, in cents. The overround the book was opened on, and the variable the entry gate tests. Blank unless all three legs were quoted.)Úpin_sum_openzpSum of Pinnacle fair probabilities across the legs. Should be ~1.00; deviation flags a stale or mismatched fair.)Úask_max_openz¢Highest leg ask at open -- the favourite. Favourites fill far more often (49.7% vs 17.7% for draws), which is how a book strands short the leg most likely to win.)Úask_min_openz'Lowest leg ask at open -- the longshot.)Úspread_c_meanzcMean ask-minus-bid across the legs at open, in cents. Mostly 1c: the venue prices on a 1-cent grid.)Úqueue_ahead_minzDSmallest queue ahead of us across the legs. The easiest leg to fill.)Úqueue_ahead_maxz_Largest queue ahead of us. The hardest leg -- and a book completes only if its WORST leg sells.)Úbook_volume_openz›Contracts traded across all three legs. The strongest single completion predictor found so far (+0.091 AUC); min-leg volume was null (rho +0.095, p=0.189).)Úleg_volume_minzˆVolume on the thinnest leg. Kept because the paper-era gate used it -- it did NOT replicate live, so treat a result here with suspicion.)Úopen_interest_sumz%Open interest summed across the legs.)Ún_posts_totalzDRe-posts across every leg. A proxy for how long the book was worked.)Úminutes_exposed_maxz'Longest any single leg sat on the book.)Úis_xlow_anyzr1 if the frozen xlow rule fired on this fixture (either side), else 0. Blank if the fixture could not be resolved.)Úis_xhigh_anyzl1 if the frozen xhigh rule fired on this fixture. xhigh overlaps xlow heavily -- not an independent feature.)Úlegs_filledz¹OUTCOME. How many legs filled, 0-3, per the EXCHANGE fill record -- the authority. Maker fills only (post_only, so never taker), which also excludes xlow taker buys on the same tickers.)Úlegs_filled_loga_  The same count derived from the LOCAL fills log, kept for comparison. It undercounts: the log joins on (ticker, price_cents) so a re-priced leg misses, and the log only records while the maker is up. On the 2026-08-28 audit the exchange said 115 books complete and the log-derived figure said 45. A large gap here means fills are being missed locally.)Úfill_sourcezw'exchange' normally; 'log' if the exchange could not be read, in which case legs_filled falls back and will undercount.)ÚcompletezxOUTCOME. 1 if all three legs filled. This is the number the strategy lives or dies on -- break-even was 61.4% on Kalshi.)Úleg_sold_firsta  Which OUTCOME sold first, in 1X2 terms: '1' home, '2' away, 'X' draw. Blank when no leg filled, or when the abbreviation cannot be resolved against the event code. Derived from first_fill_side, which carries the Kalshi leg abbreviation ('CAT') rather than a side -- readable only if you know which team that was. A Kalshi event ticker ends in the two team codes concatenated (26AUG17GEMCAT = GEM at home to CAT), so the abbreviation is matched against that pair: prefix means home, suffix means away, TIE means draw.)Úfirst_fill_sidez=Leg abbreviation of the first leg to fill, blank if none did.)Úfirst_fill_secsz1Seconds from that leg being posted to it filling.)ÚsizezøContracts per leg the maker was working, from the largest leg. SIZE went 1 -> 3 on 2026-08-23 and mixing the two eras is a trap: a size-1 completion pays ~+$0.05 and a size-3 one ~+$0.20, so an average across both understates a good book threefold.)Úshapeaz  OUTCOME, stricter than `complete`. 'unfilled' = quoted but never touched. 'clean' = three legs at the SAME size, the only shape that is actually hedged. 'ragged' = three legs at different sizes (a leg that took a 0.01-contract fill and never finished still reads complete). 'over' = a leg exceeded size, which means two orders rested at once. 'stranded' = fewer than three legs.)Ú	has_takeraW  1 if WE traded this event as a taker -- xlow, or a manual trade. The maker is post_only so it never takes. Books with this set have P&L that is not the maker own: it is the difference between a -$3.22 maker and a -$53.05 account. NOT the same as is_xlow_any, which only says the SIGNAL fired (169 books) rather than that a trade happened (13).)ÚarmzúWhich pricing arm owned the book: 'budget' (a part-filled leg prices at exactly what the book still owes) or 'latch3' (the ratchet survives the fill but sits at most 3c above that budget). Blank for books opened before the split. From mm_arm_log.csv.)Úsettledz.1 once every leg has settled and pnl is final.)ÚpnlzùOUTCOME. Realised dollars, from the venue settlement records (revenue - cost - fees) summed across the legs. Blank until settled. This is the column every P&L question should be answered from; reconstructing it by hand is where the errors came from.)Úpremium_over_budget_medzðMedian cents a part-filled leg was offered ABOVE what the book still needed, over the book's life. 0 under the 'budget' arm by construction; the old unbounded latch ran a median +1c with a tail to +54c, and that tail is what stranded books.z^\d{2}[A-Z]{3}\d{2}c                 C   sŽ   |sdS t |ƒ ¡  ¡ }|dv r$dS t | p,dƒ dd¡d  ¡ }t d|¡}|rX||vr\dS | |¡| |¡ }}|r~|s~dS |rŠ|sŠdS dS )	a	  '1' / '2' / 'X' for the leg abbreviation, or '' if it cannot be resolved.

    A Kalshi event ticker is SERIES-<date><HOME><AWAY>, e.g.
    KXARGPREMDIVGAME-26AUG17GEMCAT: GEM at home to CAT. So stripping the date
    leaves the two abbreviations concatenated, and the leg is home if it is the
    prefix and away if it is the suffix.

    Returns '' rather than guessing when both or neither match -- a code like
    'AAA' vs leg 'A' is genuinely ambiguous, and a wrong side here would be
    invisible in the data.
    Ú )ZTIEZDRAWÚXr&   ú-é   éÿÿÿÿÚ1Ú2)ÚstrÚupperÚstripÚrsplitÚ_DATE_REÚsubÚ
startswithÚendswith)r   ÚlegÚtailZpairZstartsZends© r6   úresearch/mm_book_dataset.pyÚ
leg_to_1x2¤   s    r8   c                 C   s   g | ]\}}|‘qS r6   r6   )Ú.0ÚcÚ_r6   r6   r7   Ú
<listcomp>Á   ó    r<   c              	   C   s(   z
t | ƒW S  ttfy"   Y d S 0 d S ©N)ÚfloatÚ	TypeErrorÚ
ValueError©Úvr6   r6   r7   Ú_fÄ   s    
rD   c               
   C   sd  zBt j dtj tdd¡¡ ddl} |  ddddi¡ d¡p>g }W nB t	y„ } z*t
d	t|ƒj› d
|› d�ƒ W Y d}~dS d}~0 0 ttƒ}|D ]È}t| dd¡ƒ ¡ dks’| d¡rºq’t| dd¡ƒ ¡ dkrÔq’| d¡pàd}d|vrìq’| dd¡\}}t| d¡ƒ�pdt| d¡ƒ }}	||  |d|	f¡\}
}|
| |	du�rL|	n|f|| |< q’t|ƒS )aT  event -> {leg: (qty, price)} from Kalshi's OWN fill record.

    WHY NOT THE LOCAL LOG. `filled` in the leg dataset is a join of
    mm_live_realfills.csv on (ticker, price_cents) PLUS a time window. Both
    halves lose fills:
      * the price key misses a leg that was re-priced between the resting order
        going on and the fill being recorded;
      * the local log is itself incomplete -- 354 legs against 391 the exchange
        reports, because the fill detector only runs while the maker is up.
    Audited 2026-08-28: the exchange said 115 books completed, the dataset said
    45. Completion is the one number this strategy is judged on, so it cannot
    be derived from a lossy local join.

    Maker fills only: our orders are post_only, so `is_taker` is always false
    and the side is never 'yes'. That is the same filter mm_maker_live uses to
    attribute its own fills, and it excludes xlow's taker buys on the same
    tickers.

    Returns None if the exchange cannot be read, so the caller can fall back to
    the log rather than silently reporting every book as incomplete.
    r   ú..ÚmainNú/portfolio/fillsÚfillsÚlimitéÈ   z$  [warn] exchange fills unreadable (ú: z&); falling back to the local fills logÚactionr%   ÚsellÚis_takerÚsideZyesÚtickerr'   r(   Zcount_fpç        Zyes_price_dollars)ÚsysÚpathÚinsertÚosÚjoinÚHEREÚkalshi_traderÚ_get_allÚgetÚ	ExceptionÚprintÚtypeÚ__name__r   Údictr,   Úlowerr/   rD   )ÚktÚrowsÚeÚoutÚfÚtÚevr4   ÚqÚpxZprev_qZprev_pxr6   r6   r7   Úexchange_fillsË   s6    ÿÿÿ"$$rj   c               	   C   sš   zrt j dtj tdd¡¡ ddl} g }dD ]B}z&||  ddd|d	œ¡ d¡pPg 7 }W q, t	yl   Y q,Y q,0 q,W n t	yŠ   t
ƒ  Y S 0 d
d„ |D ƒS )a  Events where WE traded as a taker -- xlow, or a manual trade.

    The maker is post_only so it never takes. An event with a taker fill has
    P&L that is not the maker's, and conflating the two is how a -$3.22 maker
    was reported as losing $53 for most of a day.
    r   rE   rF   N©r   r(   rG   rH   rJ   ©rI   Z
subaccountc                 S   sB   h | ]:}|  d ¡rd|  d¡p dv r|  d¡p0d dd¡d ’qS )rN   r'   rP   r%   r(   r   )rZ   r/   )r9   re   r6   r6   r7   Ú	<setcomp>  s   ÿztaker_events.<locals>.<setcomp>)rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   Úset)ra   rb   Ú_subr6   r6   r7   Útaker_eventsú   s(    
ÿþþÿrp   c               	   C   sT  zrt j dtj tdd¡¡ ddl} g }dD ]B}z&||  ddd|d	œ¡ d¡pPg 7 }W q, t	yl   Y q,Y q,0 q,W n t	yˆ   i  Y S 0 t
d
d„ ƒ}|D ]¦}| d¡pªd}d|vr¶qš| dd¡\}}t| d¡ƒpÖdd }t| d¡ƒpìdt| d¡ƒ� pþd }	|| }
|
d  ||	 t| d¡ƒ�p*d 7  < |
d  |¡ qšdd„ | ¡ D ƒS )a;  event -> (realised dollars, all_legs_settled) from the venue's own books.

    revenue - cost - fees, per leg, summed. This is the authority: every P&L
    figure should come from here rather than being rebuilt from fill prices,
    which is where the size-1/size-3 mixing and the taker contamination crept in.
    r   rE   rF   Nrk   z/portfolio/settlementsZsettlementsi,  rl   c                   S   s
   dt ƒ gS )NrQ   )rn   r6   r6   r6   r7   Ú<lambda>/  r=   zsettled_pnl.<locals>.<lambda>rP   r%   r'   r(   ZrevenuerQ   ç      Y@Zno_total_cost_dollarsZyes_total_cost_dollarsZfee_costc                 S   s(   i | ] \}}|t |d  dƒ|d f“qS )r   é   r(   )Úround)r9   rg   rC   r6   r6   r7   Ú
<dictcomp>E  r=   zsettled_pnl.<locals>.<dictcomp>)rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r   r/   rD   ÚaddÚitems)ra   rb   ro   ÚaggÚrrf   rg   r4   ZrevZcostÚar6   r6   r7   Úsettled_pnl  s:    
ÿþþ
&(r{   c                  C   sh   t j td¡} t j | ¡si S h d£}i }t| ƒD ]0}| d¡r2| d¡|v r2| |d |d ¡ q2|S )z:event -> pricing arm, from the append-only assignment log.zmm_arm_log.csv>   ÚbudgetZlatch3Ztieloadr   r!   )rU   rS   rV   rW   ÚexistsÚ_readrZ   Ú
setdefault)rS   Zvalidrd   ry   r6   r6   r7   Úarm_ofH  s    
r€   c                  C   s¨  t j td¡} t j | ¡si S ttƒ}t| dƒ��,}| ¡  	dd¡ 
dd¡ ¡  d¡}|D ]ô}| 	dd¡}z*tt|tt t | 
dd¡¡¡ƒƒƒ}W n tyª   Y qZY n0 | d¡d	kr¼qZt| d
¡ƒt| d¡ƒ }}t| d¡ƒt| d¡ƒ }}	d||||	fv sZ|dk�rqZ|	dk�r&||	 n|}
|| d¡  t|d |
 d ƒ¡ qZW d  ƒ n1 �sf0    Y  i }| ¡ D ]&\}}| ¡  |t|ƒd  ||< �q||S )zÚevent -> median cents a PART-FILLED leg was offered above its budget.

    The whole subject of the arm test. Recomputed from the leg log because
    nothing else records what the book was actually asked to fetch.
    zmm_live_legs.csvÚrbó    r=   úutf-8Úreplaceú,Zliver*   Z	collectedZprice_centsÚ	touch_askZscaleNr   ç      ð?r   rr   éd   é   )rU   rS   rV   rW   r}   r   ÚlistÚopenÚreadliner„   Údecoder.   Úsplitr_   ÚzipÚnextÚcsvÚreaderÚioÚStringIOr[   rZ   rD   Úappendrt   rw   ÚsortÚlen)rS   ÚperÚfhZhdrÚlinery   Úcolri   ZtouchZscr|   rd   rg   rC   r6   r6   r7   Úbudget_premium^  s6    "
ÿ
Frœ   c                  C   sä   zBt j dtj tdd¡¡ ddl} |  ddddi¡ d¡p>g }W n t	yX   i  Y S 0 i }|D ]|}t
| d	d
¡ƒ ¡ dksb| d¡rŠqb| d¡p–d
}d|vr¢qb| dd¡d | d¡p¼d
 }}||vsÖ||| k rb|||< qb|S )zGevent -> earliest maker fill timestamp. Used to place backfilled books.r   rE   rF   NrG   rH   rI   rJ   rL   r%   rM   rN   rP   r'   r(   Zcreated_time)rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r,   r`   r/   )ra   rb   rd   re   rf   rg   Útsr6   r6   r7   Ú
fill_times€  s.    ÿÿÿ
" 
rž   c              	   C   s2   t | dƒ ¡  dd¡}tt t | dd¡¡¡ƒS )Nr�   r‚   r=   rƒ   r„   )	r‹   Úreadr„   rŠ   r‘   Z
DictReaderr“   r”   r�   )rS   Úrawr6   r6   r7   r~   –  s    r~   c                  C   sr  t j td¡} t j | ¡sg S z&tj dt¡ ddl}| ¡ p@i }W nD t	yˆ } z,t
dt|ƒj› d|› d�ƒ i }W Y d}~n
d}~0 0 tdd„ ƒ}t| ƒD ]>}| d	¡p®d
}d|vrºqž| dd¡\}}|| |  |¡ qžg }	| ¡ D �]€\}}
dd„ |
 ¡ D ƒ}dd„ | ¡ D ƒ}dd„ |D ƒ}t|ƒdk�rDt|ƒd d nd}t| |¡�pXi  ¡ ƒ}dd„ | ¡ D ƒ}|	 d||tt|ƒƒ  d¡�p”d
dd… tdd„ |
 ¡ D ƒƒdt|ƒ|du�rÊ|d›nd
d
|�rÜt|ƒnd|�rìt|ƒnd|�rdt|ƒ t|ƒ d›nd
dddddtdd„ |
 ¡ D ƒƒdd
d
t|ƒt|ƒ|�rHdndt|ƒdk�r\dndd
d
d
d œ¡ qê|	S )!aQ  Poly-US books as rows in the same shape, from its own logs + venue record.

    FEWER FEATURES ON PURPOSE. pus_live_legs.csv records ts/slug/side/price/
    touch/above_touch/gross/collected/need -- it has no volume, queue depth,
    open interest or Pinnacle fair, because that maker was written to a
    narrower log. Those columns come out BLANK rather than zero: a model that
    reads 0 for "queue depth unknown" is being lied to.

    Completion comes from the VENUE's settlement record, same as the Kalshi
    side, for the same reason -- the local state stops writing during 503s.
    zpus_live_legs.csvr   Nz)  [warn] poly-US settlement unavailable (rK   ú)c                   S   s   t tƒS r>   )r   rŠ   r6   r6   r6   r7   rq   ²  r=   zpolyus_books.<locals>.<lambda>Úslugr%   r'   r(   c                 S   s&   i | ]\}}|t |d d„ d�d “qS )c                 S   s   |   dd¡S )Nr�   r%   ©rZ   ©Úxr6   r6   r7   rq   ¼  r=   z)polyus_books.<locals>.<dictcomp>.<lambda>©Úkeyr   )Úsorted)r9   ZlgrC   r6   r6   r7   ru   ¼  s   ÿz polyus_books.<locals>.<dictcomp>c                 S   s   g | ]}t | d ¡ƒ‘qS )r†   ©rD   rZ   ©r9   ry   r6   r6   r7   r<   ¾  r=   z polyus_books.<locals>.<listcomp>c                 S   s   g | ]}|d ur|‘qS r>   r6   ©r9   rz   r6   r6   r7   r<   ¿  r=   é   r‡   rr   c                 S   s0   g | ](}t | d ¡ƒpdt | d¡ƒp(d ‘qS )r†   r   Z	touch_bidr©   rª   r6   r6   r7   r<   Â  s   ÿZpolyusr   é   c                 s   s$   | ]}|D ]}|  d d¡V  q
qdS )r�   r%   Nr£   )r9   rC   ry   r6   r6   r7   Ú	<genexpr>È  r=   zpolyus_books.<locals>.<genexpr>ú.2frˆ   c                 s   s   | ]}t |ƒV  qd S r>   )r—   ©r9   rC   r6   r6   r7   r®   Ô  r=   ÚexchangeÚlog)r   r   r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )rU   rS   rV   rW   r}   rR   rT   Zpus_maker_pnlZsettled_booksr[   r\   r]   r^   r   r~   rZ   r/   r•   rw   Úvaluesr—   ÚsumrŠ   Úkeysr�   ÚiterÚminÚmax)Zlegs_csvÚPr"   rc   r˜   ry   r¢   rg   r4   rd   ÚlegsÚfirstsÚasksÚgrossÚfilledZspreadsr6   r6   r7   Úpolyus_books›  sr    ÿ"ÿ"ÿè
r¿   Tc           !   (      sd  | r:t j t¡stdƒ tjtjt j 	t
d¡gdddd� tƒ }tƒ }tƒ }tƒ }tƒ }ttƒ}ttƒ}|D ] ‰ˆ d¡rl|ˆd   ˆ¡ qlg }| ¡ D �]ü\}	}
i }t|
dd„ d	�D ]‰| ˆ d
d¡g ¡ ˆ¡ q¸dd„ | ¡ D ƒ‰‡fdd„}tˆƒ}dd„ ˆ ¡ D ƒ}dd„ |D ƒ}|dk�rFt|ƒdk�rFt|ƒd d nd}dd„ | ¡ D ƒ}|du �rr|d }}nt| |	¡�p‚i  ¡ ƒd }}d}t|
dd„ d	�D ]4‰ˆ d¡dk�r¤tˆ d¡ƒdu�r¤ˆ} �qÚ�q¤‡fdd„}t|�pði  |	i ¡ƒ}|�r&td d!„ |�pi  |	i ¡ ¡ D ƒƒng }|�r@|t|ƒd"  nd#‰ |�sPd$}nRt|ƒdk �rdd%}n>t‡ fd&d!„|D ƒƒ�r‚d'}n |d( |d)  d*k�ržd+}nd,}td-d!„ |
D ƒƒ}| d.|	t t!ˆ ¡ ƒƒ d/d¡||d0t"ƒ||du�rð|d1›nd|dk�r td2d!„ d3d„ ˆ ¡ D ƒD ƒƒd4›nd|d5t"ƒ|d5tƒ|d6d7d„ ƒdu�rX|d6d8d„ ƒd1›nd|d9tƒ|d9t"ƒ|d:t"ƒ|d;tƒ|d<tƒtd=d!„ |
D ƒƒ|d>t"ƒ|d?ƒ|d@ƒt|ƒt|ƒ|t|ƒdk�rÆdAnd)t#|	|�rÜ| d
¡ndƒ|�rò| d
d¡nd|�r| dd¡ndˆ �rˆ dB›nd||	|v �r(dAnd)| |	d¡|	|v �rZ|�rZ|||	 dA k�rZdAn|	|v �rhd)nd|	|v �r„||	 d) d4›nd| |	d¡dCœ"¡ qšdDdE„ |D ƒ}t$ƒ }|�p¶i  ¡ D �]r\}	}
|	|v �s¼|
�sÚ�q¼tdFd!„ |
 ¡ D ƒƒ}|�r|t|ƒd"  nd#‰|�sd$}nRt|ƒdk �r*d%}n>t‡fdGd!„|D ƒƒ�rHd'}n |d( |d)  d*k�rdd+}nd,}| d.|	d| |	d¡t|
ƒt|
ƒddHt|
ƒdk�rždAnd)ˆ�r®ˆdB›nd||	|v �rÀdAnd)| |	d¡|	|v �rðt|
ƒ||	 dA k�rðdAn|	|v �rþd)nd|	|v �r||	 d) d4›nd| |	d¡dIœ¡ �q¼| %t&ƒ ¡ |j'dJd„ d	� t(t)dKddLdM��J}t*j+|t,dN�}| -¡  |D ]‰| .‡fdOd„t,D ƒ¡ �qzW d  ƒ n1 �s°0    Y  dPd„ |D ƒ}dQd„ |D ƒ} tdRt)› �ƒ tdSt|ƒ› �ƒ tdTt|ƒ› �ƒ tdUt| ƒ› �|�r:dVdWt| ƒ t|ƒ dX›dY�nd ƒ tdZt j /t)¡d[ d1›d\�ƒ d)S )]a
  rebuild=False when the caller has ALREADY refreshed the leg dataset.

    The dashboard rebuilds mm_fill_dataset itself before embedding, so letting
    this re-run it as a subprocess would parse ~350k log rows twice on every
    page build for the same answer.
    z&leg dataset missing; building it firstzmm_fill_dataset.pyTi  )Zcapture_outputÚtextZtimeoutr   c                 S   s   |   dd¡S ©NÚts_firstr%   r£   r¤   r6   r6   r7   rq   ÿ  r=   zmain.<locals>.<lambda>r¦   rO   r%   c                 S   s   i | ]\}}||d  “qS )r   r6   ©r9   ÚsrC   r6   r6   r7   ru     r=   zmain.<locals>.<dictcomp>c                    s4   ‡ fdd„ˆ  ¡ D ƒ}dd„ |D ƒ}|r0||ƒS d S )Nc                    s   g | ]}t | ˆ ¡ƒ‘qS r6   r©   rª   ©Únamer6   r7   r<     r=   z%main.<locals>.col.<locals>.<listcomp>c                 S   s   g | ]}|d ur|‘qS r>   r6   r°   r6   r6   r7   r<     r=   )r³   )rÆ   rx   Úvals©r»   rÅ   r7   r›     s    zmain.<locals>.colc                 S   s   g | ]}t | d ¡ƒ‘qS )Úask_at_postr©   rª   r6   r6   r7   r<   	  r=   zmain.<locals>.<listcomp>c                 S   s   g | ]}|d ur|‘qS r>   r6   r«   r6   r6   r7   r<   
  r=   r¬   r‡   rr   Nc                 S   s&   g | ]\}}t d d„ |D ƒƒr|‘qS )c                 s   s   | ]}|  d ¡dkV  qdS )r¾   r*   Nr£   ©r9   r¥   r6   r6   r7   r®     r=   z"main.<locals>.<listcomp>.<genexpr>)ÚanyrÃ   r6   r6   r7   r<     s   ÿr²   r±   c                 S   s   |   dd¡S rÁ   r£   r¤   r6   r6   r7   rq     r=   r¾   r*   Zseconds_to_fillc                    sF   ‡ fdd„ˆ  ¡ D ƒ}tdd„ |D ƒƒr,dS tdd„ |D ƒƒrBdS dS )	Nc                    s   g | ]}|  ˆ ¡‘qS r6   r£   rª   rÅ   r6   r7   r<     r=   z)main.<locals>.anyflag.<locals>.<listcomp>c                 s   s   | ]}|d kV  qdS )r%   Nr6   r°   r6   r6   r7   r®      r=   z(main.<locals>.anyflag.<locals>.<genexpr>r%   c                 s   s   | ]}|d kV  qdS )r*   Nr6   r°   r6   r6   r7   r®   "  r=   r(   r   )r³   ÚallrË   )rÆ   rÇ   rÈ   rÅ   r7   Úanyflag  s    zmain.<locals>.anyflagc                 s   s   | ]\}}|V  qd S r>   r6   ©r9   rh   r;   r6   r6   r7   r®   '  r=   zmain.<locals>.<genexpr>r‰   rQ   ZunfilledZstrandedc                 3   s   | ]}|ˆ d  kV  qdS ©ç�íµ ÷Æ°>Nr6   ©r9   rh   )Ú_sizer6   r7   r®   0  r=   Zoverr)   r   rÐ   ZraggedZcleanc                 s   s   | ]}|  d d¡V  qdS )rÂ   r%   Nr£   rª   r6   r6   r7   r®   7  r=   Zkalshir   Z	hrs_to_kor¯   c                 s   s   | ]}|d ur|V  qd S r>   r6   rÊ   r6   r6   r7   r®   @  r=   c                 S   s   g | ]}t | d ¡ƒ‘qS )Zpin_fairr©   rª   r6   r6   r7   r<   @  r=   z.4frÉ   Zspread_cc                 S   s   t | ƒt| ƒ S r>   ©r´   r—   rB   r6   r6   r7   rq   E  r=   c                 S   s   t | ƒt| ƒ S r>   rÓ   rB   r6   r6   r7   rq   D  r=   Zqueue_aheadZbook_volumeZvolumeZopen_interestc                 s   s$   | ]}t t| d ¡ƒpdƒV  qdS )Zn_postsr   N)ÚintrD   rZ   rª   r6   r6   r7   r®   K  r=   Zminutes_exposedZis_xlowZis_xhighr(   Úg)"r   r   r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   c                 S   s   h | ]}|d  ’qS )r   r6   rª   r6   r6   r7   rm   r  r=   zmain.<locals>.<setcomp>c                 s   s   | ]\}}|V  qd S r>   r6   rÎ   r6   r6   r7   r®   w  r=   c                 3   s   | ]}|ˆ d  kV  qdS rÏ   r6   rÑ   )Úszr6   r7   r®   }  r=   z!exchange (backfilled, no leg log))r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   c                 S   s   | d p
dS )Nr   r%   r6   ©ry   r6   r6   r7   rq   —  r=   Úwrƒ   )ÚnewlineÚencoding)Z
fieldnamesc                    s*   i | ]"}|ˆ   |¡d u rdnˆ   |¡“qS )Nr%   r£   )r9   Úkr×   r6   r7   ru   œ  r=   c                 S   s   g | ]}|d  dkr|‘qS )r   r¬   r6   rª   r6   r6   r7   r<   ž  r=   c                 S   s   g | ]}|d  r|‘qS )r   r6   rª   r6   r6   r7   r<   Ÿ  r=   zwrote z  books            : z  full 3-leg books : z  completed        : z  (rˆ   z.1fz%)z  size             : g    €„.Az MB)0rU   rS   r}   ÚLEGS_DSr\   Ú
subprocessÚrunrR   Ú
executablerV   rW   rj   rp   r{   r€   rœ   r~   r   rŠ   rZ   r•   rw   r¨   r   r—   r³   r´   rµ   rD   rn   rË   r·   r�   r¶   r¸   r8   rž   Úextendr¿   r–   r‹   ÚOUTr‘   Z
DictWriterÚOUT_COLSZwriteheaderZwriterowÚgetsize)!ZrebuildÚexZtakZstlZarmsZpremrb   Zbooksrd   rg   rº   Zby_legr›   Zn_legsr¼   r½   Z
log_filledZfilled_legsÚsrcZffrÍ   Z_heldZ_qtyZ_shaper   Ú_seenZ_ftZcsr   r™   rØ   ZfullZcompr6   )rÒ   r»   ry   rÖ   r7   rF   á  s   ÿ
,
$
.ÿ(ÿ
&
×
:
$
ð<&ÿrF   Ú__main__)T)#Ú__doc__r‘   r“   rU   ÚrerÝ   rR   Úcollectionsr   rS   ÚdirnameÚabspathÚ__file__rW   rT   rV   rÜ   rá   Z
FIELD_DOCSÚcompiler0   r8   râ   rD   rj   rp   r{   r€   rœ   rž   r~   r¿   rF   r^   Úexitr6   r6   r6   r7   Ú<module>   s8   u
/0"F
 I
