o
    Ä½jn.  ã                   @   sX  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 ddl	m
Z
 eeƒ ¡ jZej dd¡ ej dd¡ ddlZddlmZ dd	lmZ e
d
ƒZdZdZeeeddƒƒZg d¢ZddddddddddddddœZdd„ Zdd „ Z d!d"„ Z!d#d$„ Z"e#d%kr‹e$ej%ƒd&kr‹e"ƒ  d'd(„ Z&e#d%kr¦e$ej%ƒd&kr¨ej%d& d)krªe&ƒ  dS dS dS dS )*aõ  
group_study.py -- [2026-09-29] The user's plan: look back over the saved days, separate the
stock-days into pattern groups, then inside each group compare the winners with the
losers and find the point where they start to differ.

Unit: every stock-day on the saved 9:28/9:30 lists (bars/ + flow/ + 14-day reference).
Group: the shape of the first 45 minutes, decided at 10:15 (known in real time):
  1 OPENING DRIVE   >= +2% over the open, above VWAP, within 1% of the day's high
  2 UP, PULLED BACK >= +1% over the open, above VWAP, more than 1% off the high
  3 V RECOVERY      fell >= 2% under the open, back above VWAP
  4 SPIKE & FADE    first-30-min high >= +2% over the open, now below VWAP
  5 SELLING SLIDE   <= -2% under the open, below VWAP
  6 WEAK DRIFT      below VWAP (the rest)
  7 FLAT / CHOP     above VWAP, the rest
Outcome after 10:15: winner = +2% or more from the 10:15 price to the close,
loser = -2% or worse, flat in between.
Divergence: for each measure, every 5 minutes from 10:15 to 12:30, AUC winners vs losers
(0.5 = no difference); the first minute with AUC >= 0.70 (or <= 0.30) that ALSO holds in
both halves of the days (>= 0.62 / <= 0.38 each). For each such point: how much of the
winners' final move they had already made by then.
é    N)Údatetime)ÚPath)ÚZoneInfoz/var/www/screener/tradez%/var/www/screener/trade1/sim/analysis)Ú_r2_eff)ÚauczAmerica/New_Yorké-   éµ   é   )z1 OPENING DRIVEz2 UP, PULLED BACKz3 V RECOVERYz4 SPIKE & FADEz5 SELLING SLIDEz6 WEAK DRIFTz7 FLAT / CHOPzprice change since 10:15 %zprice vs VWAP %zprice vs open %zprice vs day high %zposition in day range (0-1)zlast 15 min change %zbuy share, last 15 minzbuy share since the openz!RVOL so far (vs 14-day by minute)zlast 15 min volume vs normalzsmoothness (R2, 15 bars)zstraightness (15 bars)zprice vs yesterday's high %©Úret_since_1015Úvwap_pctÚret_openÚoff_highÚ	range_posÚret15Úbuy15Úbuy_cumÚrvolÚvol15xÚr2ÚeffÚvs_prev_highc                  c   sâ   � t t d¡ƒD ]f} t t | d¡¡}|d }|d D ]R}td | |› d� }t ||¡}dd„ |d	  |i ¡ d
g ¡D ƒ}t	|ƒdk sG|sHqt
rOt
|ƒsOq| ¡ rZt | ¡ ¡n
dgd dgd dœ}|||||fV  qqd S )Nzbars/bars_2026-*.json.gzÚrtÚdateÚtop30_currentÚflowz.jsonc                 S   s:   g | ]}d t  |d t¡ d¡  krdk rn n|‘qS )z09:30r   z%H:%Mz16:00)r   ÚfromtimestampÚETÚstrftime)Ú.0Úb© r!   ú:/var/www/screener/trade/reports/open_window/group_study.pyÚ
<listcomp>C   s    *ÿzstock_days.<locals>.<listcomp>ÚsymbolsÚbarséÈ   g      ð?é†  )ÚbuyÚsell)ÚsortedÚHEREÚglobÚjsonÚloadÚgzipÚopenÚREFÚgetÚlenÚONLYÚexistsÚloadsÚ	read_text)ÚpÚdÚdayÚsÚfpÚrefr%   Úflr!   r!   r"   Ú
stock_days<   s    €",õýr?   c                 C   sd  i }| D ]}t  |d t¡}|||jd d |j d < q| d d }g g g g g f\}}}	}
}|||ddf\}}}}}tdƒD ]W}| |¡}d}|rw|d }t||d	 ƒt||d
 ƒ}}|d }||7 }||d	 |d
  |d  d
 | 7 }| 	|¡ | 	|¡ |	 	|¡ |
 	|¡ | 	|r“|| n|¡ q?|d |d }}i }t
