
    ށj)                    D   d Z ddlmZ ddlZddlZddlZddlmZmZ ddl	m
Z
 ddlZddlZ e
e      j!                         j"                  j"                  Zej&                  j)                  d ee             ddlmZ  ej0                  d      Z ej0                  d      Z ej0                  d	      Zd
gej;                  e      Z ed       G d d             ZddZ ddd dZ!d!dZ"d"dZ#d#dZ$d$dZ%d%dZ&d&dZ'dddddd'dZ(d(dZ)e*dk(  r e+ e)             y))a  Causal, non-promoting study of MLP feature states before extreme BTC bars.

The event at bar t is the close-to-close return from t-1 to t.  Every
candidate predictor is taken from t-1, so it was available before the event
bar began.  Tail thresholds and feature cuts are calibrated only in the
discovery window, then held fixed in validation and OOS windows.

This is an event-profile diagnostic, not a training command and not a source
of promoted MLP parameters.
    )annotationsN)asdict	dataclass)Path)FEATURE_COLSz2023-12-31 23:59:59z
2024-01-01z
2026-03-01	mlp_scoreT)frozenc                  ,    e Zd ZU ded<   ded<   ded<   y)TailDefinitionfloat	up_returndown_returntail_fractionN)__name__
__module____qualname____annotations__     (tools/run_mlp_extreme_bar_event_study.pyr   r   !   s    r   r   c                0   t        j                  | d      }|j                         j                         r1t        j                  |dd      j
                  j                  d      S t        j                  | dd      j
                  j                  d      S )	zLParse TradingView epoch-second exports and ISO timestamps deterministically.coerce)errorssT)unitutcNraise)r   r   )pd
to_numericnotnaallto_datetimedttz_localize)valuesnumerics     r   parse_chart_timer'   (   sl    mmF84G}}~~gCT:==II$OO>>&d7;>>JJ4PPr         @	bar_hoursc                  |dk  rt        d      ddg|D cg c]  }|| j                  vs| }}|rt        d|       | ddg|   j                         }t        |d         |d<   |j	                  d      j                  d      }|d   j                         j                         s|d   j                  st        d      |d   j                  d	      }t        j                  |d
z        }||d   z
  |k  }t        j                  |d   j                  d	      |d   z        j                  |      |d<   |j                  |      |d<   |S c c}w )zCReturn feature snapshots at t and their contiguous next-bar return.r   zbar_hours must be positivetimeclosezmissing required columns: T)dropz+time must be unique and strictly increasing      ?)hoursforward_returnoutcome_time)
ValueErrorcolumnscopyr'   sort_valuesreset_index
duplicatedanyis_monotonic_increasingshiftr   	Timedeltanplogwhere)	datafeaturesr*   columnmissingframe	next_timemax_gap
contiguouss	            r   causal_event_framerI   0   sf   A~566%+W$@x$@_$@&FRVR^R^D^v$@G_5gY?@@&'-H-.335E$U6]3E&Mf%11t1<EV}!%%'uV}/T/TFGGf##B'IllS1GeFm+7J ffU7^%9%9"%=g%NOUUV`aE
%OOJ7E.L `s
   EEc                    d|cxk  rdk  st        d       t        d      | d   j                         }t        |      dk  rt        d      t        t	        |j                  d|z
              t	        |j                  |            |      S )	z<Set fixed extreme-move labels using discovery outcomes only.r   g      ?z'tail_fraction must be between 0 and 0.5r2      z4discovery window needs at least 20 complete outcomes      ?)r   r   r   )r4   dropnalenr   r   quantile)	discoveryr   returnss      r   calibrate_tailsrR   D   s    }"s"BCC #BCC()002G
7|bOPP((})<=>'**=9:# r   c                    t        j                  d| j                        }||| d   |k\  z  }||| d   |k  z  }|| d   |k  z  }| j                  || d   j	                         z     j                         S )NT)indexr,   r3   r2   )r   SeriesrT   locr    r6   )rE   startendmasks       r   _windowrZ   R   s    99T-Df&&
f$$n%,,99TE"2399;;<AACCr   c                   |dk(  r| d   |j                   k\  n| d   |j                  k  }|dk(  r| |   |k\  n| |   |k  }| |   j                         }||z  }|j                         rt	        ||   j                               nd }	|j                         rt	        ||   j                               nd }
t        |j                               t        |j                               |
|	|
|	r|	dkD  r|
|	z  dS d dS )Nupr2   highr   )observationsselected
event_rate	base_ratelift)r   r   r    r:   r   meanintsum)rE   featurecutsideeventtails
event_maskr_   usablera   r`   s              r   _profile_windowrm   \   s   ?D}'(EOO;RWXhRimrm~m~R~J(,uW~$E'Nc<QH7^!!#FH4:JJLj(--/0dI7?||~z(+00234JFJJL)' *4*@YS\_`S`
Y& 
 gk r   c                  |dvrt        d      | |   j                         }t        |      dk  rt        | d      t        |j	                  |            t        |j	                  d|z
              }	}t        | ||d||      }
