a
    ux€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mZ ddlm	Z	 ddl
Zej dd¡ ddlZe	dƒZe	dƒZg d¢Zg d	¢Zd
d„ Zdd„ Zdd„ Zddd„ZedkrÂeƒ Zeeƒ eeƒ dS )a=  Which asking price sells best -- as a regression, conditional on the book.

touch_premium_curve.py answers this MARGINALLY: one premium for everything. But
the best price for a busy Championship book is not the best price for a thin
Peruvian one, and a curve averaged over both hides that.

THE TRICK THAT MAKES THIS CHEAP. The trade tape gives, per leg, the highest
price anyone paid before kickoff. Define

    headroom = (max print - touch at post) x 100   [cents]

A resting ask at premium d would have been lifted iff headroom >= d. So one
number per leg encodes the fill/no-fill answer at EVERY premium -- no need to
re-run anything per price, and no dependence on the arm the quoter happened to
pick. headroom IS the market's willingness to pay above the touch.

WHAT IS FITTED. A logistic per premium level, P(headroom >= d | features), with
standard errors CLUSTERED BY BOOK: the three legs of a match share its flow and
its overround, so treating them as independent would overstate significance
roughly threefold -- the same pseudo-replication that inflated the pinnapi
t-stats earlier in this project.

WHAT IT IS FOR. Per book, pick the d that maximises

    E[book] = P(all three fill at d) x (overround + 3d)

and backtest that against every fixed d on a TEMPORAL split. If per-book pricing
does not beat the best single number, use the single number.

CEILING CAVEAT: a print at or above our price means we could have been hit, not
that we would have. Queue priority is assumed throughout, as in mm_settle.

Usage:  python research\premium_regression.py   (needs .tape_cache.json)
é    N)Údefaultdict)ÚPathzE:\soccer\mainz&E:\soccer\research\mm_paper_quotes.csvz#E:\soccer\research\.tape_cache.json)r   é   é   é   é   é   )Zmin_leg_vol_kZ	hrs_to_koZspread_cZoverround_cZtouch_pxZis_drawc              	   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\premium_regression.pyÚ_f7   s    
r   c                  C   sn  t  ¡ stdƒ‚t t  ¡ ¡} tt ¡ ƒd }t	 
t|¡ i }|jdddd��L}t |¡D ]0}| d¡}|rZ||vrZ| d¡sZdsZ|||< qZW d   ƒ n1 s 0    Y  ttƒ}| ¡ D ]:\}}t| d	¡ƒ}|d urº|| v rº|| d
¡  |¡ qºg }| ¡ D �]d\}}|| v�r�qt | d¡¡t | d¡¡ }	}
t| d¡ƒt| d¡ƒ }}t| d¡ƒ}| | d
¡¡�p|g }d |	|
|||fv �s|�rd|  k �r¼|  k �r¼dk �sÂn �q|
|	  ¡ d }d|  k �rêdk�sðn �q| || d
¡|
t| | ƒ| d |d d t|ƒd ||| d |d d |t| d¡ƒ ¡ dk�rZdndgdœ¡ �q|S )Nz7no .tape_cache.json -- run touch_premium_curve.py firstzmm_paper_quotes.snap.csvÚ zutf-8Úreplace)ÚnewlineÚencodingÚerrorsZ
leg_tickerÚreasonZvolumeÚeventÚtsZkickoffZk_askZk_bidZover_askr   r   g      ¬@é   ç      Y@g      ð?g     @�@ZsideZdrawç        )Ztkrr   ÚkoÚheadroomÚover_cr   )ÚCACHEÚexistsÚ
SystemExitÚjsonÚloadsÚ	read_textr   ÚtempfileZ
gettempdirÚshutilZcopyfileÚQUOTESÚopenÚcsvZ
DictReaderÚgetr   ÚlistÚitemsr   ÚappendÚMSZ_ptZtotal_secondsr
   ÚminÚstrÚlower)ÚcacheÚtmpÚfirstZfhÚrÚtZvolsÚvÚlegsr   r   ZkaZkbÚoverZvvZhrsr   r   r   Úload>   sL    
