o
    ?Œ½jI<  ã                   @   s¸  d Z ddlZddl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 ddlmZ edƒZej deeƒ¡ ddlmZ ddlZed	ƒZed
 d Zed d d Zdd„ Zdd„ Zdd„ Zdd„ Zd0dd„Zdd„ Zdd„ Z dd„ Z!edƒZ"d d!„ Z#d1d$d%„Z$e%d&krØd'ej&v r ej&ej& 'd'¡d(  d)kr d)nd"Z(d*ej&vZ)ej&d( d+krÇe(d)kr´e"ned d, Z*e+d-d.„ e* ,d/¡D ƒƒZ-nej&d( gZ-e-D ]
Z.e$e.e(e)ƒ qÏdS dS )2aä  
analyze_trades.py -- [2026-09-30] The user: "evaluate each trade today, analyze how you
could have made money on each one of them and add it to the play book".

For every trade the bot made on a day:
  - official 1-min bars 9:30-16:00, VWAP, volume vs the 14-day normal for that minute
  - the bot's trade: entry/exit, best price reached after the buy (MFE) and worst (MAE),
    what holding to the close would have made
  - the RIGHT trade (hindsight), buying and selling on 1-min closes:
      (a) while the bot was watching the stock (its scanner windows)
      (b) at any time of the day
  - measured signals at the right entry and right exit (what the bot would need to see)
  - pattern labels for the entry and the exit
Each trade becomes one CASE, appended to data/playbook/cases.jsonl (the playbook /
case library the user wants the bot to learn from), plus a chart per trade.

    python3 analyze_trades.py 2026-09-30                    the trade bot's trades that day
    python3 analyze_trades.py all --source sip --no-charts   [2026-09-30] every day of the
        sip_bot's trades (/var/www/screener/premarket, READ ONLY); it logs no watch windows,
        so its "right trade" window is the hour around its buy (right_watched) + the day
é    N)Údatetime)ÚPath)ÚZoneInfoÚAggz/var/www/screener/trade)Ú
get_clientzAmerica/New_YorkÚreportsÚplaybookÚdatazcases.jsonlc                 C   s$   t | tƒrt | ¡ t¡S |  t¡S )N)Ú
isinstanceÚstrr   ÚfromisoformatÚ
astimezoneÚET)Úts© r   ú:/var/www/screener/trade/reports/playbook/analyze_trades.pyÚet+   s   $r   c                 C   s
   |   d¡S )Nú%H:%M)Ústrftime)Údr   r   r   Úhm/   s   
r   c                 C   s´   g }t td d| › d� ƒD ]}d|v r)d|v r)| |dd… d|› d�|v f¡ qg d }}|D ]\}}|r=|d u r=|}|sL|d urL| ||f¡ d }q1|d urX| |d	f¡ |S )
NÚlogsÚ
trade_bot_z.logz[SCAN]zcandidates selectedé   é   ú'z15:15)ÚopenÚTRADEÚappend)ÚdayÚsymÚscansÚlineÚoutÚstartÚtÚonr   r   r   Úwatch_windows3   s    "€
€r'   c              	   C   s2  t  |¡jtd�}| j||jddd�|jdd�dd�}g d	d	}}}|D ]q}	|	j t¡}
|
jd d
 |
