a
    ÄUejÚ$  ã                   @   s®   d 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mZ ej	 
dd¡ ej	 
dd¡ ddlZddlZdZddd	d
œZdd„ Zdd„ Zdd„ Zdd„ Zedkrªeƒ  dS )aá  
The comprehensive attempt: every feature we can build, every model worth trying.
(read-only, trades nothing)

Prior attempts tested features in ISOLATION -- rolling form alone
(nonprice_edge_test.py), then Elo alone (elo_model_test.py). Both lost to the
closing line. This combines everything and tunes properly, so that "we didn't
try hard enough" stops being a live explanation.

FEATURES
  - Elo at THREE timescales (K=10 slow / 20 / 40 fast), goal-difference weighted,
    walk-forward so a match is always scored with the rating held BEFORE it.
  - Home-specific and away-specific Elo (teams differ home vs away).
  - Rest days per side + difference (congestion).
  - Rolling points / goals for / goals against over 5 and 10, per side.
  - VENUE-specific form (home team's home record, away team's away record).
  - Head-to-head: last-3 meetings goal difference.
  - Season progress, and the market's own probability as a base.

MODELS: multinomial logistic across a regularisation sweep, gradient boosting
across depth/rate, random forest, and a simple averaging ensemble.

SUCCESS CRITERION, fixed in advance: `market + features` must beat `market` on a
TIME-based holdout, with a paired t > 1.96 on per-fixture log loss. Anything else
is noise. A betting simulation is NOT evidence -- elo_model_test showed a +2.7%
"profit" that the no-model control revealed to be a favourite-longshot/devig
artifact, so any betting result here gets the same control.

Usage:  python research\full_model_test.py
é    N)Údatetime)ÚdefaultdictÚdequezE:\soccer\mainzE:\soccer\researchz$E:\soccer\raw_api\fixtures_index.csvé   é   ©ÚHÚDÚAc              	   C   s,   zt t| ƒƒW S  ttfy&   Y d S 0 d S ©N)ÚintÚfloatÚ	TypeErrorÚ
ValueError©Úx© r   ú%E:\soccer\research\full_model_test.pyÚ_i/   s    r   c                  C   sî   g } t tddd��¸}t |¡D ]œ}t| d¡ƒt| d¡ƒ }}|d u s|d u rRqz t |d d d… d¡ ¡ }W n t	t
fyŒ   Y qY n0 |  t|| d	¡| d
¡| d¡||d�¡ qW d   ƒ n1 sÐ0    Y  | jdd„ d� | S )NÚ zutf-8)ÚnewlineÚencodingZ
home_goalsZ
away_goalsÚdateé
   z%Y-%m-%dÚdivZ	home_teamZ	away_team)r   r   ÚhomeÚawayÚhgÚagc                 S   s   | d S ©Nr   r   r   r   r   r   Ú<lambda>C   ó    zload.<locals>.<lambda>©Úkey)ÚopenÚFIXÚcsvZ
DictReaderr   Úgetr   Ústrptimer   r   ÚKeyErrorÚappendÚdictÚsort)ÚoutZfhÚrr   r   Údr   r   r   Úload6   s     
ÿ(r0   c                 C   sz  dd„ dD ƒ}t dd„ ƒt dd„ ƒdœ}i }t dd„ ƒ}t dd„ ƒt d	d„ ƒdœ}t d
d„ ƒ}t tƒ}dd„ }| D �] }	|	d |	d  }
}g }dD ]6}||| |
 || | || |
 || |  g7 }q’||d |
 |d | |d |
 |d |  g7 }|
|v �r|	d ||
  jnd}||v �r8|	d ||  jnd}|t|dƒt|dƒt|dƒt|dƒ g7 }dD ]D}|||
 |ƒ||| |ƒ }}||| dd„ t||ƒD ƒ 7 }�qj|||d |
 dƒ||d | dƒ 7 }tt|
