a
    L$jD'  ã                   @   sÂ  d Z ddlZddlZddlZddlZddlmZ ej	j
ddd� e d¡ e dd	¡ d
\ZZddgZg d¢ZdddœZdZdZdd„ e d¡D ƒZejedd�Zejed ddd�ed< eed  ¡  Zeed dked dk @   ¡ Zg ZeD ]†Zd e› �Zeee ekee ek @   ¡ Ze  d¡j!ed!d"�Zeed#< ee ed$< ed%e› d&� ed'< ed(e› � ed)< e "e¡ qòejedd�Z#e#j d$d*d+�j!ed!d"�Z#e#  d¡j$dd,�Z#e %e#d' dkd-e#d'  ej&¡e#d.< e#d/ e#d#  'e¡k (e)¡e#d0< e#j*g d1¢d2�j$dd,�Z#e %e#d0 d3ke#d. d3 d4¡e#d5< e+e#ƒZ,e#d6  -¡ Z.e/d7e,› d8e.› d9e#j0 1¡ d:›d;e#j2 1¡ d<›d=�	ƒ e/d>ƒ e/d?ƒ e# 3d6¡Z4e 5e4 6¡ e4d0  7¡ e4d0  1¡ e4d5  1¡ e4d5  7¡ d@œ¡Z8e#d0  1¡ Z9ej:e8dA e9 dB e8dC dD�Z;e9d3e9  ej:d-e8dC  e8dC dD� Z<e=e;e< dEƒZ>e=e9d3e9  e> d3 d-ƒZ?e9e? d3e9 e?  Z@ZAe/dFe@dG›dHeAdG›dIe9d:›dJe?dK›dL�	ƒ e@e8dM  e@eA e8dC   e8dN< ejB CdOe@e8dM  eAe8dC  e8dM  ¡e8dP< ejB CdQe@e8dM  eAe8dC  e8dM  ¡e8dR< e8  dN¡ZDe/dSd6dT›dUdCdV›dUdWdX›dUdYdZ›dUd[d\›�
ƒ eD E¡ D ]R\ZFZGe/dSeFdT›dUe)eGjHƒdV›dUeGjId]›dUeGjJd^›d_eGjKd`›daeGjLd`›db�ƒ �q<e/dcƒ e/ddƒ e#d5  1¡ ZMe7dedf„ e8jND ƒƒZOeOe,e.  ZPePe8dC  e8dg< e=e8dh jQd3di�e8dg  1¡  djƒZReRdk�reReRe8dg   ndje8dk< eMe8dk e8dh eM   e8dl< eRdk�rje Sd-d-e=eRdmƒ d-e8dg    ¡ndje8dn< ejT Ude8dl  e8dn  Vdej&¡ ¡e8do< e/dpe SeP¡dq›dre SeR¡dq›dseRdk�rÊdtndu› dv�ƒ e/dSd6dT›dUdCdV›dUdwdx›dUdydz›dUd{d|›dUd}dZ›�ƒ e8  dl¡ E¡ D ]h\ZFZGe WeGjX¡�r6d~neGjXd›ZYe/dSeFdT›dUe)eGjHƒdV›dUeGjZd€›dUeGj[d�›dUeGj\d‚›dUeY› �ƒ �qe/dcƒ e/dƒƒ g Z]e8 E¡ D ]˜\ZFZGe#j^e#j_eFkd5f Z`e+e`ƒdBk �s¢e`jad3di�dk�râ�q¢e` 1¡ e`jad3di�e Se+e`ƒ¡  ZbdBd3ejT Uecebƒ¡  Zde] "eFe+e`ƒe` 1¡ ebedf¡ �q¢ej5e]g d„¢d…�  d†¡j$dd,�Zee+eeƒZfeejNd3 eed‡< eed† ef eed‡  jgdddˆ…  h¡ jgdddˆ… eed‰< e/dŠef› d‹�ƒ e/dSd6dT›dUdCdV›dUdŒdx›dUd�dX›dUdŽdx›dUd�dx›d��ƒ ee E¡ D ]x\ZiZGeGjjdOk �reGjZdk �rd‘nd’Zke/dSeGj_dT›dUe)eGjHƒdV›dUeGjZd€›dUeGjbd“›dUeGjdd”›dUeGjjd”›dSek› �ƒ �qøeeeejjdOk eejZdk @  d6  l¡ Zme/d•em�r emnd–› �ƒ e/dcƒ e/d—e› d˜�ƒ e8e8jHek jN l¡ Zne/d™en�räennd–› dše+enƒ› d›e.› dœen�	re)e8j^endCf  7¡ ƒnd› d›e,› d��ƒ e/džƒ e/dcƒ e/dŸed ›d¡�ƒ e#  d¡j$dd,�Zoe)e+eoƒe ƒZpeojgdep… eojgepd…  ZqZrd¢d£„ Zseq 3d6¡d5  td¤d¥g¡Zuer 3d6¡d5  1¡ Zveujwev xd¦¡d§d¨� *¡ Zyeyeyd¥ d©k Zye+eyƒdªk�
rre zeyd¤ eyd¦ ¡Z{e |eyd¤ eyd¦ ¡Z}e/d«e+eyƒ› d¬�ƒ e/d­e{d d®›d¯e{d3 d°›d±e}d d®›d¯e}d3 d°›dv�	ƒ e/d²ƒ ne/d³ƒ eserd5 j~ƒ\ZZ€e/d´e+erƒdµ›d;erj2 1¡ d¶›d·ed®›d¸e€d¹›�ƒ e/dSdºd»›dUd¼d½›dUd¾d¿›dUdÀdx›dUd†dX›�
ƒ dZ�dÁD �]"Z‚dÂD �]Zƒeueud¤ eƒk eud¥ e‚k@  jN l¡ Z„ererj_ …e„¡  Z†e+e†ƒdBk �rL�q ese†d5 j~ƒ\ZbZddÃeƒdÄ›dÅe‚› �Z‡e„�r€da we„¡ndÆZˆe/dSe‡d»›dUeˆddÇ… d½›dUe+e†ƒd¿›dUe†j2 1¡ dÈ›dUeddÉ›�
ƒ eqeqj_ …e„¡  Z‰e+e‰ƒdk�r e‰j2 1¡ ZŠe�du �seŠe�d k�r eŠeƒe‚e„fZ��q �
qöe�du�r¾e�\ZiZƒZ‚Z„ererj_ …e„¡  Z†ese†d5 j~ƒ\ZbZde/dÊeƒdÄ›dÅe‚› dËe„�rre„ndÆ› �ƒ e/dÌe+e†ƒ› d;e†j2 1¡ d<›d¸edd¹›dÍe€d¹›�ƒ e/dÎe€d¹›dÏ�ƒ dS )Ða‰  
Statistically-honest league-pruning toolkit for the live Kalshi CLV strategy.
Reconstructs the signal set (no exclusions) and runs four analyses:

  A. Empirical-Bayes shrinkage  -- pulls each league's estimate toward the global
     mean by an amount set by its noise, so small-n leagues can't look extreme.
       A1 beta-binomial on WIN RATE
       A2 normal-normal (James-Stein) on per-bet NET ROI  -> P(true edge < 0)
  B. Benjamini-Hochberg FDR     -- per-league test vs breakeven, corrected for
     testing many leagues at once.
  C. Minimum-n eligibility gate -- a league isn't judged until it has >= MIN_N bets.
  D. Walk-forward validation of "drop leagues below an ROI threshold": tune the
     drop-set on TRAIN, lock it, score on the untouched TEST. Plus the key
     diagnostic: does TRAIN league-ROI even predict TEST league-ROI?