j d }d|  krCdk sEn q%|
|t	|	j
ƒt	|	jƒt	|	jƒt	|	jƒt	|	jƒdœ}||d |d  |d  d |d  7 }||d 7 }|| |d< |r�|d t|d | dƒ nd |d< | |¡ q%|S )N©Útzinfoé	   é   )ÚhourÚminuter   )r,   iè  )r$   ÚendÚlimitg        é<   r   i†  )r%   ÚmÚoÚhÚlÚcÚvr3   r4   r5   é   r6   ÚvwapÚvol_per_miné   Úvolx)r   r   Úreplacer   Úget_minute_barsÚ	timestampr   r,   r-   Úfloatr   ÚhighÚlowÚcloseÚvolumeÚmaxr   )Úclientr    r   Úrefr   ÚrawÚBÚpvr6   Úbr%   r1   Úxr   r   r   Ú	load_barsD   s"   $$ÿ(&rL   é�  c           	      C   sª   d\}}t | ƒD ]J\}}|d |kr |S |dur4|d | | d  d }|du s/||d kr4|||f}||d   kr@|krRn q|du sP|d | | d k rR|}q|S )zKBest buy-on-close / sell-on-a-later-close pair, buy minute in [lo_m, hi_m].)NNr1   Nr5   r:   é   )Ú	enumerate)	rH   Úlo_mÚhi_mÚexit_byÚbestÚrun_minÚjrJ   Úgr   r   r   Ú
best_tradeW   s   ú
8€rW   c                    sº  ˆ | }ˆ d |d … ‰t ttˆƒƒ‡fdd„d�}tttˆƒƒ‡fdd„d�}t‡ fdd„ttd|d	 ƒ|ƒD ƒƒoB|d
 |d k}ˆ td|d ƒ|d … }dd„ |D ƒ}t dd„ ˆ td|d ƒ|d … D ƒƒ‰t|d ƒ|d
 t|d
 | d d dƒt|d
 |d  d d dƒˆ| d tˆ| d ƒ|| ˆ| d |d k|ˆ| d t|d
 ˆ| d  d d dƒ|rÈtt|ƒt|ƒ dƒnd ttdd„ ˆ td|d ƒ|d … D ƒƒdƒ|t‡‡fdd„ttˆƒƒD ƒƒ dœ}	g }
|	d rþ|
 d¡ |	d dk�r|	d dk �r|
 d |	d › d!�¡ |	d" �r&|d#k�r&|
 d$¡ d%|	d   k�r4d&k�r@n n
|	d �s@|
 d'¡ |	d( d)k�rS|	d* dk�rS|
 d+¡ |
�pXd,g|	d-< |	S ).Nr:   c                    ó   ˆ |  d S )Nr4   r   ©Úk©Úpriorr   r   Ú<lambda>i   ó    zentry_signals.<locals>.<lambda>©Úkeyc                    rX   ©Nr3   r   rY   r[   r   r   r]   j   r^   c                 3   s(   � | ]}ˆ | d  ˆ | d kV  qdS )r5   r8   Nr   ©Ú.0rZ   ©rH   r   r   Ú	<genexpr>k   ó   €& z entry_signals.<locals>.<genexpr>r   é   r5   r8   é   c                 S   s    g | ]}|d  dur|d  ‘qS )r;   Nr   ©rc   rK   r   r   r   Ú
<listcomp>m   s     z!entry_signals.<locals>.<listcomp>c                 s   ó   � | ]}|d  V  qdS ©r4   Nr   ri   r   r   r   re   n   ó   € r+   r%   éd   rN   r4   g×£p=
×ï?r3   c                 s   ó   � | ]	}|d  p	dV  qdS ©r;   r   Nr   ri   r   r   r   re   y   ó   € c                 3   s(   � | ]}ˆ| d  ˆ d kr|V  qdS )r4   ç•Ö&è.>Nr   rb   )Úbase_lor\   r   r   re   z   rf   )ÚtimeÚpriceÚvs_open_pctÚvs_vwap_pctÚday_lowÚday_low_timeÚmin_since_lowÚlow_held_openÚvwap_reclaim_last5Úhigh_so_farÚbelow_high_pctÚvol15xÚmax_volx_last30Úno_new_low_minr|   zVWAP reclaimrz   é   rw   g      ø?zbase after low (z min)r{   é   zopening dip held the openg      à¿g      à?zpullback to VWAP heldr~   gš™™™™™É¿rv   zbreakout to a new highÚotherÚtags)	ÚminÚrangeÚlenrD   Úanyr   ÚroundÚsumr   )rH   ÚiÚopen_pxrJ   Úlow_jÚhi_jÚcrossedÚlast15ÚvxÚsr…   r   )rH   rs   r\   r   Úentry_signalsf   sB   6(*,"õ

*

r”   c                 C   s4  | | }|d |d  }| t d|d ƒ|d … }t dd„ | ||d … D ƒƒ}t|d	 ƒ|d
 t|d
 |d  d d dƒ|rMt|d
 |d  | dƒnd |d d ur[t|d dƒnd tt dd„ |D ƒƒdƒ|d |d k|d t| ƒk r’ttdd„ | |d |d … D ƒƒ|d
  d d dƒnd dœ}g }|d dkr©| d|d › d�¡ |d d urÂ|d dkrÂ|d pºddkrÂ| d¡ dd„ | ||d … D ƒ}	t|	ƒdkròt |	d d … ƒ}
