o
    Æ·jj  ã                   @   sÂ   d Z ddlZddlZddlmZmZmZ ddlmZ ddlm	Z	 e	dƒZ
g d¢Zedd	�Zd
d„ Zdededefdd„Zdefdd„Zdd„ Zedkr]ejdd… D ]Zedeeeƒƒ qRdS dS )a_  
shadow_outcomes.py

[2026-09-26] Labels entry_rules.py shadow snapshots with what price did
afterwards, from 1-minute bars (after the close, or over replayed days):

  returns_pct   close of the first bar ending >= t0 + h, for h in HORIZONS_S
  mfe / mae     best / worst price vs p0 over bars starting >= t0, up to 60 min
  plan_result   'target' / 'stop' / 'neither' -- which of the plan's own
                target and stop (from bot_context.plan) price reached first
                before 15:55 (a bar touching both counts as 'stop')

Usage:
  python shadow_outcomes.py logs/shadow/shadow_entry_2026-09-28.jsonl
      bars from Alpaca REST (live days)
  label_file(path, bars_for)  -- from code, with your own bars source
      (bars_for(symbol, date) -> [{"t": aware dt of bar START, "o","h","l","c","v"}])
Writes <file>.outcomes.jsonl next to the input.
é    N)ÚdatetimeÚ	timedeltaÚtimezone)ÚPath)ÚZoneInfozAmerica/New_York)é<   i,  i„  i  i  é   )Úminutesc                 C   s    | d ur|r| | d d S d S )Ng      ð?g      Y@© )ÚaÚbr
   r
   ú*/var/www/screener/trade/shadow_outcomes.pyÚ_pct   s    r   ÚsnapÚbarsÚreturnc                    sð  t  | d ¡‰|  d¡}d| d | d |  d¡| d |i d d d d dœ}|s'|S ˆ t¡jdd	d
d
d�‰ ‡ ‡fdd„|D ƒ}tD ])}ˆt|d� ‰t‡fdd„|D ƒd ƒ}|r`t	t
|d |ƒdƒnd |d t|ƒ< q?‡fdd„|D ƒ}|r–t	t
tdd„ |D ƒƒ|ƒdƒ|d< t	t
tdd„ |D ƒƒ|ƒdƒ|d< |  d¡pœi  d¡p¡i }| d¡| d¡}	}
|	rö|
rö|	|  k r»|
k rön |S d|d< |D ]1}|d |	krÑd|d< n
|d  |
krÛd|d< |d dkrõt	|d! t ˆ  ¡ d" d#ƒ|d$<  |S qÄ|S )%NÚtsÚpriceÚoutcomeÚidÚsymbolÚevent)Útyper   r   r   Út0Úp0Úreturns_pctÚmfe_pctÚmae_pctÚplan_resultÚminutes_to_resulté   é7   r   )ÚhourÚminuteÚsecondÚmicrosecondc                    s(   g | ]}|d  ˆkr|d  ˆ k r|‘qS )Útr
   ©Ú.0r   )Úeodr   r
   r   Ú
<listcomp>,   s   ( z"label_snapshot.<locals>.<listcomp>©Úsecondsc                 3   s$   � | ]}|d  t  ˆ kr|V  qdS )r&   N)ÚBARr'   )Útgtr
   r   Ú	<genexpr>/   s   €" z!label_snapshot.<locals>.<genexpr>Úcé   r   c                    s*   g | ]}|d  ˆ t ttƒd� k r|‘qS )r&   r+   )r   ÚmaxÚ
HORIZONS_Sr'   )r   r
   r   r*   1   s   * c                 s   ó   � | ]}|d  V  qdS )ÚhNr
   r'   r
   r
   r   r/   3   ó   € r   c                 s   r4   )ÚlNr
   r'   r
   r
   r   r/   4   r6   r   ÚbotÚplanÚstopÚtargetÚneitherr   r7   r5   r&   r   r   r   )r   ÚfromisoformatÚgetÚ
astimezoneÚETÚreplacer3   r   ÚnextÚroundr   Ústrr2   Úminr-   Útotal_seconds)r   r   r   ÚoutÚafterr5   r   Úwinr9   r:   r;   r
   )r)   r   r.   r   Úlabel_snapshot#   sD   
þ*""
÷
"ýrJ   c           	   	   C   sÎ   t | ƒ} dd„ t| ƒD ƒ}i }|  d¡}t|dƒ�D}|D ]8}| d¡r$qt |d ¡ t¡ ¡ }|d |f}||vrC||d |ƒ||< | 	t
jt||| ƒdd	�d
 ¡ qW d   ƒ |S 1 s`w   Y  |S )Nc                 S   s   g | ]}d |v rt  |¡‘qS )z"type":"snapshot")ÚjsonÚloads)r(   r7   r
   r
   r   r*   F   s    zlabel_file.<locals>.<listcomp>z.outcomes.jsonlÚwÚerrorr   r   )ú,ú:)Ú
separatorsÚ
)r   ÚopenÚwith_suffixr>   r   r=   r?   r@   ÚdateÚwriterK   ÚdumpsrJ   )	ÚpathÚbars_forÚsnapsÚcacheÚout_pathÚfÚsÚdÚkeyr
   r
   r   Ú
label_fileD   s$   

$ù
ÿ	÷	ra   c                 C   sp   t j dtttƒ ¡ jƒ¡ ddlm	} |ƒ }t
|j|j|jddtd�}|j| ||jdd�dd	�}d
d„ |D ƒS )Nr   )Ú
get_clienté	   é   )Útzinfoé   )r"   iè  )ÚstartÚendÚlimitc              	   S   s>   g | ]}|j t|jƒt|jƒt|jƒt|jƒt|jƒd œ‘qS ))r&   Úor5   r7   r0   Úv)Ú	timestampÚfloatrS   ÚhighÚlowÚcloseÚvolumer'   r
   r
   r   r*   [   s
    ÿ
ÿz#alpaca_bars_for.<locals>.<listcomp>)ÚsysrX   ÚinsertrD   r   Ú__file__ÚresolveÚparentÚalpaca_clientrb   r   ÚyearÚmonthÚdayr@   Úget_minute_barsrA   )r   r_   rb   r0   rg   Úrawr
   r
   r   Úalpaca_bars_forU   s   ÿr}   Ú__main__Úwrote)Ú__doc__rK   rr   r   r   r   Úpathlibr   Úzoneinfor   r@   r3   r-   r   ÚdictÚlistrJ   ra   r}   Ú__name__ÚargvÚpÚprintr
   r
   r
   r   Ú<module>   s$    
!
þ