Pure analysis -- nothing here touches the live pipeline.
é    N)Ústatszutf-8Úreplace)ÚencodingÚerrorsz	E:\soccerzdisplay.widthéª   )çš™™™™™©?g¸…ëQ¸¾?ÚhomeÚaway)Z	game_dater   r	   ÚHÚA)r   r	   é(   g333333ã?c                 C   s,   g | ]$}|  d ¡r|dkrt d| ¡‘qS )z.csvztest.csvz
live_data/)ÚendswithÚpdZread_csv)Ú.0Úf© r   ú-E:\soccer\research\analysis\_league_honest.pyÚ
<listcomp>!   s   ÿr   Z	live_dataT)Zignore_indexZ	timestampZmixedZcoerce)Úformatr   ZtsZstatusZPREÚelapsedZclv_kalshi_Úfirst)ZkeepÚsideZclvZkalshi_Z_askZaskZ	pin_fair_Úp_winF)Z	ascending)Údropg      ð?ÚoddsÚftrÚwon)r   r   r   )Zsubseté   g      ð¿ÚnetÚleaguezreconstructed z bets across z leagues | overall WR z.1%z | ROI z+.1%Ú
zn==============================================================================================================zXA1  EMPIRICAL-BAYES SHRINKAGE on WIN RATE (beta-binomial prior fit by method of moments))ÚnÚwinsÚwrÚroir   r#   é   r!   )Zweightsg�íµ ÷Æ°>z  prior: Beta(a0=z.1fz, b0=z)  -> prior mean z, strength ~z.0fz pseudo-betsr"   Ú	wr_shrunkr   Úwr_logffffffî?Úwr_hiz  z<8ú z>4zraw WRz>7z	shrunk WRz>10z90% CIz>18z>7.1%z>10.1%z   [z>5.1%ú,ú]zo
==============================================================================================================z]A2  EMPIRICAL-BAYES SHRINKAGE on per-bet NET ROI (James-Stein normal model) -> P(true edge<0)c                 c   s8   | ]0}t jt j|kd f tj|df  d  ¡ V  qdS )r   r$   r%   N)ÚsigÚlocr   ÚperÚsum)r   Úlgr   r   r   Ú	<genexpr>V   ó    r1   Ús2r$   ©Zddofç        ÚwÚ
roi_shrunkgê-�™—q=Zpost_sdÚp_negz  pooled within-league sd(net)=z.3fz | between-league sd(edge)=z (zleagues DO differzCtau2=0 -> no detectable between-league signal; all shrink to globalú)zraw ROIz>8z
shrunk ROIz>11zshrink wz>9z	P(edge<0)z   n/az>9.1%z>8.1%z>11.1%z>9.2fzSB  BENJAMINI-HOCHBERG FDR  -- per-league two-sided test vs breakeven (mean net = 0))r   r!   r$   ÚzÚp)Úcolumnsr;   ZrankéÿÿÿÿÚbh_qz
  testing z% leagues; flag = BH q<0.05 AND losingZROIr:   zraw pzBH qz  flagzLOSE*Ú z>+7.2fz>8.4fz-  --> survive FDR as genuinely unprofitable: ZNONEz%C  MINIMUM-N ELIGIBILITY GATE (MIN_N=z*) -- below this, no power; pool the leaguez  eligible for judgement: z  (ú/z
 leagues, z bets)zW  everything else is statistically indistinguishable from the pooled rate at current n.zPD  WALK-FORWARD: tune a 'drop leagues below ROI threshold' rule on TRAIN (first z.0%z), score TESTc                 C   sR   t | ƒ}|dk r tdƒtdƒfS |  ¡ | jdd�t |¡  }|dtj |¡ fS )Nr%   Únanr   r4   )	ÚlenÚfloatÚmeanÚstdÚnpÚsqrtr   ÚnormÚcdf)r   r!   r:   r   r   r   Úzp‹   s    rJ   rD   ÚsizeÚte_roiÚinner)Zhowé   é   z1  D0 PERSISTENCE (leagues with >=5 TRAIN bets, n=z
 leagues):z+     corr(TRAIN ROI, TEST ROI):  Pearson r=z+.2fz (p=z.2fz) | Spearman rho=zc     --> if ~0, a league being bad in TRAIN tells you nothing about TEST, and dropping CANNOT work.z8  D0: too few overlapping leagues to assess persistence.z#
  TEST baseline (drop nothing): n=z>3z>+7.1%z | z=z | p=z.4fz7rule (drop if TRAIN ROI < thr & TRAIN league-n >= minL)z<52Zdroppedz<22ZTESTnz>5ZTESTroi)r   rN   é
   )r5   gš™™™™™¹¿g      Ð¿g      à¿zthr<z+.0%z, minL>=z(none)é   z>+8.1%z>7.4fz$
  LOCKED rule (max TRAIN ROI): thr<z  drops z  -> TEST: n=z   vs baseline p=z@  Honest read: if the locked rule's TEST p is not clearly below z%, league-dropping is in-sample noise.)‹Ú__doc__ÚosÚsysZnumpyrF   Zpandasr   Zscipyr   ÚstdoutÚreconfigureÚchdirZ