tt |	d d … ƒ|
 d ƒd!k rò| d"¡ |d# dk�r| d$|d# › d%�¡ |d& d'k�r| d(¡ |�pd)g|d*< |S )+Nr3   r4   r   rg   é   c                 s   rk   ©r3   Nr   ri   r   r   r   re   �   rm   zexit_signals.<locals>.<genexpr>r:   r%   r5   r8   rn   rN   r;   c                 s   ro   rp   r   ri   r   r   r   re   •   rq   rr   c                 s   rk   rl   r   ri   r   r   r   re   —   rm   é   )rt   ru   rw   Úbar_close_posÚbar_volxÚmax_volx_pm5Úat_run_highÚnext30_low_pctrš   é
   zvolume climax (zx)r˜   gffffffÖ?r™   r7   zrejection bar on heavy volumec                 S   ó   g | ]}|d  ‘qS )r3   r   ri   r   r   r   rj   ž   ó    z exit_signals.<locals>.<listcomp>r‚   iöÿÿÿgú~j¼t“h?z
double toprw   z
stretched z% over VWAPr1   i|  z
end of dayztop (no clear signal)r…   )rD   r   rŠ   rˆ   r†   r   Úabs)rH   rU   Úentry_irJ   ÚrngÚnearÚrun_hir“   r…   ÚhighsÚprev_topr   r   r   Úexit_signals‹   s8    Jù	(
 

r§   c              
      sj  t jddddddgidd�\}\‰ }dd	„ |D ƒ}ˆ j|d
d	„ |D ƒdddd� ˆ j|dd	„ |D ƒdddd� ˆ j|d d dddd� |d D ]\}	}
ˆ jt ˆ› d|	› �¡t ˆ› d|
› �¡ddd� qH‡ ‡fdd„}|d }||d |d  d!dd"|d  d#›�d$ƒ ||d% |d& d'dd(|d& d#›d)|d* d+›d,�d-ƒ |d. }|rØ||d/ d0 |d/ d d1d2d3d4 |d/ d5 ¡ d6ƒ ||d7 d0 |d7 d d8d2d9d4 |d7 d5 ¡ d:ƒ ˆ j| › d;ˆ› d<|d* d=›d>|rì|d? ndd@›dA�dBdC� ˆ j	dDdE� ˆ j
dFdGdH� |j|dId	„ |D ƒdJdKd	„ |D ƒdL� |j	dDdE� |j t dM¡¡ t  ¡  t j|dNdO� t  ¡  d S )PNrN   r:   )é   gffffff@Úheight_ratiosr7   T)ÚfigsizeÚgridspec_kwÚsharexc                 S   s   g | ]
}|d  j dd�‘qS )r%   Nr(   ©r<   ri   r   r   r   rj   ­   s    zchart.<locals>.<listcomp>c                 S   rž   )r5   r   ri   r   r   r   rj   ®   rŸ   ú#1f3a5fru   )ÚcolorÚlwÚlabelc                 S   rž   )r8   r   ri   r   r   r   rj   ¯   rŸ   z#c0392bgš™™™™™ñ?ÚVWAPr   r2   Úgreyú:gš™™™™™é?)r¯   Úlsr°   ÚwatchedÚTz#eaf2fb)r¯   Úzorderc                    sb   t  ˆ› d| › �¡}ˆ j|g|g||ddddd� ˆ j|||fd|fdd	|td
d|dd�d� d S )Nr·   é‚   rg   Úblackg333333ã?)r¯   Úmarkerr“   r¸   Ú	edgecolorÚ	linewidthé   zoffset pointsg      @rŠ   Úwhite)ÚboxstyleÚfcÚecr°   )ÚxytextÚ
textcoordsÚfontsizer¯   Úbbox)r   r   ÚscatterÚannotateÚdict)ÚtmÚpÚcolÚmkÚtxtÚdyÚtt©Úaxr   r   r   Úmark´   s
   