t        | ||	d||      }|
d   xs t        d	      |d   xs t        d	      }}||k\  rd|	|fnd||
f\  }}}|||||t        ||||||      t        ||||||      d
S )zEChoose one discovery-tail direction, then hold that rule fixed later.>   r\   downzevent must be 'up' or 'down'rK   z# has too few discovery observationsrL   lowr]   rb   -inf)rf   ri   rh   rg   rP   
validationoos)r4   rM   rN   r   rO   rm   )rP   rr   rs   rf   ri   rj   feature_tailr%   low_cuthigh_cutrp   r]   low_lift	high_liftrh   rg   discovery_profiles                    r   profile_featurerz   l   s#   N"788w&&(F
6{RG9$GHIIfool;<eFOOTWZfTfDg>hXG
)WgueU
KC9gxNDf+6vV8UfiH?HH?TFHd#;[`biknZo D# &%j'3eUSsGS$uE r   c                    | d   }t        |t              sJ t        |d   xs t        d            t        | d         fS )NrP   rb   rq   rf   )
isinstancedictr   str)profilerP   s     r   	_rank_keyr      sD    $Ii&&&)F#4uV}5s79;M7NOOr   c                  t        | |      }| ||d}i }dD ]  }	g }
|D ]  }t        | ||||	||      }|j                         D ci c]8  \  }}|t        ||t	        |d         t        |d         |	t        ||            : }}}|
j                  ||	|d   |d   |d        t        |
d d	      ||	<    |S c c}}w )
a6  Describe within-window tail behavior without reselecting feature rules.

    The event thresholds are recalculated within each reporting window, so this
    is descriptive of *relative* extremes rather than an executable fixed-size
    return rule.  Feature direction and cut remain selected in discovery.
    rP   rr   rs   r\   ro   rf   ri   rj   rt   rg   rh   )rf   ri   rh   rg   windowsc                D    t        | d   d   d   xs t        d            S )Nr   rP   rb   rq   )r   )r   s    r   <lambda>z(relative_tail_profiles.<locals>.<lambda>   s$    gi&8&Ef&M&^QVW]Q^ _r   Tkeyreverse)rR   rz   itemsrm   r   r~   appendsorted)rP   rr   rs   rB   rt   r   discovery_tailsr   resultri   profilesrf   r_   namewindowrelatives                   r   relative_tail_profilesr      s
    &i?O%ZLG13FG&:sG5%LH %,MMO %4LD& ofguXe_7MsS[\bScOdfk&5fm&LN N$3  
 OO" (#   " _
u'  0 M#s   =B;
皙?皙?r   rt   r*   rB   c                  t        j                  |       }|j                  j                  j	                         j                  j                         |_        t        t        j                  |xs# t        D cg c]  }||j                  v s| c}            }|st        d      t        |||      }t        |d t              }	t        |t        t        t        j                   d      z
        }
