a
    Ê‹j¬#  ã                   @   sB  d Z ddlZddlZddlZddlZddlmZmZ ddlm	Z	 ddl
mZ ddlmZ ddlmZ ddlmZ ddlZe d	¡ ddlmZ ej dd
¡ ejjddd� ddlZddlZe	dƒZdZ dd„ Z!e!dƒZ"e" #dd¡Z$e" #dd¡Z%e" #dd¡Z&d$dd„Z'dd„ Z(dd„ Z)dd„ Z*dd „ Z+d!d"„ Z,e-d#k�r>e,ƒ  dS )%u²  
Weekly strategy-metrics report â€” emails the running forward-test state every week.

Covers: frozen xlow forward test (primary + f10/t60/unique/overlap diagnostics),
the strict-xlow live ledger (units + dollars, week and cumulative), league
breakdown. (The n>=100 checkpoint was passed 2026-08 and no longer tracked.)

Scheduled weekly via Task Scheduler (SoccerWeeklyStrategyMetrics).
Usage: python main\weekly_strategy_metrics.py
é    N)ÚdateÚ	timedelta)ÚPath)ÚMIMEMultipart)ÚMIMEText)Ú	MIMEImage)ÚdefaultdictZAggzE:\soccer\researchzutf-8Úreplace)ÚencodingÚerrorszE:\soccer\data\bet_history.jsonéd   c                 C   sl   i }zPt | ƒD ]B}| ¡ }|r| d¡sd|v r| dd¡\}}| ¡ || ¡ < qW n tyf   Y n0 |S )Nú#ú=é   )ÚopenÚstripÚ
startswithÚsplitÚ	Exception)ÚpathÚenvÚlineÚkÚv© r   úmain/weekly_strategy_metrics.pyÚ	_load_env!   s    r   zE:\soccer\.envZEMAIL_SENDERÚ ÚEMAIL_RECIPIENTÚEMAIL_APP_PASSWORDc                 C   s˜   t dƒ}| |d< t|d< t|d< | t|dƒ¡ |rRt|ƒ}| dd¡ | |¡ t dd	¡�&}| 	tt
¡ | |¡ W d   ƒ n1 sŠ0    Y  d S )
NZrelatedZSubjectZFromZToÚhtmlz
Content-IDz<equity>zsmtp.gmail.comiÑ  )r   ÚEMAIL_ADDRESSr   Zattachr   r   Z
add_headerÚsmtplibZSMTP_SSLZloginr   Zsend_message)ÚsubjectZ	html_bodyÚ
inline_pngÚmsgZimgZsrvr   r   r   Ú
send_email4   s    
r&   c               
   C   sb  t  ¡ } dd„ dd„ | D ƒD ƒ}|jdd„ d� dd„ |D ƒ}td	d„ |D ƒd
d„ |D ƒ dd„ d�}dd„ |D ƒ}tt|ƒd ƒ}tt ¡ dd„ d�}dd„ dd„ |D ƒD ƒ}dd„ |D ƒ}dd„ }	tj	ddd�\}
}|
j
 d¡ | d¡ d|	|d|… ƒdfd|	||d… ƒdfd|	|ƒdffD ]\\}}}|jtt|ƒƒ||d|d � |j|d! d"›d#�t|ƒd$ |d! fd%d&d'd(d)d*� �q&|jd+d,d$d-� |jd.d'd/� |jd0d'd/� |jd1d2d3d4� |jd5d6d7d-� d8D ]}|j|  d9¡ �qÔd:D ]}|j|  d,¡ �qð|jd'd;� |jd9d<d(d=� |jd>d?� t ¡ }|
 ¡  |
