a
    �*ej  ã                   @   s’   d Z ddlZddlZej dd¡ ddlZddlZh d£Z	h d£Z
h d£ZdZdd	„ Zd
d„ Zddd„Zdd„ Zdd„ Zdd„ ZedkrŽeƒ  dS )a  
Is Pinnacle structurally mis-calibrated in SOUTH AMERICA? (read-only, trades nothing)

Built 2026-07-25 from the user's hypothesis: "there's something structurally wrong
with South American leagues." Pooling regions is the point -- no single SA league
has the sample to say anything (BSA n=32, PE1 n=12, CL1 n=8), but pooled they do.

Same engine as pin_calibration_by_league.py: EVERY fixture with Pinnacle odds and
a result, not just the ones we bet.

THE THREE CONTROLS THAT MAKE THIS MORE THAN A SCAN:
  1. DROP THE MOTIVATING LEAGUE. The hypothesis came from BSA's 0-for-12, and BSA
     is 44% of the SA sample. If the pattern is really just BSA, removing it kills
     the effect. (It doesn't -- the effect gets STRONGER.)
  2. SIGN CONSISTENCY across independent leagues. pin_calibration_by_league's own
     standing rule: randomly-signed deviations at small n = noise; a real
     structural bias is consistent across comparable leagues. Reported as a sign
     test.
  3. WHICH SIDE WE ACTUALLY BET. A calibration error only costs us money if it
     lands on the side we take. This is the step that stops a real finding from
     being mis-read as an explanation for a bad record.

RESULT ON FIRST RUN (2026-07-25):
  SA n=73: homes implied 48.2% -> actual 60.3% (z+2.06); draws 27.4% -> 16.4%
  (z-2.10); aways 24.4% -> 23.3% (z-0.21). Excluding BSA (n=41) the home/draw
  effect PERSISTS (z+1.87 / -1.55). Home z>0 in 5/5 SA leagues (sign test p=.062).
  Europe/N.America/Asia all flat (|z| <= 1.3).
  BUT: 25 of our 28 SA bets are AWAY, and away is the one side calibrated fine.
  So the finding does NOT explain the -35.3% SA record (which is z=-0.46 on win
  count = noise). If anything the home under-pricing is an OPPORTUNITY.

Usage:  python research\region_calibration_test.py
é    NzE:\soccer\research>   ZPE1ZAR1ÚBSAZBR2ZCO1ZCL1>   ZUSLZNWSLZMX1ZCANZMLS>   ZCN1ZKO1ZJP1r   c                 C   s(   | t v rdS | tv rdS | tv r$dS dS )Nú	S.Americaú	N.AmericaÚAsiaÚEurope)ÚSAÚNAÚASIA©Úlg© r   ú-E:\soccer\research\region_calibration_test.pyÚregion/   s    r   c                 C   s6   t  | | d|  ¡}|dkr.|||   | S tdƒS )Né   r   Únan)ÚmathÚsqrtÚfloat)ÚnÚpZactualZsdr   r   r   Úz_for9   s    r   çÍÌÌÌÌÌÜ?c                 C   s   dt  |d|  |  ¡ d S )zCSmallest calibration error (pp) detectable at 95% conf / 80% power.gffffff@r   éd   )r   r   )r   Úbaser   r   r   Ú
detectable>   s    r   c                    sè   t | ƒ}|dk r.td|d›d|d›d�ƒ d S d|d›d|d›�g}dD ]t\‰ ‰t‡ fdd	„| D ƒƒ| }t‡fd
d	„| D ƒƒ}| ˆ› d|d d›d|| d d›dt|||ƒd›d�¡ qH| dt|ƒd›d�¡ td |¡ƒ d S )Né   ú  Z26sú n=Ú4dz  -- too few))ÚpfhÚH)ÚpfdÚD)ZpfaÚAc                 3   s   | ]}|ˆ  V  qd S )Nr   ©Ú.0Úx©Úkeyr   r   Ú	<genexpr>J   ó    zline.<locals>.<genexpr>c                 3   s   | ]}|d  ˆ kV  qdS )ÚftrNr   r$   )Úletterr   r   r)   K   r*   ú r   ú5.1fz->z (zú+5.2fú)z
| detects z.0fZpp)ÚlenÚprintÚsumÚappendr   r   Újoin)ÚsZlabelr   ÚoutÚimpZcntr   )r(   r,   r   ÚlineC   s    &ÿr9   c                     s6  t  ¡ } tdƒ dD ]‰t‡fdd„| D ƒˆƒ qtdt› d�ƒ tdd„ | D ƒdƒ td	d„ | D ƒd
t› �ƒ tdd„ | D ƒt› d�ƒ tdƒ g }ttƒD ]Ò‰ ‡ fdd„| D ƒ}t|ƒ}|dk rÆqžtdd„ |D ƒƒ| }tdd„ |D ƒƒ}tdd„ |D ƒƒ| }tdd„ |D ƒƒ}| 	ˆ |t
|||ƒt
|||ƒf¡ tdˆ d›d|d›d|d d d›d|d d d›�ƒ qžt|ƒ}tdd„ |D ƒƒ}	td d„ |D ƒƒ}
td!|	› d"|› d#|
› d"|› �ƒ td$|› d%dd&|  d'›d(�ƒ td)ƒ g }t ¡ D ]>}t|ƒ}|�rò|d* tjk�rò|d+ tv |d,< | 	|¡ �qòd-d.d/„ fd0d1d/„ ffD ]Þ\}‰‡fd2d„|D ƒ}d3D ]¶‰‡fd4d„|D ƒ}|�sˆ�qht|ƒ}td5d„ |D ƒƒ}td6d„ |D ƒƒ| }td|d7›d8ˆd9›d|d:›d;|d<›d=|| d> d?›d@tdAd„ |D ƒƒ| d> d?›dB|d> dC›dD�ƒ �qhtƒ  �qJtdEƒ d S )FNz?A) PINNACLE CALIBRATION BY REGION (all fixtures with a result)
)r   r   r   r   c                    s    g | ]}t |d  ƒˆ kr|‘qS r
   )r   ©r%   Úf)Úrgr   r   Ú