t        |t        d       }t#        |	|      }i }dD ]6  }|D cg c]  }t%        |	|
|||||       }}t'        |t(        d      ||<   8 t        |       d	|d
z  t+        |      |t        t              t        t              t        t        t        j                   d      z
        gt        t              dt-        |	      t-        |
      t-        |      d|t/        |	|
||||      dS c c}w c c}w )Nz(no requested feature columns are presentr)      )nanosecondsr   r   Tr   zFnext 6h close-to-close return; feature snapshot is the preceding closer0   )ri   max_label_gap_hourstail_definitionrt   discovery_endrr   	oos_startr   )rB   rt   r   )	data_path
definitionr   studiesrelative_tail_studies)r   read_csvr5   r~   lowerstriplistr}   fromkeysDEFAULT_FEATURESr4   rI   rZ   DISCOVERY_ENDVALIDATION_START	OOS_STARTr=   rR   rz   r   r   r   rN   r   )r   r   rt   r*   rB   rA   rf   selected_featuresrE   rP   rr   rs   rj   r   ri   r   s                   r   runr      s   ;;y!D<<##))+//557DLT]]8+{O_7{O_GcjnrnznzczO_7{|}CDDt%6)LEt]3I 0)bllWX>Y2YZJ
%D
)CI}5E24G#46#4 $Iz3W\di  yE  F#4 	 6iF  
 ^]#,s?%e}( //0#i",,[\B]6]2^_Y
 "%Ys:WZ[^W_`!7z31B%]"
  8|6s   7G,G,G1c                    t        j                  t              } | j                  dt        dd       | j                  dt
        d       | j                  d	t
        d
       | j                  dt
        dd       | j                  ddd       | j                  dt        d       | j                         }t        |j                  |j                  |j                  |j                  |j                        }t        j                  |d      }t        |       |j                   rE|j                   j"                  j%                  dd       |j                   j'                  |dz          y)N)descriptionz--dataTz4TradingView chart-data CSV to read without modifying)typerequiredhelpz--tail-fractionr   )r   defaultz--feature-tailr   z--bar-hoursr(   zBExpected chart-bar duration; labels crossing >1.5 bars are dropped)r   r   r   z
--features*z@Feature columns to profile; defaults to mlp_score when available)nargsr   z--outputzOptional JSON output path)r   r   r      )indent)parentsexist_ok
r   )argparseArgumentParser__doc__add_argumentr   r   
parse_argsr   rA   r   rt   r*   rB   jsondumpsprintoutputparentmkdir
write_text)parserargsr   texts       r   mainr      sB   $$9F
tdAwx
)tD
(udC
E3  FJ  K
C6xy

4OPD$*<*<4K\K\hlhvhv  BF  BO  BO  PF::fQ'D	$K{{   =td{+r   __main__)r%   	pd.Seriesreturnr   )rA   pd.DataFramerB   	list[str]r*   r   r   r   )rP   r   r   r   r   r   )rE   r   rW   pd.Timestamp | NonerX   r   r   r   )rE   r   rf   r~   rg   r   rh   r~   ri   r~   rj   r   r   zdict[str, float | int | None])rP   r   rr   r   rs   r   rf   r~   ri   r~   rj   r   rt   r   r   dict[str, object])r   r   r   ztuple[float, str])rP   r   rr   r   rs   r   rB   r   rt   r   r   r   r   z"dict[str, list[dict[str, object]]])r   r   r   r   rt   r   r*   r   rB   zlist[str] | Noner   r   )r   rd   ),r   
__future__r   r   r   sysdataclassesr   r   pathlibr   numpyr>   pandasr   __file__resolver   REPOpathinsertr~   strategies.strategy_mlp_scoresr   	Timestampr   r   r   r}   r   r   r   r'   rI   rR   rZ   rm   rz   r   r   r   r   r   
SystemExitr   r   r   <module>r      s/  	 #   
 )   H~&&-- 3t9  7 232<<- BLL&	>$--"=>  $  Q WZ (D .P"J 48thk  KO !H$ z
TV
 r   