|gƒƒ}t|| ƒ}||�rtdd„ |D ƒƒt	|ƒ ndt	|ƒg7 }|t||
 dƒt|| dƒg7 }||	d< |	d |	d  }|dk�rjd n|dk�rxd!nd}t
 t|ƒd" ¡d" }dD ]j}d d d#|| | || |
  d$ d%    }|| ||  }|| |
  |7  < || |  |8  < �q–d d d#|d | |d |
  d%    }d&| ||  }|d |
  |7  < |d |  |8  < |dk�rpd'n|dk�r~d"nd}||
  ||	d |	d f¡ ||  |d"k�r¸d'| nd"|	d |	d f¡ |d |
  ||	d |	d f¡ |d |  |d"k�r
d'| nd"|	d |	d f¡ ||  |
|d k�r8|n| ¡ ||
  d"7  < ||  d"7  < |	d  ||
< ||< qr| S )(zJWalk forward once, attaching only information available BEFORE each match.c                 S   s   i | ]}|t d d„ ƒ“qS )c                   S   s   dS ©Ng     p—@r   r   r   r   r   r    I   r!   z&featurise.<locals>.<dictcomp>.<lambda>)r   ©Ú.0Úkr   r   r   Ú
<dictcomp>I   r!   zfeaturise.<locals>.<dictcomp>)r   é   é(   c                   S   s   dS r1   r   r   r   r   r   r    J   r!   zfeaturise.<locals>.<lambda>)ÚhÚac                   S   s
   t dd�S ©Nr   ©Úmaxlen©r   r   r   r   r   r    L   r!   c                   S   s
   t dd�S r:   r=   r   r   r   r   r    M   r!   c                   S   s
   t dd�S r:   r=   r   r   r   r   r    N   r!   c                   S   s
   t dd�S )Né   r;   r=   r   r   r   r   r    O   r!   c                    s4   t | ƒ| d … ‰ ˆ sg d¢S ‡ fdd„tdƒD ƒS )N)ç        r?   r?   c                    s*   g | ]"‰ t ‡ fd d„ˆD ƒƒtˆƒ ‘qS )c                 3   s   | ]}|ˆ  V  qd S r   r   ©r3   r   ©Úir   r   Ú	<genexpr>V   r!   z4featurise.<locals>.agg.<locals>.<listcomp>.<genexpr>©ÚsumÚlen©r3   ©ÚsrA   r   Ú
<listcomp>V   r!   z*featurise.<locals>.agg.<locals>.<listcomp>r>   )ÚlistÚrange)ZdqÚnr   rH   r   ÚaggR   s    zfeaturise.<locals>.aggr   r   r8   r9   r   é   é   )é   r   c                 S   s   g | ]\}}|| ‘qS r   r   )r3   r   Úyr   r   r   rJ   d   r!   zfeaturise.<locals>.<listcomp>rQ   c                 s   s   | ]
}|V  qd S r   r   r@   r   r   r   rC   h   r!   zfeaturise.<locals>.<genexpr>r?   r7   r   r   r   r   ç      ð?g      à?r   r   g     @P@g      y@r6   r>   )r   r   ZdaysÚminÚzipÚtupleÚsortedrK   rE   rF   ÚmathÚlogÚabsr*   )ÚfxZeloZ	elo_venueZlastZformZvformZh2hZplayedrN   Úfr8   r9   ÚrowÚKZrhZrarM   Zfh_Zfa_r#   ZhhÚgdÚscZmultZexpr/   ZexpvZdvZphr   r   r   Ú	featuriseG   sh    

ÿ
4ÿ  *$(0  ,( . 2"ra   c            #         s4  dd l } ddlm} ddlm}m} ddlm} tt	ƒ ƒ}t
 ¡ }g }|D ]h}|d t
 t |d ¡¡t
 t |d ¡¡f}	| |	¡}