ÿzchart.<locals>.markÚbotÚ
entry_timeÚentry_pricez#27ae60zBOT BUY ú.2fé   Ú	exit_timeÚ
exit_pricez#e74c3cz	BOT SELL z (Úplz+.0fz$)iêÿÿÿÚright_watchedÚentryrt   z#16a085Ú*z
RIGHT BUY ú, r…   iÞÿÿÿÚexitú#8e44adzRIGHT SELL é   ú u	    â€” bot ú+.2fz$ | right trade while watched Úgain_pctz+.1fz!% | blue = on the bot's watchlistg      #@)rÅ   g333333Ó?)ÚalpharS   é   )ÚlocrÅ   c                 S   rž   )r6   r   ri   r   r   r   rj   Ä   rŸ   glÁlÁF?c                 S   s$   g | ]}|d  p	ddkrdnd‘qS )r;   r   rg   rá   r®   r   ri   r   r   r   rj   Å   ó   $ )Úwidthr¯   r   én   )Údpi)ÚpltÚsubplotsÚplotÚaxhlineÚaxvspanr   r   ÚjoinÚ	set_titleÚgridÚlegendÚbarÚxaxisÚset_major_formatterÚmdÚDateFormatterÚtight_layoutÚsavefigrB   )r    r   rH   r%   ÚcaseÚpathÚfigÚaxvr   ÚaÚzrÓ   ÚbtÚrwr   rÑ   r   Úchart«   s<   $4&444ÿÿÿr  z'/var/www/screener/premarket/data/tradesc                 C   s"  |dkrg }t t| › d� ƒD ]m}zt |¡}W n	 ty!   Y qw | d¡dks5| d¡d u s5| d¡s6q| |d t|d ƒt|d ƒt|d	 ƒtt|d ƒt|d ƒ t|d	 ƒ d
ƒ|d |d | d¡pjd| dd¡d d… g| d¡dœ
¡ q|S dd„ t t	d d | › d� ƒD ƒS )NÚsipz_trades.jsonlÚstatusÚclosedrÚ   rÙ   ÚsymbolrÖ   ÚsharesrN   rÕ   Úexit_reasonÚ Úentry_reasonéÈ   Úinitial_stop)
r	  rÖ   rÚ   ÚqtyÚ
pl_dollarsrÕ   rÙ   r  ÚreasonsÚ
stop_pricec                 S   ó   g | ]}t  |¡‘qS r   ©ÚjsonÚloads©rc   r4   r   r   r   rj   á   ó    zload_trades.<locals>.<listcomp>r	   Útrades)
r   ÚSIPr  r  Ú	ExceptionÚgetr   r?   rŠ   r   )r   Úsourcer#   r4   r%   r   r   r   Úload_tradesÐ   s&   ÿ&( 
û$r  ÚtradeTc           !         s$  t ƒ }tˆ|ƒ}|sg S t‡fdd„|D ƒƒ}|rLztjt ˆ¡ ¡ |dd� ttdƒr1tj	 
¡ nd  W n tyK } ztd|ƒ W Y d }~nd }~ww g }t|dd„ d	�D �]…}|d
 }	t ˆ|	¡}