D ]é}|| }t||d |d … ƒt||d |d … ƒ}}t|d|d … ƒt|d|d … ƒ}}t|d |d |d … ƒ}t||d |d … ƒ\}}||t  d d |||  d d || d d |||  d d || |	| k�r-||	|  || |	|   nd|||d   d d || �rD|||  nd|| �rP|||  ndt|
d|d … ƒt|d | dƒ |�rtt|
|d |d … ƒ| nd||| d¡�r‡||d  d d nddœ||< q¤t|dd… ƒ}||||	|||| d d |	t | d d |d dœ	S )z?Forward-filled per-minute series + the measures at each minute.r   é	   é<   é   é   g        r'   é   é   é   r	   r(   r)   é   NÚvol_per_minéd   g      à?é   Úcum_volÚ	prev_highr
   i�  )	r0   ÚcloseÚhiÚloÚvwapÚmÚfirst30_hi_pctÚlow_pctÚfinal)r   r   r   ÚhourÚminuteÚranger2   ÚmaxÚminÚappendÚMINUTESÚsumr   ÚT)r%   r>   r=   Úbyr    ÚtÚorM   rN   rO   ÚvolÚpvÚlastÚhÚlÚcvÚcpvrQ   Úvr(   r)   ÚoutÚcÚbvÚsvÚcbÚcsÚnorm15r   r   Ú
first30_hir!   r!   r"   Ú
per_minuteN   sb   
$