|
sŒqJ|
\}}| t|d |||d d	�¡ qJ|jd
d„ d� tdt|ƒ› dt|d d ƒ› �ƒ tt|ƒd ƒ}|d |… ||d …  }}tdt|ƒ› d|d d › dt|ƒ› d|d d › d�	ƒ dd„ |D ƒ‰dd„ |D ƒ‰| jdd„ |D ƒtd�}| jdd„ |D ƒtd�}|ƒ  |¡}| |¡| |¡ }}|  dd„ |D ƒ¡}|  dd„ |D ƒ¡}dd„ |D ƒ}‡fdd „‰ˆ|ƒ‰ t ˆ ¡}td!d"›d#d$d%›d#d&d%›d#d'd%›�ƒ td(d"›d#|d)›d#d*d%›d#d*d%›�ƒ g ‰‡ ‡‡‡‡fd+d,„}|  ||g¡|  ||g¡ }}d-D ]$}|d.|› �||||d/d0d1�ƒ �q”d2D ]4\}}}|d3|› d4|› �||||||d5dd6�ƒ �q¾|d7|||d8d9ddd:�ƒ |d;|||d<d=d>dd?�ƒ tˆd@dA�d dB… ‰tˆƒdCk�rð‡fdDd„ttˆƒƒD ƒ}ˆ|ƒ‰‡ ‡fdEd„ttˆƒƒD ƒ}t |¡} t |¡t  !t|ƒ¡ }!tdFd"›d#t ˆ¡d)›d#| dG›d#| |! dH›| |! dIk�rædJndK› �ƒ tdLƒ dMd„ ˆD ƒ}"tt|"ƒ› dNtˆƒ› dO�ƒ |"�s0tdPƒ d S )QNr   )ÚLogisticRegression)ÚHistGradientBoostingClassifierÚRandomForestClassifier)ÚStandardScalerr   r   r   r   )r   ÚpÚresr   c                 S   s   | d S r   r   )r.   r   r   r   r    •   r!   zmain.<locals>.<lambda>r"   zmatched fixtures: z   features per fixture: gffffffæ?z  train z (to éÿÿÿÿz	)   test z (z on)
c                 S   s   g | ]}|d  ‘qS ©rg   r   ©r3   r.   r   r   r   rJ   œ   r!   zmain.<locals>.<listcomp>c                 S   s   g | ]}|d  ‘qS ri   r   rj   r   r   r   rJ   �   r!   c                 S   s   g | ]}|d  ‘qS r   r   rj   r   r   r   rJ   ž   r!   )Zdtypec                 S   s   g | ]}|d  ‘qS r   r   rj   r   r   r   rJ   Ÿ   r!   c                 S   s   g | ]}d d„ |d D ƒ‘qS )c                 S   s   g | ]}t  t|d ƒ¡‘qS ©g•Ö&è.>©rX   rY   Úmax©r3   Úvr   r   r   rJ   ¢   r!   ú#main.<locals>.<listcomp>.<listcomp>rf   r   rj   r   r   r   rJ   ¢   r!   c                 S   s   g | ]}d d„ |d D ƒ‘qS )c                 S   s   g | ]}t  t|d ƒ¡‘qS rk   rl   rn   r   r   r   rJ   £   r!   rp   rf   r   rj   r   r   r   rJ   £   r!   c                 S   s   g | ]}|d  ‘qS )rf   r   rj   r   r   r   rJ   ¤   r!   c                    s   ‡ ‡fdd„t tˆƒƒD ƒS )Nc              	      s.   g | ]&}t  tˆ | tˆ|   d ƒ¡ ‘qS rk   )rX   rY   rm   ÚIDX©r3   rB   )ÚPÚyter   r   rJ   §   r!   z(main.<locals>.ll_vec.<locals>.<listcomp>)rL   rF   ©rs   )rt   ru   r   Úll_vec¦   s    zmain.<locals>.ll_vecÚmodelÚ48sú zlog lossz>9szvs mktzpaired tzMARKET (Pinnacle closing)ú9.5fz--c              
      s.  z|  |ˆ¡ W n: tyJ } z"t| d›d|› �ƒ W Y d }~d S d }~0 0 | |¡‰t|jƒ‰ ‡ ‡fdd„ttˆƒƒD ƒ}ˆ|ƒ‰‡‡fdd„ttˆƒƒD ƒ}t 	|¡}t 