<listcomp>W   r*   zmain.<locals>.<listcomp>z(
B) CONTROL -- does SA survive dropping z( (the league that raised the question)?
c                 S   s   g | ]}|d  t v r|‘qS r
   )r   r:   r   r   r   r=   [   r*   zSA allc                 S   s(   g | ] }|d  t v r|d  tkr|‘qS r
   )r   Ú
MOTIVATINGr:   r   r   r   r=   \   r*   zSA excluding c                 S   s   g | ]}|d  t kr|‘qS r
   )r>   r:   r   r   r   r=   ^   r*   z alonezB
C) SIGN CONSISTENCY across SA leagues (noise is randomly signed)
c                    s   g | ]}|d  ˆ kr|‘qS r
   r   r:   r
   r   r   r=   c   r*   r   c                 s   s   | ]}|d  V  qdS )r   Nr   r$   r   r   r   r)   g   r*   zmain.<locals>.<genexpr>c                 s   s   | ]}|d  dkV  qdS )r+   r    Nr   r$   r   r   r   r)   h   r*   c                 s   s   | ]}|d  V  qdS )r!   Nr   r$   r   r   r   r)   i   r*   c                 s   s   | ]}|d  dkV  qdS )r+   r"   Nr   r$   r   r   r   r)   j   r*   r   Z6sr   r   z  home zéÿÿÿÿé   r/   z	   draw zé   c                 s   s   | ]}|d  dkrdV  qdS )r@   r   r   Nr   ©r%   Úrr   r   r   r)   n   r*   c                 s   s   | ]}|d  dk rdV  qdS )rA   r   r   Nr   rB   r   r   r   r)   o   r*   z
  home z>0 in ú/z leagues, draw z<0 in z  P(all z one way by chance) = g      à?z.3fz  (two-tailed sign test)zA
D) DOES IT LAND ON THE SIDE WE BET? (forward bets, post-freeze)
ÚgdZleagueÚsazSouth Americac                 S   s   | d S ©NrF   r   ©Úbr   r   r   Ú<lambda>z   r*   zmain.<locals>.<lambda>zrest of worldc                 S   s
   | d  S rG   r   rH   r   r   r   rJ   {   r*   c                    s   g | ]}ˆ |ƒr|‘qS r   r   ©r%   rI   )Úselr   r   r=   |   r*   )ÚhomeÚawayc                    s   g | ]}|d  ˆ kr|‘qS ©Úsider   rK   rO   r   r   r=   ~   r*   c                 s   s   | ]}|d  V  qdS )ÚwonNr   rK   r   r   r   r)   ‚   r*   c                 s   s*   | ]"}|d  rd|d  d ndV  qdS )rQ   r   Úpxr?   Nr   rK   r   r   r   r)   ƒ   r*   Z14sr-   Z5sZ3dz W=Z2dz WR=r   r.   z
% implied=c                 s   s   | ]}|d  V  qdS )rR   Nr   rK   r   r   r   r)   …   r*   z% ROI=z+7.1fú%zD  A calibration error only costs money on the side we actually take.)ÚPZload_fixturesr2   r9   r>   Úsortedr   r1   r3   r4   r   ÚFÚfire_with_sideZFREEZE_DATE)ÚfxZrowsr6   r   ZiHZcHZiDZcDÚkÚphÚpd_Zbetsr;   rI   ZlblZssÚwZroir   )r   r<   rL   rP   r   ÚmainR   sj    ÿ":  

ÿ4ÿÿ
r]   c              
   C   s,  | d D �]}t  | d¡¡t  | d¡¡t  | d¡¡  }}}d|||fv s|dkr|dkr|dksjqt  |||f¡}g }t j ¡ D �]‚\}}t  |d|¡\}	}
t  |d|¡\}}|	du sˆ|du sˆd	|	  k rÚdk rˆn qˆd	|  k ròdk söqˆ qˆ|	|k�r|	|
|  }}}n|||	  }}}|du sˆd	|  k �rBdk �sFqˆ qˆ|| | ||  }|| | ||  }||k rˆt jd	 |  k�ršt jd k �sžqˆ qˆt jd	 |  k�rÂt jd k �rÈqˆ nqˆ| d
 dk�rà|dk�pô| d
 dk�oô|dk}| t	||||d�¡ qˆ|rt
|dd„ d�  S qdS )zHfire_xlow, but keeping which side qualified (the base version drops it).ZpreZpin_homeZpin_drawZpin_awayNr   ZkalshiZpolyr   r+   r    rM   r#   rN   )ÚclvrR   rQ   rP   c                 S   s   | d S )Nr^   r   )Údr   r   r   rJ   ¨   r*   z fire_with_side.<locals>.<lambda>r'   )rV   Z_fÚgetZ	fair_multZSIDXÚitemsZ
book_quoteZBANDr4   ÚdictÚmax)rX   rC   rZ   r[   ZpaZpfZcandsrP   ZsiZkmZkaZpmZpa_ZmidrR   Úotherr^   ZocrQ   r   r   r   rW   Š   s>    ÿ
&>
".(ÿrW   Ú__main__)r   )Ú__doc__Úsysr   ÚpathÚinsertZpin_calibration_by_leaguerT   Zforward_test_unique_bookrV   r   r   r	   r>   r   r   r   r9   r]   rW   Ú__name__r   r   r   r   Ú<module>   s"   !

8"