(
"@
  ÿür;   c                 C   sP  dd l m} | t dd„ | D ƒt¡¡}t dd„ | D ƒ¡}tt| ƒ› dtt|ƒƒ› d�ƒ tdƒ t dd„ | D ƒ¡}d	D ]&}td
|d›dt 	||¡d›d�ƒ q|tdd|dk 
¡  d›d�ƒ tdƒ tdd›ddd›d�d dd„ tD ƒ¡ ƒ tD �]F}||k t¡}| ¡ dk �s.d|  ¡ dk �rPt|d›dt| ¡ ƒd›d�ƒ qúz | ||¡jdd d!|id"�}W nL t�y¼ }	 z2t|d›d#t|	ƒj› �ƒ W Y d }	~	qúW Y d }	~	n
d }	~	0 0 g }
ttdd$�D ]>\}}|j| d%k �rêd&nd}|
 |j| d'›|› d(�¡ �qÎt|d›dt| ¡ ƒd›d)�d d*d„ |
D ƒ¡ ƒ qútd+ƒ d S ),Nr   c                 S   s   g | ]}|d  ‘qS r   r   ©Ú.0Úlr   r   r   Ú
<listcomp>i   ó    zfit_report.<locals>.<listcomp>c                 S   s   g | ]}|d  ‘qS )r   r   r<   r   r   r   r?   j   r@   z legs, z books
z;headroom (cents above touch that the market actually paid):c                 S   s   g | ]}|d  ‘qS ©r   r   r<   r   r   r   r?   m   r@   )é
   é   é2   éK   éZ   z   pz<3ú z+6.1fÚcz   share with headroom >= 0: r   z.0fz%
z5P(fill at premium d), logistic, SEs clustered by bookÚdz>3Zfillsz>7c                 s   s   | ]}|d ›V  qdS )z>14Nr   )r=   Únr   r   r   Ú	<genexpr>s   r@   zfit_report.<locals>.<genexpr>é   r   z>2zc  z>6z   (too few either way to fit)ZclusterÚgroups)ZdispZcov_typeZcov_kwdszc  fit failed: )Ústartgš™™™™™©?Ú*z+8.3fz     z   c                 s   s   | ]}|d d… V  qd S )Né   r   )r=   rH   r   r   r   rK   ƒ   r@   z$  * = p<0.05 with book-clustered SEs)Zstatsmodels.apiZapiZadd_constantÚnpÚarrayr
   ÚprintÚlenÚsetZ
percentileZmeanÚjoinÚFEATSÚPREMIUMSÚastypeÚsumÚintZLogitÚfitÚ	ExceptionÚtypeÚ__name__Ú	enumerateZpvaluesr.   Úparams)r9   ZsmÚXrM   ÚhÚqrI   ÚyÚresÚeZcellsÚiZ_nZstarr   r   r   Ú
fit_reportg   s:     $,
  ÿ