set_optionZEDGE_LOZEDGE_HIZSIDESZGAMEZSIDE_LETTERZMIN_NZSPLITÚlistdirZdfsÚconcatZdfZto_datetimeZnotnaÚcopyZpreZentriesr   ÚcÚqZsort_valuesZdrop_duplicatesÚappendr,   Zreset_indexÚwhererA   ÚmapZastypeÚintZdropnarB   ÚNZnuniqueÚKÚprintr   rD   r   ÚgroupbyÚgZ	DataFramerK   r/   r.   ÚmZaverageZvar_obsZsamp_varÚmaxZtau2_wrZkappaZa0Zb0ZbetaZppfZshowZiterrowsr0   Úrr!   r#   r&   r'   r(   ZmuÚindexZssZsigma2ÚvarZtau2rG   rH   rI   r   Zisnar8   Zpnr$   r7   r6   Zrowsr-   r   ÚsrE   r:   Úabsr;   ZfdrZmmZilocZcumminÚ_r>   ÚflagÚtolistZsig_loseZeligZsoZcutZtrZterJ   ZaggZtr_roirL   ÚjoinÚrenameZbothZpearsonrZprZ	spearmanrZspÚvaluesZzbZpbZbestZminLZthrr   ZisinZkeptÚtagZddZtr_keptZtroir   r   r   r   Ú<module>   s   

 
 &$ "2
ÿ&* ,,
0L""6* ÿ
8F "  4: R $ÿÿ
:
20

"B

&0