a
    jb¨jd$  ã                   @   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ZdZdZ	ej
 ej
 e¡¡Zej
 ed¡ZdZdZdd	d
„Zdd„ Zdd„ Zdd„ Zedkr¤e eƒ ¡ dS )a0  Separate real market makers from patient directional traders, then rank them.

(read-only; touches no account and places nothing)

THE PROBLEM THIS SOLVES. `maker_share` only means "the order was resting when it
got hit", which a whale building a position satisfies exactly as well as a
market maker. That contaminated the earlier ranking: the top wallets by P&L were
1.00 legs / 0% all-three and made seven figures on a single match, which is a
directional bet, not making.

THE DISCRIMINATOR. A market maker works BOTH SIDES of the same token -- buying
and selling it repeatedly and carrying little net exposure. A directional trader
only ever accumulates. So per wallet, per token:

    flip     = min(buy_qty, sell_qty) / max(buy_qty, sell_qty)   ~1 maker, ~0 directional
    net_exp  = |net position| / gross volume                      ~0 maker, ~1 directional

P&L is settlement-aware: cash flow plus net position valued at gamma
outcomePrices. That is robust to SPLIT/MERGE even though those never appear as
trades -- a split's $1 cost equals the settlement liability of the phantom
-1 Yes / -1 No position it creates, because p_yes + p_no = 1. (I previously
claimed split/merge broke this accounting. It does not.)

ONLY COMPLETE-HISTORY MATCHES are used: /trades refuses offset > ~10500, and a
truncated market returns its most recent rows -- a settlement-adjacent slice of
0.999/0.001 cleanup that would make everyone look one-sided and profitable.

STILL FILLS, NEVER QUOTES. Polymarket's CLOB is off-chain, so resting orders are
public nowhere. "legs" means legs FILLED.
é    Nz https://gamma-api.polymarket.comzhttps://data-api.polymarket.comzpm_maker_twosided.csviô  i'  é   c              	   C   sˆ   t |ƒD ]z}ztj| |dd�}W n( tyH   t d|d  ¡ Y qY n0 |jdkr`| ¡   S |jdkrp d S t d|d  ¡ qd S )Né   )ÚparamsZtimeoutg333333ó?é   éÈ   é�  )ÚrangeÚrequestsÚgetÚ	ExceptionÚtimeÚsleepZstatus_codeÚjson)Zurlr   ZtriesÚiÚr© r   úresearch/pm_maker_twosided.pyÚ_get0   s    

r   c                 C   sr   g d }}|t k rn| t|dœ}|s*d|d< tt› d�|ƒ}|s@qn||7 }|t|ƒ7 }t|ƒtk rbqnt d¡ q
|S )Nr   )ÚmarketÚlimitÚoffsetÚfalseÚ	takerOnlyú/tradesçš™™™™™¹?)Ú
OFFSET_CAPÚPAGEr   ÚDATAÚlenr   r   )ÚcidZ
taker_onlyÚrowsÚoffÚpÚdr   r   r   Útrades>   s    
r$   c              
   C   s¾   g }dD ]°}t t› d�d|dddddœƒ}|s2 qº|D ]€}| d	¡pFg }t|ƒd
ks6d| d¡pbd ¡ vrlq6tdd„ |D ƒƒs€q6tdd„ |D ƒƒr”q6| |¡ t|ƒ| kr6|    S q6q|S )N)r   éd   r   i,  r   z/eventsr%   ZsoccerÚtrueZvolumer   )r   r   Ztag_slugÚclosedÚorderZ	ascendingÚmarketsé   z vsÚtitleÚ c                 s   s   | ]}|  d ¡V  qdS )ÚoutcomePricesN©r
   ©Ú.0Úmr   r   r   Ú	<genexpr>Z   ó    z#complete_matches.<locals>.<genexpr>c                 s   s2   | ]*}t t› d �| d¡dtd ddœƒV  qdS )r   ÚconditionIdr   r   r   )r   r   r   r   N)r   r   r
   r   r/   r   r   r   r2   ]   s   ý

ÿÿ)r   ÚGAMMAr
   r   ÚlowerÚallÚanyÚappend)ÚnÚoutr!   ÚevsÚeZmsr   r   r   Úcomplete_matchesN   s.    