z	t||	ˆ|
ƒ‰ W n ty‡ } zt|	› d|› �ƒ W Y d }~qVd }~ww tˆ ƒdk r�qVt|d ƒt|d ƒ‰‰t‡fdd„tˆ ƒD ƒƒ}t‡fdd„tˆ ƒD ƒtˆ ƒd ƒ}ˆ |d … }tt|tˆ ƒƒ‡ fdd„d	�}tdd„ ˆ ||d … D ƒƒ}|dk�rtˆjd ˆj d dƒ}tˆjd ˆj d dƒ}|d d›d|d d›�|d d›d|d d›�fg}ntˆ|	ƒ}dd„ }d }d }|D ]%\}}tˆ ||ƒt||ƒdƒƒ}|�rM|d u �sK|d |d k�rM|}�q)|�rqtˆ |d ˆ d d ƒtˆ |d |d ƒt|d d  dƒd!œ}tˆ ddƒ}|�r™tˆ |d ˆ d d ƒtˆ |d |d ƒt|d d  dƒd!œnd }|dk�r¢d"nd#ˆ|	|ˆ d d td$d„ ˆ D ƒƒtd%d„ ˆ D ƒƒˆ d& d' tˆ d& d' ˆ d d  d d  dƒd(œtˆƒ|d) tˆƒ|d* |d+ |d, |d- d d.… | d/¡tˆ |ˆ d d ƒˆ | d0 tˆ | d1 ƒtˆ | d0 |d)  d d  dƒt||d)  d d  dƒtˆ d& d' |d)  |d,  dƒd2œ||d3œ}| |¡ |�r[t |	ˆˆ ||t!ˆ› d4|	› d4tˆƒ "dd5¡› d6� ƒ t|	› d7|d+ d8›d9|d: d; d8›d<|d: d= › d>|d: d? d8›d@�
|�rº|dA dB › dC|dA dD dE›dF|dG dB › dC|dG dD dE›dC|dH d8›dIdJ #|dA dK ¡› dLdJ #|dG dK ¡› dM�ndN |�rÖdO|dA dB › dP|dG dB › dC|dH d8›dQ�nd5 dRdS� qVt$j%j&dRdRdT� |dk�rìd"nd#‰t$ '¡ �rüdUdV„ t(t$ƒD ƒng }‡‡fdWdV„|D ƒ}|D ]}�q
‡‡fdXdY„|D ƒ}|D ]"}| |dZ |d
 |d: d f¡}|�r;d[D ]	}|| ||< �q1�qt(t$d\ƒ�} || D ]}|  )t*j+|t,d]�d^ ¡ �qGW d   ƒ n	1 �sbw   Y  |dk�r}t*j-|t(t!ˆ› d_� d\ƒdt,d`� tˆ› dCˆ› dat|ƒ› dbt$› �dRdS� |S )cNc                    s$   h | ]}t  ˆ |d  ¡s|d  ’qS )r	  )Ú	referenceÚload)rc   r%   )r   r   r   Ú	<setcomp>é   ré   zmain.<locals>.<setcomp>F)ÚverboseÚ_CACHEz   reference build failedc                 S   s   | d S )NrÕ   r   )rK   r   r   r   r]   ñ   s    zmain.<locals>.<lambda>r_   r	  z: bars failed r+   rÕ   rÙ   c                 3   ó.   � | ]\}}|d  ˆ j ddd�kr|V  qdS ©r%   r   )ÚsecondÚmicrosecondNr­   ©rc   rZ   rK   )Úeinr   r   re   ü   ó   €, zmain.<locals>.<genexpr>c                 3   r&  r'  r­   r*  )Úeoutr   r   re   ý   r,  r:   c                    rX   ra   r   rY   rd   r   r   r]   ÿ   r^   c                 s   rk   rl   r   ri   r   r   r   re      rm   r  r0   i:  i“  Ú02dr´   c                 S   s,   t | d d… ƒd d t | dd … ƒ d S )NrN   r*   r0   r7   r+   )Úint)r“   r   r   r   r]     ó   , iY  rN   r   r2   rn   )rÝ   rà   rå   Úsip_botÚ	trade_botc                 s   rk   r–   r   ri   r   r   r   re     rm   c                 s   rk   rl   r   ri   r   r   r   re     rm   éÿÿÿÿr5   )r   r@   rA   rB   Úopen_to_close_pctrÖ   rÚ   r  r  r  éZ   r  r3   r%   )rÕ   rÖ   rÙ   rÚ   rÛ   r  r  Úentry_reasonsr”   Ú	mfe_priceÚmfe_timeÚmfe_pctÚmae_pctÚhold_to_close_pl)r  Údater	  r¶   r   rÔ   rÜ   Ú	right_dayÚ_r  z.pngz: bot rä   z  MFE rÔ   r9  z% at r8  z  hold r;  z  | right (watched) rÝ   rt   rã   ru   r×   z -> rà   rå   z% [rß   r…   z | ú]ú-z  | right (day) z->ú%T)Úflush)ÚparentsÚexist_okc                 S   r  r   r  r  r   r   r   rj   -  r  zmain.<locals>.<listcomp>c                    s,   g | ]}|d  ˆ kr|  dd¡ˆks|‘qS )r<  r  r2  ©r  ©rc   r5   ©r   Úsrcr   r   rj   .  r0  c                    sN   i | ]#}|d  ˆ kr|  dd¡ˆkr|  d¡r|d  |d |d d f|“qS )r<  r  r2  Ú
suggestionr	  rÔ   rÕ   rE  rF  rG  r   r   Ú
<dictcomp>1  s    &ÿzmain.<locals>.<dictcomp>r<  )Úwhat_happenedrI  Úrule_candidatesÚw)ÚdefaultÚ
z_cases.json)ÚindentrN  z: z
 cases -> ).r   r  Úsortedr!  Úbuildr   r   r<  Úhasattrr%  Úclearr  Úprintr"  rL   rˆ   r   ÚnextrO   rD   r‡   r†   r,   r-   r'   rW   r”   r§   rŠ   r   r  r   r  ÚOUTr<   rò   ÚCASESÚparentÚmkdirÚexistsr   Úwriter  Údumpsr   Údump)!r   r  ÚchartsrE   r  ÚneedÚeÚcasesr%   r    rF   ÚeiÚxoÚafterÚmfe_jÚmaer  r  ÚwinÚminsr  Úbest_wr  ÚbdÚrdrý   ÚoldÚkeepr5   Úlessonsr2   rZ   Úfr   )rH   r   r+  r-  rH  r   Úmainä   sæ   
€€ÿ€þ$
8
"€(ÿ,ÿÿÿ*.ÿ  ùó
42ÿ@ÿÿÿÿý6üü  €ÿÿ
"&rq  Ú__main__z--sourcer:   r  z--no-chartsÚallr  c                 c   s   � | ]
}|j d d… V  qd S )Nr�   )Úname)rc   rË   r   r   r   re   F  s   € re   z*_trades.jsonl)rM   )r   T)/Ú__doc__r  Úsysr   Úpathlibr   Úzoneinfor   Ú
matplotlibÚuseÚmatplotlib.datesÚdatesrù   Úmatplotlib.pyplotÚpyplotrí   r   rþ   Úinsertr   Úalpaca_clientr   r!  r   rW  rX  r   r   r'   rL   rW   r”   r§   r  r  r  rq  Ú__name__ÚargvÚindexrH  r_  ÚfolderrQ  ÚglobÚdaysr   r   r   r   r   Ú<module>   sN    

% "
],
÷