j|d@dAdB� t |
¡ | ¡ S )CzNTrain/test/forward cumulative-unit curves (flat 1u, Kalshi-execution pricing).c                 S   s   g | ]}|r|‘qS r   r   ©Ú.0Úbr   r   r   Ú
<listcomp>F   ó    zequity_png.<locals>.<listcomp>c                 s   s   | ]}t  |¡V  qd S )N)ÚKÚxlow©r(   Úfr   r   r   Ú	<genexpr>F   r+   zequity_png.<locals>.<genexpr>c                 S   s   | d S ©NÚgdr   ©r)   r   r   r   Ú<lambda>G   r+   zequity_png.<locals>.<lambda>©Úkeyc                 S   s   g | ]}|d  dkr|‘qS )ÚbookÚpolyr   r'   r   r   r   r*   H   r+   c                 S   s   g | ]}|d  dkr|‘qS )r7   Zkalshir   r'   r   r   r   r*   I   r+   c                 S   s   g | ]}t ||d  d�‘qS )Ú
kalshi_ask©Úpx)Údictr'   r   r   r   r*   J   r+   c                 S   s   | d S r1   r   r3   r   r   r   r4   J   r+   c                 S   s,   g | ]$}|d  r$d|d  |d  nd‘qS ©Úwonr   r;   éÿÿÿÿr   r'   r   r   r   r*   K   r+   g333333ã?c                 S   s   | d S r1   r   )r/   r   r   r   r4   M   r+   c                 S   s   g | ]}|r|‘qS r   r   r'   r   r   r   r*   O   s   ÿc                 s   s0   | ](}|d  t jkrt  |¡rt  |¡V  qdS )r2   N)ÚFÚFREEZE_DATEZin_primary_leaguesZfire_xlow_primaryr.   r   r   r   r0   O   s   ÿc                 S   s,   g | ]$}|d  r$d|d  |d  nd‘qS r=   r   r'   r   r   r   r*   Q   r+   c                 S   s,   dgd }}| D ]}||7 }|  |¡ q|S )Nç        )Úappend)ZrsÚoutÚcÚrr   r   r   ÚeqS   s
    zequity_png.<locals>.eq)é	   gÍÌÌÌÌÌ@é–   )ZfigsizeZdpiZwhitezTrain (first 60% of backtest)Nz#2a78d6zTest (last 40%)z#008300zForward (since 7/05 freeze)z#eda100é   )ÚcolorÚ	linewidthZlabelr?   ú+.1fÚur   )é   r   zoffset pointsz#3d3d3arH   Úcenter)ZxyZxytextZ
textcoordsrK   ÚfontsizeZvar   z#c9c8c0)rK   rL   z
Bet number)rK   zCumulative units (flat 1u/bet)u(   xlow equity â€” train vs test vs forwardz#1a1a19é   )rK   rQ   Tz#eeede6gffffffæ?)ÚtopÚrightF)ÚleftZbottom)Zcolorsz
upper left)ZframeonZlocrQ   g¸…ëQ¸®?)ÚxZpngZtight)ÚformatZbbox_inches) r,   ÚloadÚsortÚsortedÚintÚlenr@   Úload_fixturesÚpltZsubplotsZpatchZset_facecolorZplotÚrangeZannotateZaxhlineZ
set_xlabelZ
set_ylabelZ	set_titleZgridZspinesZset_visibleZ	set_colorZtick_paramsZlegendZmarginsÚioÚBytesIOZtight_layoutZsavefigÚcloseÚgetvalue)ÚfxÚbetsr8   ÚstreamZretsZcutÚpreppedZfwdZfwd_retsrG   ZfigZaxÚnameZseriesrK   ÚsZbufr   r   r   Ú
equity_pngC   sV    ÿÿ
þ&ÿ

rj   c               	   C   sö   t  ¡ } dd„ | D ƒ}t  |¡}t  |¡}t  |¡t  |¡t  t  |¡¡t  dd„ |D ƒ¡t  t  |¡¡dœ}t  |¡\}}t  |¡|d< t  |¡|d< tt	ƒ}|D ]$}t  
|¡}	|	r¤||d   |	¡ q¤dd	„ t| ¡ d
d„ d�D ƒ}
||
t|ƒfS )zFOOS stats per rule from the frozen tracker, plus per-league xlow rows.c                 S   s   g | ]}|d  t jkr|‘qS )r2   )r@   rA   )r(   rd   r   r   r   r*   y   r+   z!forward_stats.<locals>.<listcomp>c                 S   s   g | ]}|d  t jkr|‘qS r:   )r@   ZXLOW_PRICE_FLOORr'   r   r   r   r*   ƒ   r+   )úxlow (PRIMARY)zxlow (all leagues, pooled)zxlow (outside scope, tracking)Zxlow_f10Zt60ÚuniqueÚoverlapZleaguec                 S   s   i | ]\}}|t  |¡“qS r   )r@   Ústat)r(   ÚlgZbsr   r   r   Ú
<dictcomp>Ž   r+   z!forward_stats.<locals>.<dictcomp>c                 S   s   t | d ƒ S )Nr   )r\   )Zkvr   r   r   r4   Ž   r+   zforward_stats.<locals>.<lambda>r5   )r@   r]   Zclassify_xlowZclassify_xlow_btrn   Zclassify_xlow_newlgZclassify_t60Zclassifyr   ÚlistZ	fire_xlowrC   rZ   Úitemsr\   )rg   Zoosr-   Zxlow_btÚrowsZuniqrm   Zby_lgrd   r)   Úleaguesr   r   r   Úforward_statsv   s(    

û
ru   c                     sX   t  t ¡ ¡} dd„ | D ƒ}t ¡ tdd�  ¡ ‰ dd„ }|‡ fdd„|D ƒƒ||ƒfS )zOStrict-xlow live ledger (strategy=='xlow'): week + cumulative, units + dollars.c                 S   s,   g | ]$}|  d ¡dkr|  d¡dvr|‘qS )Zstrategyr-   Zftr)ZVOIDZEXP©Úgetr'   r   r   r   r*   •   r+   z ledger_stats.<locals>.<listcomp>é   )Zdaysc           	      S   s¢   d }}d }}| D ]€}|  d¡p*|  d¡}|  d¡d urD|  d¡n|  d¡}|r|d u r\q|d7 }|dk}||7 }||r†d| | nd7 }||7 }q||||fS )	Nr   rB   r9   Zpoly_askZ
kalshi_pnlZpoly_pnlr   r?   rv   )	re   ÚnÚwZunitsZdollarsr)   ZaskZpnlr>   r   r   r   Úroll˜   s    "
zledger_stats.<locals>.rollc                    s    g | ]}|  d d¡ˆ kr|‘qS )r   r   rv   r'   ©Z
week_startr   r   r*   §   r+   )ÚjsonÚloadsÚBET_HISTORYÚ	read_textr   Útodayr   Ú	isoformat)ZhistZxbetsr{   r   r|   r   Úledger_stats’   s
    rƒ   c                 C   sH   | sdS d| d › d| d d›d| d d›d	| d
 d›d| d d›d�S )Nu   <td colspan=4>â€”</td>z<td>ry   z	</td><td>Úwrz.1fz% (impl Ziwrz%)</td><td>ÚroirM   z