|¡t t|ƒ¡ }|dkrÒ|| nd}	ˆ ||	| |f¡ |	dk� röd	nd
}
t| d›dt 	ˆ¡d›d|d›d|	d›|
› �ƒ d S )Nrx   z FAILED c                    s"   g | ]‰ ‡ ‡‡fd d„dD ƒ‘qS )c                    s   g | ]}ˆˆ  ˆ  |¡ ‘qS r   )Úindexr2   )rB   ÚoÚprr   r   rJ   ¸   r!   z/main.<locals>.ev.<locals>.<listcomp>.<listcomp>r   r   rG   )r|   r}   rA   r   rJ   ¸   r!   z$main.<locals>.ev.<locals>.<listcomp>c                    s   g | ]}ˆ | ˆ|  ‘qS r   r   rr   ©Úbase_vro   r   r   rJ   º   r!   r   r?   ç\�Âõ(\ÿ?ú  *** BEATS MARKET ***r   ry   rz   ú+9.5fú+9.2f)ÚfitÚ	ExceptionÚprintZpredict_probarK   Zclasses_rL   rF   Ú
statisticsÚmeanÚpstdevrX   Úsqrtr*   )Zlabelr
   ÚBrw   Úers   r/   ÚmuÚseÚtÚflag)r   rv   Úresultsrt   Úytr)r|   r}   ro   r   Úev°   s     


zmain.<locals>.ev)gú~j¼t“h?g{®Gáz„?ç¸…ëQ¸ž?gš™™™™™¹?g333333Ó?rS   z"market + ALL features, logistic C=i   Zmultinomial)ÚCÚmax_iterZmulti_class))r   r”   é�  )r>   çš™™™™™©?é,  )é   r˜   r™   )é   r”   iô  zmarket + ALL, GBM d=z lr=rS   )Ú	max_depthr–   Úlearning_rateZl2_regularizationÚrandom_statezmarket + ALL, RandomForestr—   é   )Zn_estimatorsZmin_samples_leafZn_jobsrž   zfeatures ONLY, GBM d=4rš   r™   r˜   )rœ   r–   r�   rž   T)Úreverser>   r   c                    s$   g | ]‰ ‡‡ fd d„t dƒD ƒ‘qS )c                    s,   g | ]$‰ t ‡‡ fd d„ˆD ƒƒtˆƒ ‘qS )c                 3   s   | ]}|d  ˆ  ˆ V  qdS )r>   Nr   )r3   Úg)rB   Újr   r   rC   Õ   r!   z-main.<locals>.<listcomp>.<listcomp>.<genexpr>rD   rG   )ÚgoodrB   )r¢   r   rJ   Õ   r!   rp   r>   )rL   rG   )r£   rA   r   rJ   Õ   s   ÿc                    s   g | ]}ˆ | ˆ|  ‘qS r   r   rr   r~   r   r   rJ   Ø   r!   zENSEMBLE (top 3 averaged)r‚   rƒ   r€   r�   r   zA
Success criterion set in advance: paired t > 1.96 vs the market.c                 S   s   g | ]}|d  dkr|‘qS )r   r€   r   rj   r   r   r   rJ   à   r!   z of z configurations met it.zGNone. The closing line already contains everything these features know.)"ZnumpyZsklearn.linear_modelrb   Zsklearn.ensemblerc   rd   Zsklearn.preprocessingre   ra   r0   ÚTZ	load_oddsZnormÚDSZ	fdco_namer'   r*   r+   r,   r†   rF   r   Zarrayr   r„   Z	transformr‡   rˆ   ZhstackrW   rL   r‰   rX   rŠ   )#Znprb   rc   rd   re   r[   ZoddsZrowsr\   r4   Zhitrf   rg   ZcutZtrZteZXtrZXter`   ZMtrZMteZmkÚbaser“   ZXM_trZXM_ter•   ZdepthZlrÚitrs   r/   r�   rŽ   Úwinr   )r   r£   rv   r‘   ro   rt   r’   r   Úmain…   s     
.
 $&
ÿ

&&ÿþÿÿÿÿÿ

ÿ
ÿÿþr©   Ú__main__)Ú__doc__Úsysr&   rX   r‡   r   Úcollectionsr   r   ÚpathÚinsertZdaily_signalsr¥   Znonprice_edge_testr¤   r%   rq   r   r0   ra   r©   Ú__name__r   r   r   r   Ú<module>   s$   >a