" 6ri   çÍÌÌÌÌÌä?c                    sì  ddl m} ddlm} ddlm} ttƒ}| D ]}||d   |¡ q0t	dd„ | 
¡ D ƒdd	„ d
�}t|ƒdk rŠtdt|ƒ› d�ƒ d S tt|ƒ| ƒ}|d |… ||d …  }	‰dd„ |	D ƒ}
t dd„ |
D ƒt¡}t dd„ |
D ƒ¡}i ‰ tD ]X}||k t¡}| ¡ dk sôd|  ¡ dk �r&qô||ƒ |dd�ƒ}| ||¡ |ˆ |< qôtdd› dt|	ƒ› dtˆƒ› d�ƒ td|	d d d›d|	d d d›dˆd d d›dˆd d d›d�	ƒ tdd d!›d"d#d$›d"d%d&›d"d'd(›�ƒ ‡fd)d*„}d+\}}tD ]x}||fd,d	„ƒ\}}}|�r$|| nd}tdd-t|ƒ d. d!›d"|d$›d"|d/›d"|d0›d.�	ƒ ||k�rü|| }}�qü‡ fd1d2„}||ƒ\}}}tdd3d!›d"|d$›d"|d/›d"|�rº|| ndd0›d.�	ƒ td4|› d5|d6›d7�ƒ td8ƒ d S )9Nr   )ÚLogisticRegression)Úmake_pipeline)ÚStandardScalerr   c                 S   s4   g | ],\}}t |ƒd krtdd„ |D ƒƒ||f‘qS )r   c                 s   s   | ]}|d  V  qdS )r   Nr   )r=   r   r   r   r   rK   �   r@   z&backtest.<locals>.<listcomp>.<genexpr>)rT   r0   )r=   rg   r8   r   r   r   r?   �   s   ÿzbacktest.<locals>.<listcomp>c                 S   s   | d S )Nr   r   )r7   r   r   r   Ú<lambda>�   r@   zbacktest.<locals>.<lambda>)Úkeyé<   z
only z' three-leg books -- too few to backtestc                 S   s    g | ]\}}}|D ]}|‘qqS r   r   )r=   Ú_r8   r>   r   r   r   r?   –   r@   c                 S   s   g | ]}|d  ‘qS r   r   r<   r   r   r   r?   —   r@   c                 S   s   g | ]}|d  ‘qS rA   r   r<   r   r   r   r?   ˜   r@   é   r   i¸  )Zmax_iterÚ
zB==================================================================z
TEMPORAL BACKTEST  train z books / test z booksz  train z%m-%dz .. éÿÿÿÿz   test z  ZpolicyZ26rG   zbooks quotedz>13Zcompletez>9zE[book]z>10c                    sx   d\}}}ˆD ]^\}}}| |ƒ‰ ˆ d u r*q|d7 }|d d }t ‡ fdd„|D ƒƒr|d7 }||dˆ   7 }q|||fS )N)r   r   r   r   r   r   c                 3   s   | ]}|d  ˆ kV  qdS )r   Nr   r<   ©rI   r   r   rK   ±   r@   z*backtest.<locals>.score.<locals>.<genexpr>r   )Úall)ZpickZtotZcompZquotedrq   r8   r:   )Útestru   r   Úscore©   s    
zbacktest.<locals>.score©Ng    eÍÍÁc                 S   s   |S r	   r   )r8   rI   r   r   r   rn   ¸   r@   zfixed +rH   z>8z>9.2fc                    s~   t  dd„ | D ƒt¡}d\}}ˆ  ¡ D ]R\}}tt  | |¡d d …df ¡ƒ}|| d d d|   }||kr&|| }}q&|S )Nc                 S   s   g | ]}|d  ‘qS r   r   r<   r   r   r   r?   ¿   r@   z0backtest.<locals>.model_pick.<locals>.<listcomp>ry   r   r   r   r   )rQ   rR   r
   r-   ZprodZpredict_proba)r8   ZXbZbestZbevrI   ÚmÚpÚev)Úmodelsr   r   Ú
model_pick¾   s     zbacktest.<locals>.model_pickzmodel: per-book premiumz+
  best fixed premium on the test window: +zc (z.2fzc/book)zD  E[book] is per book QUOTED. Fills assume queue priority (CEILING).)Zsklearn.linear_modelrk   Zsklearn.pipelinerl   Zsklearn.preprocessingrm   r   r,   r.   Úsortedr-   rT   rS   r[   rQ   rR   r
   rX   rY   rZ   r\   r1   )r9   Z
train_fracrk   rl   rm   Zbooksr>   ZfullZcutZtrainZtr_legsZXtrZhtrrI   re   rz   rx   Z
best_fixedZbest_valrd   rH   r7   r|   r~   r   )r}   rw   r   Úbacktest‡   sj    ÿÿ
ÿ
$ÿÿ
(6
	ÿ

ÿ
r€   Ú__main__)rj   )Ú__doc__r*   r#   r'   Úsysr&   Úcollectionsr   Úpathlibr   ZnumpyrQ   ÚpathÚinsertZ	mm_settler/   r(   r    rX   rW   r   r;   ri   r€   r_   ÚLr   r   r   r   Ú<module>   s,   ") 
H