2*0$$"óýrq   c                 C   sÔ   | d t  }|d dkr|d dkr|d dkrtd S |d dkr,|d dkr,td S | d	 d
kr<|d dkr<td S | d dkrL|d dk rLtd S |d d
kr\|d dk r\td S |d dk rftd S td S )NrQ   r   rE   r   r   r   éÿÿÿÿrC   rS   éþÿÿÿrR   rF   rD   r	   é   )r]   ÚGROUPS)ÚxÚfr!   r!   r"   Úgroup_ofƒ   s   $rx   c                     s>  g } t ƒ D ]@\}}}}}t|||ƒ}|d |d t  d d }|  ||t|ƒ||d |d  d d |dkr9dn|dkr?d	nd
|dœ¡ qtdd„ | D ƒƒ}t|d t|ƒd … ƒ‰tt| ƒ› dt|ƒ› d|d › d|d › d|t|ƒd  › d�
ƒ tdd›ddd›ddd›ddd›ddd›ddd›ddd ›dd!d"›�ƒ t	D ]\‰ ‡ fd#d$„| D ƒ}	|	s¯q¡d%d$„ |	D ƒ}
tˆ d›dt|	ƒd&›dt
d'd(„ |	D ƒƒd&›dt
d)d(„ |	D ƒƒd&›dt
d*d(„ |	D ƒƒd&›dt |
¡d+›d,t |
¡d-›d,t
d.d(„ |	D ƒƒd/›�ƒ q¡t	D �]›‰ ‡ fd0d$„| D ƒ}	d1d$„ |	D ƒ}d2d$„ |	D ƒ}td3ˆ › d4t|	ƒ› dt|ƒ› d5t|ƒ› d6�	ƒ t|ƒd7k �s?t|ƒd7k �rEtd8ƒ �q td9d: d;d(„ t|d<d=„ d>�d d?… D ƒ¡ ƒ td@d: dAd(„ t|dBd=„ d>�d d?… D ƒ¡ ƒ t dCd(„ |D ƒ¡}tdDdEdF›ddGdH›dIdJdF›ddKdL›ddMdN›�
ƒ t ¡ D ]ÿ\‰}t‡fdOd$„|D ƒ‡fdOd$„|D ƒƒ}d }tD ]…‰‡‡fdPd$„|D ƒ}‡‡fdQd$„|D ƒ}t||ƒ}
t‡‡‡fdRd$„|D ƒ‡‡‡fdRd$„|D ƒƒ}t‡‡‡fdSd$„|D ƒ‡‡‡fdSd$„|D ƒƒ}|
dTk�r|dUk�r|dUk�s|
dVk�r:|dWk�r:|dWk�r:t ‡fdXd(„|D ƒ¡}ˆ|
||t |¡t |¡|f} n�q¶|�rŒ|\‰}
}}}}}dYdZˆ d[  › d\dZˆ d[ d]›�}tdD|dF›d|d^›dI|› d_|
d`›da|d`›db|d`›dcddde›d|df›dg|dh›d|di›dj|dk›dl�ƒ �q›tdD|dF›d|d^›dm�ƒ �q›�q d S )nNrT   rM   rC   rI   r0   rE   ÚWrs   ÚLÚF)r:   ÚsymÚgroupÚafterÚocÚclsrv   c                 S   ó   h | ]}|d  ’qS ©r:   r!   ©r   Úrr!   r!   r"   Ú	<setcomp>œ   ó    zmain.<locals>.<setcomp>z stock-days, z days (r   z .. rr   z); halves split at Ú
zgroup at 10:15Ú20ú Únz>4ÚwinÚflatÚlosezavg 10:15->closez>17Úmedú>6zbig (open->close >=5%)z>23c                    ó   g | ]
}|d  ˆ kr|‘qS ©r}   r!   rƒ   ©Úgr!   r"   r#   ¢   ó    zmain.<locals>.<listcomp>c                 S   s   g | ]}|d  ‘qS )r~   r!   rƒ   r!   r!   r"   r#   ¥   r†   Ú4c                 s   ó   � | ]	}|d  dkV  qdS )r€   ry   Nr!   rƒ   r!   r!   r"   Ú	<genexpr>¦   ó   € zmain.<locals>.<genexpr>c                 s   r–   )r€   r{   Nr!   rƒ   r!   r!   r"   r—   ¦   r˜   c                 s   r–   )r€   rz   Nr!   rƒ   r!   r!   r"   r—   §   r˜   z+16.2fú% z+5.2fc                 s   s   � | ]	}|d  dkV  qdS )r   r	   Nr!   rƒ   r!   r!   r"   r—   §   r˜   Ú23c                    r�   r‘   r!   rƒ   r’   r!   r"   r#   ª   r”   c                 S   ó   g | ]
}|d  dkr|‘qS )r€   ry   r!   rƒ   r!   r!   r"   r#   «   r”   c                 S   r›   )r€   rz   r!   rƒ   r!   r!   r"   r#   ¬   r”   z
=== z: z
 winners, z losers ===rt   z'   too few winners or losers to comparez   winners: z, c                 s   ó<   � | ]}|d  › d|d dd… › d|d d›d�V  qdS ©r|   r‰   r:   r	   Nr~   z+.0fú%r!   rƒ   r!   r!   r"   r—   ±   ó   €: c                 S   s
   | d  S ©Nr~   r!   ©r„   r!   r!   r"   Ú<lambda>±   s   
 zmain.<locals>.<lambda>)Úkeyé   z   losers:  c                 s   rœ   r�   r!   rƒ   r!   r!   r"   r—   ²   rŸ   c                 S   s   | d S r    r!   r¡   r!   r!   r"   r¢   ²   s    c                 s   s   � | ]}|d  V  qdS )r~   Nr!   rƒ   r!   r!   r"   r—   ³   ó   € z   ÚmeasureÚ34zat 10:15 AUCú>12z  zfirst divergence (both halves)zwinners / losers therez>24zwinners move madez>18c                    s    g | ]}|d  d t  ˆ  ‘qS ©rv   rQ   ©r]   rƒ   )Úkr!   r"   r#   ¶   ó     c                    ó    g | ]}|d  d ˆ ˆ  ‘qS r©   r!   rƒ   ©r«   rQ   r!   r"   r#   ¹   r¬   c                    r­   r©   r!   rƒ   r®   r!   r"   r#   º   r¬   c                    s,   g | ]}|d  ˆ v r|d d ˆ ˆ ‘qS ©r:   rv   rQ   r!   rƒ   ©Úh1r«   rQ   r!   r"   r#   ¼   ó   , c                    s,   g | ]}|d  ˆ vr|d d ˆ ˆ ‘qS r¯   r!   rƒ   r°   r!   r"   r#   ½   r²   gffffffæ?g×£p=
×ã?g333333Ó?gR¸…ëQØ?c                 3   s$   � | ]}|d  d ˆ  d V  qdS )rv   rQ   r   Nr!   rƒ   ©rQ   r!   r"   r—   ¿   ó   €" r@   rB   rA   ú:Ú02dz12.2fz AUC z.2fz (ú/ú)Ú Ú8ú+11.2fz / ú+.2fz+7.2fz% of z+.1frž   z  none by 12:30)r?   rq   r]   rZ   rx   r*   Úsetr3   Úprintru   r\   ÚstÚmeanÚmedianÚjoinÚMEASURESÚitemsr   r[   )Úrowsr:   r;   r%   r>   r=   rv   r~   ÚdaysÚRÚary   rz   ÚwfinalÚnameÚa0ÚfoundÚwÚlo_Úa1Úa2ÚmadeÚmwÚmlr_   r!   )r“   r±   r«   rQ   r"   Úmain”   s~   
þBFBÿ
ÿ
ÿ
ÿ
.000&
..<€$JÿÿíôrÔ   Ú__main__rC   c                     sÒ  g } t ƒ D ]\}}}}}t|||ƒ}|  ||t|ƒ|dœ¡ qtdd„ | D ƒƒ}t|dt|ƒd … ƒ‰td ddd	ftd d
dd	ftd ddd	ftd ddd	ftd	 ddd	ftd	 d
dd	ftd	 dddftd	 ddd	ftd	 ddd	ftd dddftd dddftd ddd	ftd ddd	ftd d
dd	ftd ddd	ftd ddd	ftd ddd	ftd d
dd	ftd ddd	ftd ddd	ftd ddd	ftd d
dd	fg}tddd›ddd›dd d!›dd"d#›dd$d%›dd&d'›dd(d)›�ƒ |D ]ô\‰‰‰‰‡fd*d+„| D ƒ}	t‡‡fd,d-„|	D ƒƒ}
d.d+„ |	D ƒ}d/d+„ |	D ƒ}t	 
‡‡fd0d-„|D ƒ¡t	 
‡‡fd0d-„|D ƒ¡ d ‰‡fd1d2„‰ ‡‡‡‡fd3d+„|	D ƒ‰‡fd4d+„|	D ƒ}‡ ‡fd5d+„ˆD ƒ}‡ ‡fd6d+„ˆD ƒ}d7d8ˆ d  › d9d8ˆ d d:›�}ˆ› dˆdk�r‚d;nd<› dˆd=›d>|› �}tˆd›d|d›dtˆƒd?›dt	 ‡ fd@d-„ˆD ƒ¡dA›dB|�r²t	 |¡nddC›dD|�r¾t	 |¡ndd=›dBt	 ‡ fdEd-„|D ƒ¡dF›dBt‡ fdGd-„ˆD ƒƒtˆƒ dH dI›dJ�ƒ qòdS )Kz¨[2026-09-29] Each divergence as a rule: at its minute, stocks in the group on the
    winners' side of the midpoint vs the rest -- result FROM THAT MINUTE to the close.)r:   r|   r}   rv   c                 S   r�   r‚   r!   rƒ   r!   r!   r"   r…   Ö   r†   zrule_check.<locals>.<setcomp>NrE   r   r   é2   rC   r   rA   r   é7   r   r   r   rr   r   r   r   rF   rD   r   éF   r	   r‡   r}   Ú18r‰   zrule (at minute)Ú38zn sigz>5zsig -> closer¨   Úhalvesz>14zrest -> closez>13zsig upr�   c                    r�   r‘   r!   rƒ   r’   r!   r"   r#   â   r”   zrule_check.<locals>.<listcomp>c                 3   ó$   � | ]}|d  d ˆ ˆ  V  qdS ©rv   rQ   Nr!   rƒ   r®   r!   r"   r—   ã   r´   zrule_check.<locals>.<genexpr>c                 S   s8   g | ]}|d  d |d  d t   d d dkr|‘qS )rv   rT   rM   rC   rI   rE   rª   rƒ   r!   r!   r"   r#   å   ó   8 c                 S   s8   g | ]}|d  d |d  d t   d d dkr|‘qS )rv   rT   rM   rC   rI   rs   rª   rƒ   r!   r!   r"   r#   æ   rÞ   c                 3   rÜ   rÝ   r!   rƒ   r®   r!   r"   r—   ç   r´   c                    s$   | d d | d d ˆ   d d S )Nrv   rT   rM   rC   rI   r!   r¡   r³   r!   r"   r¢   è   s   $ zrule_check.<locals>.<lambda>c                    s0   g | ]}|d  d ˆ ˆ  ˆ ˆ dkr|‘qS )rv   rQ   r   r!   rƒ   )r«   rQ   ÚsgnÚthrr!   r"   r#   é   s   0 c                    s   g | ]}|ˆ vr|‘qS r!   r!   rƒ   )Úsigr!   r"   r#   ê   s    c                    s    g | ]}|d  ˆv rˆ |ƒ‘qS r‚   r!   rƒ   ©Úfwdr±   r!   r"   r#   ë   r¬   c                    s    g | ]}|d  ˆvrˆ |ƒ‘qS r‚   r!   rƒ   râ   r!   r"   r#   ì   r¬   r@   rB   rµ   r¶   ú>ú<r¼   z at Ú5c                 3   ó   � | ]}ˆ |ƒV  qd S ©Nr!   rƒ   ©rã   r!   r"   r—   ï   r¥   r»   r™   z+6.2fr·   c                 3   rç   rè   r!   rƒ   ré   r!   r"   r—   ð   r¥   z+12.2fc                 3   s   � | ]	}ˆ |ƒd kV  qdS )r   Nr!   rƒ   ré   r!   r"   r—   ñ   r˜   rI   z5.0frž   )r?   rq   rZ   rx   r*   r½   r3   ru   r¾   r¿   rÁ   rÀ   r\   )rÅ   r:   r;   r%   r>   r=   rv   rÆ   ÚtestsrÇ   Úvalsry   rz   ÚrestÚs1Ús2r_   Úruler!   )rã   r“   r±   r«   rQ   rß   rá   rà   r"   Ú
rule_checkÏ   sJ   8F8***ú@8$*:ÿÿÿ"þòrð   Úrules)'Ú__doc__r/   r-   Ú
statisticsr¿   Úsysr   Úpathlibr   Úzoneinfor   Ú__file__ÚresolveÚparentr+   ÚpathÚinsertÚ	referencer1   Úentry_v2r   Ú
separationr   r   r]   r4   ÚlistrW   r[   ru   rÃ   r?   rq   rx   rÔ   Ú__name__r3   Úargvrð   r!   r!   r!   r"   Ú<module>   sV    ó57$%
ÿ