
    \j#              
          S r SSKrSSKrSSKrSSKJr  SSKrSSKr	SSK
r
SSKrSSKr\" \5      R                  5       R                   R                   r\S-  S-  S-  rSrSrSS	S
S.rS\	R,                  4S jrS\	R,                  S\S\\   S\S\	R,                  4
S jrS\R8                  S\R8                  S\4S jrS\	R,                  S\\\R8                  4   SS4S jrS\4S jr \!S:X  a  \RD                  " \ " 5       5        gg)u  
Punto 2 della roadmap: backtest walk-forward del modello base Dixon-Coles,
misurato contro le probabilità implicite delle quote di chiusura.

Per ogni lega, il modello viene ri-addestrato periodicamente (default: ogni 7
giorni) usando SOLO le partite precedenti, e predice le partite del periodo
successivo. Nessun dato del futuro entra mai nel training (no look-ahead).

Metriche: log loss e Brier score multiclasse, confrontati con:
  - il mercato (probabilità implicite delle quote di chiusura, senza margine)
  - un baseline naive (frequenze storiche H/D/A della lega)

Uso:
    python scripts/backtest.py
    python scripts/backtest.py --eval-seasons 2023/24 2024/25 2025/26 --refit-days 14

Output: data/processed/backtest_base.csv (una riga per partita predetta)
    N)Pathdata	processedzbacktest_base.csvgŏ1w-!_?i!        )HDAreturnc                    [         R                  " U R                  U R                  U R                  U R
                  SS9nUR                  5       nUR                  S5        [        R                  " UR                  5       / SQS9nUR                  5         [        R                  " US   5      US'   S H  nX4   R                  [        5      X4'   M     U R                  n[         R"                  " US   R%                  5       S	U-
  US
   -  XSS   -  -   US
   5      US'   [         R"                  " US   R%                  5       S	U-
  US   -  XSS   -  -   US   5      US'   U$ )N	tigertips)hostportuserpassworddatabasea  
        SELECT l.code, m.season, m.match_date, h.name, a.name,
               m.home_goals, m.away_goals, m.result,
               m.imp_prob_home, m.imp_prob_draw, m.imp_prob_away,
               m.home_xg, m.away_xg
        FROM matches m
        JOIN leagues l ON l.id = m.league_id
        JOIN teams h  ON h.id = m.home_team_id
        JOIN teams a  ON a.id = m.away_team_id
        ORDER BY m.match_date
    )leagueseasondatehomeawayhgagresultmkt_hmkt_dmkt_axg_hxg_a)columnsr   )r   r   r   r   r   r   r   r   hg_trainr   r   ag_train)pymysqlconnectr   r   r   r   cursorexecutepd	DataFramefetchallcloseto_datetimeastypefloatalphanpwherenotna)argsconncurdfcr.   s         +C:\wamp64\www\Tigertips\scripts\backtest.pyload_matchesr8   )   s<   ??						$(MMKID
++-CKK 
 
	 
clln /I 
JB 	JJL6
+BvJ8U# 9 JJEXXbj..0 5yBtH4u&z7II2d8UBzNXXbj..0 5yBtH4u&z7II2d8UBzNI    r5   r   eval_seasons
refit_daysc                    X S   U:H     R                  SS9nUS   R                  U5      nUR                  5       (       d  [        R                  " 5       $ [        UR                  US4   R                  5       5      nUS   nUS   n/ n	S n
S nSn[        R                  " 5       nXx::  Ga  U[        R                  " US9-   nXDS   U:  US   U[        R                  " [        S9-
  :  -     nXEUS   U:  -  US   U:  -     nUR                  (       a  UnMt  [        [        US	   5      [        US
   5      -  5      n[        U5       VVs0 s H	  u  nnUU_M     nnnXS   -
  R                  R                  R!                  5       n["        R$                  " [&        * U-  5      nUU:X  a  U
OS n[(        R*                  " US	   R-                  U5      R!                  5       US
   R-                  U5      R!                  5       US   R!                  5       US   R!                  5       UUUS9nUR/                  5       UpUS-  nUR1                  SS9 H  n[(        R2                  " UUR4                  5      u  nn[(        R2                  " UUR6                  5      u  nn[(        R8                  " UUUUU5      u  nnn U	R;                  UUR<                  UR>                  UR4                  UR6                  UR@                  UUU URB                  URD                  URF                  S.5        M     UnXx::  a  GM  [I        SU S[K        U	5       SU S[        R                  " 5       U-
  S S3	5        [        R                  " U	5      $ s  snnf )Nr   T)dropr   r   r   )daysr   r   r!   r"   )home_idxaway_idx
home_goals
away_goalsweightsteamsx0r   Findex)r   r   r   r   r   r   model_hmodel_dmodel_ar   r   r     z: z partite predette, z fit, z.0fs)&reset_indexisinanyr'   r(   sortedlocuniquetime	TimedeltaTRAIN_MAX_DAYSemptyset	enumeratedtr?   to_numpyr/   expXIdcfitmapparams_vector
itertuplesteam_paramsr   r   predictappendr   r   r   r   r   r   printlen)!r5   r   r:   r;   r   	eval_mask
eval_dateswindow_start	last_daterows
warm_start
prev_teamsn_fitst0
window_endtrain
to_predictrE   itteam_idxdays_agorD   rF   modelratt_hdfn_hatt_adfn_ap_hp_dp_as!                                    r7   backtest_leaguer   I   sI   lf$%11t1<DX##L1I==??||~F!23::<=Ja=L2IDJ#'JF	B

#!BLLj$AA
6l\16llR\\~5V&VVX YtF||'CD<*46 7
%Ls5=)Cf,>>?%.u%56%5TQAqD%56 =04499BBD&&"x( !J.ZD6]&&x099;6]&&x099;Z(113Z(1135R
 "'!4!4!6J!&&U&3A>>%8LE5>>%8LE5JJueUE5IMCcKK AHHaff!((33177QWW	 	 4 "M 
#P 
BvhbT#6vhfYY[2c"!% &<<= 7s   Nprobsoutcome_idxc           
      4   [         R                  " U SS5      nX"R                  SSS9-  n[        U5      n[         R                  " U5      nSU[         R
                  " U5      U4'   [        [         R                  " [         R                  " U[         R
                  " U5      U4   5      5      * 5      [        [         R                  " [         R                  " X$-
  S-  SS95      5      [        [         R                  " UR                  SS9U:H  5      5      S.$ )z*Log loss, Brier multiclasse e accuratezza.g-q=r   T)axiskeepdimsr   )r   )loglossbrieracc)
r/   clipsumrg   
zeros_likearanger-   meanlogargmax)r   r   pnonehots        r7   metricsr      s    
ua A	EEq4E((AKA]]1F()F299Q<$%"''"&&299Q<+D)E"FGGHrwwrvvqza&7a@ABRWWQXX1X-<=> r9   bttrain_freqsc                    U R                  / SQS9R                  5       nUS   R                  [        5      R	                  5       nU/ SQ   R	                  5       nU/ SQ   R	                  5       n[
        R                  " US    Vs/ s H  oaU   PM	     sn5      n[        S[        U5       S35        SS	 S
S SS SS 3n[        U5        SU4SU4SU44 H0  u  p[        X5      n[        U	S	 US   S US   S US   S 35        M2     [        S5        UR                  S5       H  u  plUS   R                  [        5      R	                  5       n[        U/ SQ   R	                  5       U5      n[        U/ SQ   R	                  5       U5      nUS   US   -
  n[        SUS SUS   S SUS   S SUS 35        M     g s  snf )N)r   r   r   )subsetr   )rI   rJ   rK   r   z
=== Risultati backtest (z partite con quote) === z<18zlog lossz>10Brierzaccur.z>9zMercato (closing)z
Modello DCzNaive (frequenze)r   z>10.4fr   r   z>9.1%z(
Log loss per lega (modello vs mercato):rL   z<5z	 modello z.4fz   mercato z   gap z+.4f)dropnacopyr`   RESULT_INDEXr[   r/   vstackrf   rg   r   groupby)r   r   scoredoutcomemodel_pmkt_plgnaive_pheadernamer   mgrpoim_modelm_mktgaps                    r7   reportr      s   YY9Y:??AFX""<099;G67@@BG./88:Eii6(3CD3CRR3CDEG	&s6{m3J
KL3x
3'}XbMBF	&M(%0!7+('24 Ac
1Y</'
6/B1U8EBRST	4 

56>>(+]|,557#?@IIKRP78AACRHi 5#332b'79#5c": ;y)#.gc$ZA 	B , Es   Gc            
      *   [         R                  " SS9n U R                  SSSS/SS9  U R                  S	[        S
SS9  U R                  SSS SS9  U R                  S[        SSS9  U R                  SS SS9  [
        R                  " U 5        U R                  5       n[        U5      nUR                  =(       d    [        US   R                  5       5      nUR                  (       a  [        UR                  5      O[        n[        SU SUR                    SUR"                   SUR$                   35        X"S   R'                  UR                   5      )    n0 nUR)                  S5       Hm  u  pxUS   R+                  [,        5      R/                  5       R1                  / SQ5      R3                  S5      n	XR5                  5       -  R7                  5       Xg'   Mo     U Vs/ s H$  n[9        X'UR                   UR"                  5      PM&     n
n[:        R<                  " U
 Vs/ s H  oR>                  (       a  M  UPM     snSS9nUR@                  RC                  SSS 9  URE                  US!S"9  [G        X5        [        S#U 35        gs  snf s  snf )$Nz!Backtest walk-forward Dixon-Coles)descriptionz--eval-seasons+z2024/25z2025/26z.Stagioni da predire (default: 2024/25 2025/26))nargsdefaulthelpz--refit-days   z-Ogni quanti giorni ri-addestrare (default: 7))typer   r   z	--leaguesz'Codici lega da testare (default: tutte)z--alphag        zOPeso xG negli pseudo-gol di training: 0 = solo gol reali (default), 1 = solo xGz--outz+File di output (default: backtest_base.csv))r   r   r   zBacktest su z, stagioni z, refit ogni z giorni, alpha xG = r   r   )r   r   r   r   T)ignore_index)parentsexist_okFrG   z
Predizioni salvate in: )$argparseArgumentParseradd_argumentintr-   configadd_db_args
parse_argsr8   leaguesrQ   rS   outr   OUT_PATHrf   r:   r;   r.   rO   r   r`   r   value_countsreindexfillnar   r[   r   r'   concatrW   parentmkdirto_csvr   )parserr2   r5   r   out_path
train_onlyr   r   r   countspartsr   r   s                r7   mainr      sr   $$1TUF
(i=SM  O
S!L  N
3F  H
	sI  J J  L
vD	d	Bll;fR\%8%8%:;G!%tDHH~xH	L	T->->,? @((<TZZLJ K \&&t'8'899:JK%%h/X""<0==?GG	RYYZ[\!JJL0::< 0
   RT%6%6H 
  	u4u!GGAu44	HBOO$6IIheI$
2	%hZ
01 4s   "+J#J;J__main__)#__doc__r   sysrT   pathlibr   numpyr/   pandasr'   r#   r   dixon_colesr^   __file__resolver   PROJECT_ROOTr   r]   rV   r   r(   r8   strlistr   r   ndarraydictr   r   r   __name__exit r9   r7   <module>r      s3  &  
       H~%%'..55& ;.1DDQQ'",, @; ;c ;c ; #;(*;|2:: BJJ 4 Br|| B$sBJJ*? BD B4%c %P zHHTV r9   