ÿÿ"ý
r>   c            (         sú  t tjƒdkrttjd ƒnd} t| ƒ}tt |ƒ› d�ƒ t dd„ ¡}|D �]h}| d¡p^d 	dd	¡ 
¡ }td
|d d… d›�ddd� d}|d D �]
}| d¡}zdd„ t | d¡¡D ƒ}W n tyÚ   Y q–Y n0 t|dƒ}	dd„ t|dƒD ƒ}
|t |	ƒ7 }|	D �]”}|d }z@t| d¡�p*dƒ}t| d¡�p>dƒ}t| d¡�pRdƒ}W n ttf�yv   Y �q
Y n0 ||f}|| ‰ |d |f|
v �r¬ˆ d  d7  < nˆ d  d7  < ˆ d  | d ¡¡ ˆ d! | d ¡  |¡ |t |ƒk �rþ|| nd"ˆ d# |< | d$¡�pd ¡ d%k�rbˆ d& |  |7  < ˆ d'  || 8  < ˆ d( |  |7  < n<ˆ d) |  |7  < ˆ d'  || 7  < ˆ d( |  |8  < �q
q–td*|d+›d,�ƒ qLg }| ¡ D �]\}‰ ˆ d ˆ d  }|d-k �sÄˆ d | d.k �rþ�qÄtˆ d& ƒtˆ d) ƒB }g g d"  }}}d}|D ]”}ˆ d&  |d"¡ˆ d)  |d"¡ }}|| }||7 }|dk�r€|dk�r€|d7 }| t||ƒdk�r¨t||ƒt||ƒ nd"¡ | t|| ƒ¡ �q.t‡ fd/d0„ˆ d(  ¡ D ƒƒ}d1d„ ˆ d!  ¡ D ƒ}| |tˆ d' | d2ƒ|tˆ d | d3ƒt |ƒ|�r>t|t |ƒ d3ƒnd|�r\tt|ƒt |ƒ d3ƒnd|�rvtt|ƒ| d3ƒnd4t|ƒt ˆ d ƒ|�r¤tt|ƒt |ƒ d2ƒnd|�rÌttd5d0„ |D ƒƒt |ƒ d2ƒndd6œ¡ �qÄ|jd7d„ d8� ttd9dd:d;��<}t j!|t"|d  #¡ ƒd<�}| $¡  | %|¡ W d   ƒ n1 �s>0    Y  td=t |ƒ› d>t› d?�ƒ d@d„ |D ƒ} dAd„ |D ƒ}!dBdC„ }"tdDƒ |"|dEƒ |"| dFƒ |"|!dGƒ | �rötdHƒ tdIdJ ƒ t&| dKd„ d8�d dL… D ]@}#tdM|#dN |#dO |#dP |#dQ |#dR |#dS d-|#dT  f ƒ �qÞdUd„ | D ƒ}$dVd„ | D ƒ}%tdWƒ dX|$fdY|%ffD ] \}&}'|'�rTtdZ|&t |'ƒtd[d0„ |'D ƒƒt |'ƒ td\d0„ |'D ƒƒt |'ƒ td]d0„ |'D ƒƒt |'ƒ d-td^d0„ |'D ƒƒ t |'ƒ td_d0„ |'D ƒƒt |'ƒ f ƒ �qTdS )`Nr   é
   z! complete-history soccer matches
c                
   S   s2   t  t¡t  t¡dt  t¡i ddt  t¡tƒ dœ	S )Nç        r   )	ÚbuyÚsellÚcashÚposÚ	settle_pxÚmkÚtkÚlegsÚmatches)ÚcollectionsÚdefaultdictÚfloatÚsetr   r   r   r   Ú<lambda>m   s
    
üzmain.<locals>.<lambda>r+   r,   ÚasciiÚreplaceú  é2   z<50T)ÚendÚflushr   r)   r4   c                 S   s   g | ]}t |ƒ‘qS r   )rL   ©r0   Úxr   r   r   Ú
<listcomp>z   r3   zmain.<locals>.<listcomp>r-   Fc                 S   s   h | ]}|d  |d f’qS )ÚtransactionHashÚproxyWalletr   )r0   Útr   r   r   Ú	<setcomp>~   r3   zmain.<locals>.<setcomp>rY   ÚsizeZpriceZoutcomeIndexrX   rG   rF   rI   ZslugrH   r@   rE   ZsideZBUYrA   rC   rD   rB   ú z>6z rowsr%   ç333333ã?c                 3   s&   | ]\}}|ˆ d    |d¡ V  qdS )rE   r@   Nr.   )r0   ÚkÚq©Úsr   r   r2   ¦   r3   zmain.<locals>.<genexpr>c                 S   s   g | ]}t |ƒ‘qS r   )r   )r0   Úvr   r   r   rW   §   r3   é   r*   g      ð?c                 s   s   | ]}|d krdV  qdS )r*   r   Nr   rU   r   r   r   r2   ´   r3   )ÚwalletÚpnlÚfillsZmaker_shareÚtokensZtwo_sided_shareÚflipÚnet_exposureÚgross_volumerI   Ú	mean_legsÚ
all3_sharec                 S   s
   | d  S ©Nrf   r   ©r   r   r   r   rN   ¶   r3   )ÚkeyÚwzutf-8)ÚnewlineÚencoding)Z
fieldnamesz
wrote z wallets -> Ú
c                 S   s(   g | ] }|d  dkr|d dkr|‘qS )ri   g333333Ó?rj   r^   r   ©r0   r   r   r   r   rW   ½   r3   c                 S   s   g | ]}|d  dk r|‘qS )ri   r   r   ru   r   r   r   rW   ¾   r3   c                 S   s¤   | st d|› d�ƒ d S dd„ | D ƒ}tdd„ | D ƒƒt| ƒd  }t d|t| ƒd	t|ƒ t| ƒ |td
d„ | D ƒƒt| ƒ d	tdd„ | D ƒƒ t| ƒ f ƒ d S )NrQ   z: nonec                 S   s   g | ]}|d  dkr|‘qS ©rf   r   r   ru   r   r   r   rW   Â   r3   z+main.<locals>.summarise.<locals>.<listcomp>c                 s   s   | ]}|d  V  qdS )rf   Nr   ru   r   r   r   r2   Ã   r3   z*main.<locals>.summarise.<locals>.<genexpr>rd   zJ  %-26s n=%-4d profitable=%3.0f%%  median pnl=%9.0f  legs=%.2f all3=%.0f%%r%   c                 s   s   | ]}|d  V  qdS ©rl   Nr   ru   r   r   r   r2   Æ   r3   c                 s   s   | ]}|d  V  qdS ©rm   Nr   ru   r   r   r   r2   Ç   r3   )ÚprintÚsortedr   Úsum)ÚrsÚlabelr"   Zmedr   r   r   Ú	summarise¿   s    þÿzmain.<locals>.summarisezPOPULATION SPLITzall maker-dominantzTRUE MAKERS (2-sided)zdirectional (1-sided)z
TRUE MAKERS BY P&Lz  %-44s %10s %6s %5s %6s %5s %s)re   rf   rg   ri   ZnetexprH   Zall3c                 S   s
   | d  S rn   r   ro   r   r   r   rN   Ñ   r3   é   z,  %-44s %10.0f %6d %5.2f %6.2f %5.2f %4.0f%%re   rf   rg   ri   rj   rl   rm   c                 S   s   g | ]}|d  dkr|‘qS rv   r   ru   r   r   r   rW   Õ   r3   c                 S   s   g | ]}|d  dkr|‘qS rv   r   ru   r   r   r   rW   Ö   r3   z6
WHAT SEPARATES WINNERS FROM LOSERS (true makers only)ZwinnersZloserszD  %-8s n=%-3d flip=%.2f netexp=%.2f legs=%.2f all3=%.0f%% gross=%.0fc                 s   s   | ]}|d  V  qdS )ri   Nr   ru   r   r   r   r2   Ü   r3   c                 s   s   | ]}|d  V  qdS )rj   Nr   ru   r   r   r   r2   Ý   r3   c                 s   s   | ]}|d  V  qdS rw   r   ru   r   r   r   r2   Þ   r3   c                 s   s   | ]}|d  V  qdS rx   r   ru   r   r   r   r2   ß   r3   c                 s   s   | ]}|d  V  qdS )rk   Nr   ru   r   r   r   r2   à   r3   )'r   ÚsysÚargvÚintr>   ry   rJ   rK   r
   ÚencodeÚdecoder   Úloadsr   r$   rL   Ú	TypeErrorÚ
ValueErrorÚaddÚupperÚitemsrM   r9   ÚmaxÚminÚabsr{   ÚvaluesÚroundÚsortÚopenÚOUTÚcsvZ
DictWriterÚlistÚkeysZwriteheaderZ	writerowsrz   )(Z	n_matchesr<   ÚWr=   r+   Znrr1   r   ZpricesZallrrG   rZ   rq   ZszZpxZoirp   r    Ztotr•   ZflipsZnetsZgrossZ	two_sidedr_   ÚbZslÚgZsettleZnlegsZfhZwtrÚrealZdirnr~   r   ÚwinZlosr}   r|   r   ra   r   Úmainh   sÔ     




(">B".
(ô2	


ÿÿÿ
ûÿ
r›   Ú__main__)r   )Ú__doc__rJ   r“   r   Úosr€   r   r	   r5   r   ÚpathÚdirnameÚabspathÚ__file__ZHEREÚjoinr’   r   r   r   r$   r>   r›   Ú__name__Úexitr   r   r   r   Ú<module>   s&   
|