%</td><td>Úzú+.2fú</td>r   )ri   r   r   r   Úfmt_statª   s    $ÿÿr‰   c                  C   sœ  t ƒ \} }}tƒ \\}}}}\}}}	}
dt ¡  ¡ › d�d|› dtj› dt› d�ddg}|  ¡ D ]$\}}| 	d	|› d
t
|ƒ› d�¡ q`| 	d¡ | 	d¡ | ¡ D ]$\}}| 	d|› dt
|ƒ› d�¡ q¢| 	d¡ | 	d¡ | 	d|› d|› d|| › d|d›d|d›d|› d|› d|| › d|	d›d|
d›d�¡ | d �rjd|› d| d d d›d|d›d|d ›d!�	nd|› �}t|d" |¡tƒ d#� td$|› �ƒ d S )%Nu"   <h2>xlow forward test â€” week of z</h2>z<p><b>n=z</b> (frozen z; the n&ge;u5    checkpoint was passed â€” this is judgeable now)</p>z(<h3>Forward (out-of-sample) by rule</h3>zq<table border=1 cellpadding=4 cellspacing=0><tr><th>rule</th><th>n</th><th>WR</th><th>ROI/bet</th><th>z</th></tr>z<tr><td><b>z	</b></td>z</tr>z</table>z’<h3>Forward xlow by league</h3><table border=1 cellpadding=4 cellspacing=0><tr><th>league</th><th>n</th><th>WR</th><th>ROI/bet</th><th>z</th></tr>z<tr><td>rˆ   u—   <h3>Equity curves</h3><img src='cid:equity' style='max-width:100%'><p style='color:#888'>Forward axis is shorter â€” compare slopes, not endpoints.</p>z5<h3>Live ledger (strict xlow only)</h3><p>This week: z bets, zW-zL, r‡   zu, $z<br>Cumulative: u®   </p><p style='color:#888'>Reference: backtest target +17.8% fee-adj (n=286, p=.008). ROI swings of Â±25pp are expected at current n â€” no verdicts before the checkpoint.</p>rk   z[XLOW WEEKLY] fwd n=z ROI r…   rM   z	% | week zu ($z+.0fú)r   )r$   zsent: )ru   rƒ   r   r�   r‚   r@   rA   ÚCHECKPOINT_Nrr   rC   r‰   r&   Újoinrj   Úprint)rs   rt   Zn_xlowZwnZwwZwuZwdZtnZtwZtuZtdr    rh   ri   ro   r#   r   r   r   Úmain±   s`    ü



ÿÿÿÿÿþþþþþ
	þÿÿÿþrŽ   Ú__main__)N).Ú__doc__r`   r}   Úsysr"   Zdatetimer   r   Úpathlibr   Zemail.mime.multipartr   Zemail.mime.textr   Zemail.mime.imager   Úcollectionsr   Z
matplotlibZuseZmatplotlib.pyplotZpyplotr^   r   ÚinsertÚstdoutÚreconfigureZforward_test_unique_bookr@   Zkalshi_only_executionr,   r   r‹   r   Z_envrw   r!   r   r   r&   rj   ru   rƒ   r‰   rŽ   Ú__name__r   r   r   r   Ú<module>   s:   
 

3*
