+
    3M=j                        R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RI	H
t
 ^ RIt^ RIt]P                  P!                  ^ ]! ]! ]4      P'                  4       P(                  P(                  4      4       ^ RIHtHtHt ]P                  P3                  ]! ]! ]4      P'                  4       P(                  P(                  4      4       Rt]3R R lltR]P8                  ! ^R	7      R
]P8                  ! ^R	7      R]P8                  ! ^R	7      R]P8                  ! ^R	7      R]P8                  ! ^R7      /tRRRR
RRRR/tR R ltR R lt R R lt!R R lt"R R lt#R;R R llt$R R  lt%R! R" lt&R# R$ lt'R% R& lt(R<R' R( llt)R) R* lt*R=R+ R, llt+R- R. lt,R<R/ R0 llt-R>R1 R2 llt.R3 R4 lt/R?R5 R6 llt0R7 R8 lt1R9 t2]3R:8X  d
   ]2! 4        R# R# )@u  
Compare TradingView Trade List vs Python Backtest Signals
=========================================================

Robust TV/Python parity diagnostic tool. Loads a TradingView trade-list
export, runs the Python strategy with the same params, matches trades using
timeframe-aware timestamps (TV fills at open[T+1]; Python signals fire at
bar-close T), then classifies each divergence by root cause.

Usage
-----
    # Basic comparison — auto-detects TF from data filename
    python tools/compare_tv_trades.py \
        --tv-trades data/ActivationScores_COINBASE_BTCUSD_2026-03-26.csv \
        --data data/COINBASE_BTCUSD-4H.csv \
        --params results/winners/optimization_winner_activation_scores_COINBASE_BTCUSD_4H.csv

    # MLP strategy comparison
    python tools/compare_tv_trades.py \
        --strategy-file strategy_mlp_scores.py \
        --tv-trades data/MLPScores_COINBASE_BTCUSD_2026-06-17.csv \
        --data data/COINBASE_BTCUSD-6H.csv \
        --params results/winners/optimization_winner_strategy_mlp_scores_COINBASE_BTCUSD_6H.csv

    # Verbose: show score context for every divergent trade
    python tools/compare_tv_trades.py ... --verbose

    # Show exit-detail tables for entry-matched but exit-mismatched trades
    python tools/compare_tv_trades.py ... --exit-detail

    # Override timeframe (if not inferrable from filename)
    python tools/compare_tv_trades.py ... --timeframe 4H

Timestamp offset note
---------------------
Pine fills at open[T+1], so TV records entry at time[T+1] while Python
records the signal at time[T].  For a 4H chart this is a 4-hour forward
offset.  The tool compensates automatically: when matching trades it
computes  TV_entry_time - TF_offset ≈ Python_signal_time.
Tolerance is ±2 bars by default (adjustable with --tolerance-bars).

Root-cause classification
-------------------------
  SCORE_DIFF    : Python score vs TV exported score differ near crossunder
  CASCADE       : Python state diverged from TV after a prior exit mismatch
  TRAILING_STOP : Same entry, exit diverges (trailing stop fired differently)
  EXIT_CONF     : Exit confirmation threshold caused a 1-bar timing difference
  UNKNOWN       : Cannot determine without TV score export on those specific bars
N)Path)Optional)SCORE_START	TRAIN_ENDTRAIN_STARTg{Gzt?c                H    V ^8  d   QhR\         R\         R\         R\         /# )   entry_pxexit_pxcommission_ratereturn)float)formats   "B/Users/jameslopez/projects/TradingBot25/tools/compare_tv_trades.py__annotate__r   L   s*     4 4% 4% 4!&4=B4    c                n    V ^V,           ,          pV^V,
          ,          pWC,
          V,          ^d,          # )u   Per-trade P&L % net of commission — identical model to
strategies/validate_strategy.py: pay commission_rate on the entry notional
and on the exit notional (0.5%/side default). )r	   r
   r   	eff_entryeff_exits   &&&  r   net_pnl_pctr   L   s5    
 A/0I1./H I-33r   4Hhours6H8H12H1D)days240360480720c                F    V ^8  d   QhR\         R\        \         ,          /# )r   	data_pathr   )strr   )r   s   "r   r   r   d   s        r   c                ~   \        V 4      P                  P                  4       p\         F;  pVP	                  RV 24      '       g   VP	                  RV 24      '       g   K9  Vu # 	  \
        P                  4        F#  w  r2VP	                  RV 24      '       g   K!  Vu # 	  VP	                  R4      '       d   R# R# )zInfer timeframe from the data CSV filename.

Handles both dash/underscore-suffix forms (COINBASE_BTCUSD-4H.csv) and
the TV minute-based export form (COINBASE_BTCUSD, 360.csv).
-_, z, 1Dr   N)r   stemupperTF_DURATIONSendswith_MINUTES_TO_TFitems)r$   nametfminss   &   r   detect_timeframer3   d   s     	?%%'D==1RD""dmmatH&=&=I  #((*==2dV%%I + }}Vr   c                D    V ^8  d   QhR\         R\        P                  /# )r   tf_strr   )r%   pd	Timedelta)r   s   "r   r   r   x   s     ; ;c ;bll ;r   c                 X    \         P                  V \        P                  ! ^R7      4      # )   r   )r,   getr6   r7   )r5   s   &r   	tf_offsetr;   x   s    FBLLq$9::r   c                F    V ^8  d   QhR\         R\        \        ,          /# )r   pathr   )r%   listdict)r   s   "r   r   r   ~   s"     B B Bd Br   c                  a a \         P                  ! S RR7      oSP                  P                  P	                  4       Sn        R VV 3R llpV! RRR4      pV! R4      pV! R	R
R4      pV! RR4      pV! RRR4      p\        V3R lR 4       R4      p/ pSP                  4        F  w  r \        W,          4      p\        T
P                  TR4      4      P	                  4       P                  4       pY9  d   / Y&   RT9   d   YT,          R&   Kl  RT9   g   Ku  YT,          R&   K  	  . p\        V4       EF  pW,          pRV9  g   RV9  d   K  VR,          pVR,          p \         P                  ! \        W,          4      4      p\         P                  ! \        VV,          4      4      p\        W,          4      p\        VV,          4      p\        VV,          4      pV'       d*   \        VP                  VR4      4      P	                  4       MRpTP!                  RTRTRTRTRTRTRTRRTP                  4       9   /4       EK  	  V#   \        \        3 d     EK  i ; i  \         d     EKC  i ; i) a  
Parse a TradingView exported trade-list CSV.

TV exports rows in order: Exit first, then Entry for each trade.
Returns a list of dicts with keys:
    trade_num, entry_dt, exit_dt, entry_price, exit_price,
    net_pnl_pct, exit_signal, is_margin_call
sorted by entry_dt.
	utf-8-sigencodingc                0    V ^8  d   QhR\         R\         /# )r   namesr   r%   )r   s   "r   r   $load_tv_trades.<locals>.__annotate__   s     [ [C [C [r   c                     < V  F  pVSP                   9   g   K  Vu # 	  \        R S RRP                  V 4       24      h)z%None of these columns are present in : r)   )columnsKeyErrorjoin)rE   r0   dfr=   s   * r   colload_tv_trades.<locals>.col   sD    Drzz!  >tfBtyyQVGWFXYZZr   zTrade #zTrade numberzTrade NumberTypezDate and timez	Date/TimeDatez	Price USDPricez	Net P&L %z	Net PnL %zNet profit %c              3   L   <"   T F  qSP                   9   g   K  Vx  K  	  R # 5iNrJ   ).0r0   rM   s   & r   	<genexpr>!load_tv_trades.<locals>.<genexpr>   s     R(;rzz?Qtt(;s   $
$N entryexit	trade_numentry_dtexit_dtentry_price
exit_pricer   exit_signal	is_marginmargin)SignalOrder)r6   read_csvrJ   r%   stripnextiterrowsint
ValueErrorrK   r:   lowersorted	Timestampr   	Exceptionappend)r=   rN   	trade_coltype_coltime_col	price_colpnl_col
signal_colrawr(   rownumt_typetradeste_rowx_rowr]   r^   r	   r
   pnl_pctsignalrM   s   f                      @r   load_tv_tradesr   ~   sJ    
TK	0B%%'BJ[ [ I~~>I6{H?K8HK)I+{N;GR(;RTXYJC++-	cn%C SWWXr*+11399;>CHf #HWv"HV   Fc{H!vQ'
&		S%9:HSx%9:Ge./HeI./GeGn-GBLEIIj"56<<>RTF 	CHGHGGFH6	
 		 2 MI H% 		0  		s%   +I%B3I*I'&I'*I:9I:c                0    V ^8  d   QhR\         R\         /# )r   strategy_filer   rF   )r   s   "r   r   r      s     * * * *r   c                N    \        V 4      P                  pVP                  R4      # )zReturn winner-file stem for a strategy filename.

Examples:
  strategy_activation_scores.py -> activation_scores
  strategy_mlp_scores.py        -> mlp_scores
	strategy_)r   r*   removeprefix)r   r*   s   & r   strategy_stemr      s%     ##D[))r   c                0    V ^8  d   QhR\         R\        /# )r   params_pathr   )r%   r?   )r   s   "r   r   r      s      S T r   c                    V '       d&   \         P                  P                  V 4      '       g   / # V P                  R 4      '       df   \        P
                  ! V 4      P                  ^ ,          P                  4       p0 RmpVP                  4        UUu/ uF  w  r4W29  g   K  W4bK  	  upp# V P                  R4      '       d   \        V 4      ;_uu_ 4       p\        P                  ! V4      pRRR4       / pXP                  4        FV  w  r4\        V\        4      '       d8   RV9   d   VP                  RR.4      ^ ,          MVP                  R^ 4      Ws&   KR  WGV&   KX  	  V# / # u uppi   + '       g   i     L; i).csvz.jsonNvaluesstart>   verified	CPU_Score	Composite	GPU_Score_pnl_dd_percentile% In MarketTotal P&L %Calmar RatioP&L/DD RatioSharpe RatioTotal TradesSortino RatioMax Drawdown %)osr=   existsr-   r6   rf   ilocto_dictr/   openjsonload
isinstancer?   r:   )r   rx   dropkvfrw   flats   &       r   load_paramsr      s!   bggnn[99	F##kk+&++A.668Y "%>>>G$$+!))A,C  IIKDA!T""8@A!%%4&1!4155QXZ[K\Q	  
 I ?s   
E%"E%E++E;	c                \    V ^8  d   QhR\         R\        R\         R\        P                  /# )r   r$   paramsr   r   )r%   r?   r6   	DataFrame)r   s   "r   r   r      s.      3  '*JL,,r   c                b   \        V4      pVP                  4       '       g@   \        \        4      P                  4       P                  P                  R,          V,          pVP                  4       '       g   \        RV 24      h\        P                  P                  RV4      p\        P                  P                  V4      pV\        P                  R&   VP                  P                  V4       \        P                   ! V 4      pVP"                  P$                  P'                  4       P$                  P)                  4       Vn        \        P*                  ! VR,          RR7      P,                  P/                  R4      VR&   VP0                  ! V3/ VB p\3        V4      VP4                  R&   V# )	z>Load data CSV, run generate_signals, return signals DataFrame.
strategieszStrategy file not found: strategy_moduletimeT)utcNr   )r   is_absolute__file__resolveparentr   FileNotFoundError	importlibutilspec_from_file_locationmodule_from_specsysmodulesloaderexec_moduler6   rf   rJ   r%   rl   rg   to_datetimedttz_localizegenerate_signalsr   attrs)r$   r   r   strategy_pathspecmodrM   signalss   &&&     r   run_python_strategyr      sA    'M$$&&X..077>>MP]]!!";M? KLL>>112C]SD
..
)
)$
/C%(CKK!"KKC 	Y	B%%'++113BJ6
588DDTJBvJ ""200G%2=%AGMM/"Nr   c                Z    V ^8  d   QhR\         P                  R\        \        ,          /# r   r   r   )r6   r   r   r%   )r   s   "r   r   r     s"      R\\ hsm r   c                    V P                   P                  R4      pVR8X  d   RpMVR8X  d   RpMRpV F  pW0P                  9   g   K  Vu # 	  R# )zCReturn the TV-exported score column present in a signal/data frame.r   
mlp_scoresactivation_scoresN)	mlp_scoremlp_score_poc)activation_score_pocactivation_scores_poc)r   r   r   r   )r   r:   rJ   )r   strategy
candidatesrN   s   &   r   tv_score_columnr     sV    }}  1H<3
	(	(F
4
//!J  r   c                d    V ^8  d   QhR\         P                  R\         P                  R\        /# )r   rx   r   r   )r6   Seriesr   r   )r   s   "r   r   r     s)     & &		 &BLL &U &r   c                 l    \        V4      pVf   \        R4      # V P                  V\        R4      4      # )Nnan)r   r   r:   )rx   r   rN   s   && r   tv_score_valuer     s0    
'
"C
{U|773e%%r   c                $    V ^8  d   QhR\         /# )r   r   )bool)r   s   "r   r   r     s      $ r   c                     \        V \        4      '       d"   V P                  4       P                  4       R9   # \	        V 4      # )1>   r   yonyestrue)r   r%   rg   rl   r   )values   &r   _param_boolr     s4    %{{}""$(GGG;r   c                   V ^8  d   QhR\         P                  R\         P                  R\         P                  R\         P                  R\        R\        \         P                  \         P                  \         P                  3,          /# )r   entriesexits	close_arrhigh_arrtrail_stop_pctr   )npndarrayr   tuple)r   s   "r   r   r      sl     &) &)ZZ&)::&) zz&) jj	&)
 &) 2::rzz2::-.&)r   c                >   \        V 4      p\        P                  ! V\        P                  R7      p\        P                  ! V\        R7      p\        P                  ! V\        R7      pRp	Rp
Rp\        V4       F  pV	'       d_   RpVR8  d5   W8w  d   W<,          V
8  d	   W<,          p
W,,          V
RV,
          ,          8*  pW,          '       g	   V'       d   Rp	RW&   Rp
RpM%W,          '       d   Rp	RW|&   W,,          p
V^,           pV	'       d   ^M^ Wl&   K  	  WgV3# )z6Replay Pine's flat/long lifecycle from raw conditions.dtypeF              ?T)lenr   zerosint32r   range)r   r   r   r   r   nin_pos
exec_entry	exec_exitposition
trade_highfill_bari	trail_hits   &&&&&         r   _replay_positionsr      s     	GAXXarxx(F!4(J$'IHJH1XI#=X[:%=!)J%LJ#:N,OO	xx9 #	 
zz $
&\
q5!Aq	' * y((r   c          
          V ^8  d   QhR\         P                  R\        R\         P                  R\        \         P                  ,          R\         P                  /# )r   r   r   r   endr   )r6   r   r?   rn   r   )r   s   "r   r   r   I  sV     d d\\dd <<d 
",,		d
 \\dr   c           
     F
   0 R%mpVP                  V P                  4      '       g   V # V P                  4       pV P                  P	                  R4      R8X  Ed   ^ RIHp \        V4      pW'R&   W7R	&   \        P                  ! VP	                  R
\        P                  ! RVP                  R7      4      RR7      P                  R4      P                  \        P                  R7      pV! VVVVR,          P                  \        P                  R7      VR,          P                  \        P                  R7      4      p	V	P                  P!                  V P                  4       V	# VR,          p
\#        VP	                  RR4      4      p\#        VP	                  RR4      4      p\#        VP	                  RR4      4      p\%        VP	                  RR4      4      p\%        VP	                  RR4      4      pV'       d8   V
P'                  ^4      V8  V
P'                  ^4      V8  ,          W8  ,          pM\        P                  ! RVP                  R7      pR
VP                  9   d   VR
,          P                  R4      R8g  pV
P'                  ^4      V8  V
P'                  ^4      V8  ,          V,          pV'       d`   V
P'                  ^4      V8  V
P'                  ^4      V8  ,          WP'                  ^4      8  ,          VP'                  ^RR7      ( ,          pMV
P'                  ^4      V8  W8  ,          p\)        VP	                  R^ 4      4      p\#        VP	                  RR&4      4      pV^ 8  d&   V
P+                  V^R7      P-                  4       V8  pM"\        P                  ! RVP                  R7      p\%        VP	                  RR4      4      '       d%   RVP                  9   d   VVR,          ^ 8  ,          p\        P.                  ! VR,          4      pVV8  pVe   VVV8*  ,          pVV,          V,          P                  R4      P                  \0        R7      pVV,          P                  R4      P                  \0        R7      p\#        VP	                  R R4      4      R!,          p\3        VVVR,          P                  \        P                  R7      VR,          P                  \        P                  R7      V4      w  pppVVR"&   VVR#&   VVR$&   V# )'aU  Rebuild executed trades with Pine's startDate/endDate gate.

Strategy signal generation intentionally runs on full history so scores and
crossunders have the same warm-up context as Pine. Pine still gates
strategy.entry()/strategy.close() with `timeCondition`, so pre-start raw
entries must not carry position state into the scoring window.
r   activation_scoreclosehighr   r   )_score_to_signals_pine_time_start_pine_time_endstoch_peak_normr   indexcoerceerrorsr   !i_long_entry_activation_threshold     Z@ i_long_exit_activation_threshold     a@-i_long_exit_activation_confirmation_thresholdg4@@i_use_long_exit_confirmationTi_use_long_entry_confirmationF)
fill_valuei_regime_windowi_regime_entry_min_score)windowmin_periodsi_mvrv_suppress_bearmvrv_regimei_trailing_stop_thresholdg      Y@r   execute_entryexecute_exit>   r  r   r  r  g     @)issubsetrJ   copyr   r:   strategies.strategy_mlp_scoresr  r?   r6   
to_numericr   r  fillnato_numpyr   float64updater   r   shiftrj   rollingmeanr   r   r   )r   r   r   r  requiredrM   r  replay_params
stoch_peakreplayedscoreentry_thresholdexit_thresholdexit_conf_thresholduse_exit_confuse_entry_confexit_raw	entry_rawregime_window
regime_min	regime_okr   time_okr   r   r   r   s   &&&&                       r   apply_pine_time_gater;  I  sS    =HW__--	B}})\9DV,1()*-&']]FF$bii288&DE
 &+hhRZZh0 	 %wK  rzz 2vJbjj1
 	gmm,!"EFJJ'JERSO6::&H%PQN

+Z\c de

+I4 PQM ,KU!STN[[^~-[[^n,.(* 	 YYuBHH5


*-.55c:cAJ[[^~-[[^n,. 	 [[^.[[^o-/[[^#% ^^A%^001 	 [[^65;RS	

#4a89Mvzz"<gFGJqMMAMFKKMPZZ	IId"((3	6::4e<==-SUS]S]B]M!2a!78	>>"V*%DemG
TS[)Y&088?HHtHTI7"**51:::FH6::&A3GH5PN$5
72::.
6
"**-%!FJ	 BzN$B"B~Ir   c                Z    V ^8  d   QhR\         P                  R\        \        ,          /# r   )r6   r   r>   r?   )r   s   "r   r   r     s"      2<< DJ r   c                   . pRpR;p;rEV P                  4        F  w  rgV'       g(   VR,          '       d   RpVR,          pVR,          pTpK4  V'       g   K>  VR,          '       g   KO  RpVR,          pVR,          p	W,
          V,          ^d,          p
VP                  RVR	VR
VRV	R\        WI4      RV
RVRV/4       R;p;rEK  	  V# )z4Walk signals DataFrame and extract entry/exit pairs.FNr  Tr   r  r  r]   r^   r_   r`   r   gross_pnl_pct	entry_idxexit_idx)ri   rp   r   )r   r{   r   r]   r	   r?  idxrx   r^   r
   	gross_pnls   &          r   extract_python_tradesrC    s    FF&**H*x$$&#o..FFHGHIVN++F6{G7|G +x7#=IMM X!?  /32H2x)/ '0 Mr   c                    V ^8  d   QhR\         \        ,          R\         \        ,          R\        R\        R\        \         \        ,          \         \        ,          \         \        ,          3,          /# )r   	tv_trades	py_tradesr5   tolerance_barsr   )r>   r?   r%   rj   r   )r   s   "r   r   r     sZ     )/ )/d)/d)/ )/ 	)/
 4;T
DJ./)/r   c                   \        V4      pWC,          pV  Uu. uF  qfR,          '       d   K  VNK  	  pp\        V4      p\        V4      p	. p
V F  pRpV\        P                  ! ^R7      ,           pV FB  pVR,          V,
          p\	        VR,          V,
          4      pVV8:  g   K5  VV8  g   K>  TpTpKD  	  Vf   Kq  V
P                  W34       VP                  V4       W9   g   K  V	P                  V4       K  	  WV3# u upi )am  
Match TV and Python trades by entry time.

TV fills at open[T+1], so TV entry time = Python signal bar time + 1 bar.
We subtract one TF offset from the TV entry time before comparing.

Returns:
    matched       : list of (py_trade, tv_trade) pairs
    py_only       : Python trades with no TV match
    tv_only       : TV trades (non-margin) with no Python match
rb   N)secondsr]   )r;   r>   r6   r7   absrp   remove)rE  rF  r5   rG  offset	tolerancer|   tv_realavailable_tvunmatched_pymatchedpybestbest_errtvtv_adjerrs   &&&&             r   match_tradesrX    s    " &!F'I#:)Q[>>qq)G:=L	?LGr||A66B
^f,Fbnv-.CiC(N  NNB:&%!##B'   ,..+ ;s
   DDc                z    V ^8  d   QhR\         P                  R\        R\        \         P                  ,          /# )r   r   rJ   r   )r6   r   r%   r   r   )r   s   "r   r   r     s.      ",, # (299:M r   c                4   . pV FV  pW0P                   9  d   K  \        P                  ! W,          RR7      P                  R4      R8g  pVP	                  V4       KX  	  V'       g   R# V^ ,          P                  4       pVR,           F  pWV,          pK  	  V# )zHReturn truthy marker mask for any available exported Data Window column.r  r  r   N:   NN)rJ   r6   r#  r$  rp   r!  )r   rJ   masksrN   markeroutmasks   &*     r   _marker_maskr`    s    Eoo%w|H=DDSISPV	 
 
(--/Cb		j Jr   c                    V ^8  d   QhR\         \        ,          R\        P                  R\        R\        P
                  R\        \        P
                  ,          R\        \        ,          /# )r   rE  r   r5   r   r  r   )r>   r?   r6   r   r%   rn   r   )r   s   "r   r   r     s]     2 2Dz2\\2 2 <<	2
 
",,	2 d^2r   c                   \        VRR4      pVe   RVP                  9  d   R# \        VR4      pVf#   \        P                  ! RVP                  R7      pV  Uu. uF  qwR,          '       d   K  VNK  	  pp\        V4      p	\        P                  ! VR,          4      p
\        VP                  V
4       UUu/ uF  w  rWbK	  	  ppp. p\        4       pV F  pVR	,          V	,
          pVP                  V4       VP                  V4      pVf   VP                  VVR
34       KO  \        VP                  V,          4      '       d   Ks  VP                  VVR34       K  	  WV( ,          W8  ,          pVe   VW8*  ,          p\        V
V,          4      p\        VV,
          4      pRRR\        V4      R\        V4      \        V4      ,
          RVR\        V4      RV/# u upi u uppi )a!  Compare Strategy Tester entries with exported Pine entry markers.

The TV trade list records fills one bar after the Pine signal. The chart
export records the signal-bar `Entry (...)` marker. When these disagree,
trade-list parity is not trustworthy even if Python and chart scores match.
zentry (standard)zentry (confirmed)Nr   zmissed entryFr
  rb   r]   z#no chart bar at adjusted entry timez.no exported Entry marker on adjusted entry bar	availableTtv_counttv_with_markertv_without_markerchart_exec_countchart_without_tv)r`  rJ   r6   r   r  r;   r   zipsetaddr:   rp   r   locrm   r   )rE  r   r5   r   r  entry_markermissed_entryr|   real_tvrL  signal_timesrA  tstime_to_idxrf  tv_signal_timesrU  	signal_dt
chart_execchart_exec_timesrh  s   &&&&&                r   check_tv_entry_markersrw    s     );=PQLvW__<8Lyygmm<#:)Q[>>qq)G:vF>>'&/2L*-gmm\*JK*Jws27*JKKeOzNV+	I&ooi(;$$b)5Z%[\l&&s+,,$$b)5e%fg  -1FGJ
<#67
<
34.@A 	TCL#g,->)??.C 01, - ; Ls   G 0G 9G%c                \    V ^8  d   QhR\         P                  R\        R\        R\        /# )r   r   bar_idxcontextr   )r6   r   rj   r%   )r   s   "r   r   r   H  s,      2<< #  C r   c                $   \        ^ W,
          4      p\        \        V 4      ^,
          W,           4      pV P                  W4^,            p\	        V 4      pT;'       g    RpRRR RRR RRR RVR	 RR
R RRR 2.pVP                  R4       \        VP                  4       4       F  w  p	w  rW8X  d   RMRp\        W4      p\        P                  ! V4      '       g   VR MRpRV P                  9   d   VR,          R MRpVP                  RR4      '       d   RMRpVP                  RR4      '       d   RMRpVP                  RV
R R\        VR,          4      R,          R RVR RVR	 RVR RVR V 24       K  	  RP                  V4      # )z;Return a compact table of activation scores around bar_idx.tv_score  bar>4r   z>19r/  z>9z>12rZ   z>5r[   z <<<rY   z.2fz   n/ar  r  FE.r  X:N   N
zF  --------------------------------------------------------------------)maxminr   r   r   rp   	enumerateri   r   r   isnanrJ   r:   r%   rL   )r   ry  rz  lohirowstv_coltv_labellinesr   ridxrx   r]  r|  
tv_score_sscore_ventry_fexit_fs   &&&               r   score_contextr  H  s   	Q!	"B	S\Aw0	1B<<6"DW%F##H%2fS\GB<r(3r'RTUWX^_aWbcdE	LL!#DMMO4;D?!#/.0hhx.@.@~h
6HGOO6[S+,S1ai%88#c%88#cb	CF,S1#6bBzRUFVVXY`acXddfgmnpfqrxqyz	
 5 99Ur   c          
      h    V ^8  d   QhR\         R\        P                  R\        R\        R\        /# )r   tv_trader   r0  r5   r   r?   r6   r   r   r%   )r   s   "r   r   r   _  s5     & &t &bll &U & &%(&r   c           	     j   \        V4      pV R,          V,
          pV^,          pVR,          WV,
          8  VR,          WV,           8*  ,          pW,          pVP                  '       d   R# VP                  VR,          P                  V4      P	                  4       P                  4       ,          p	VP                  V	,          p
V
P                  R\        R4      4      pV	^ 8  d   VP                  V	^,
          R3,          M
\        R4      p\        W4      p\        P                  ! V4      '       g   \	        W,
          4      M
\        R4      p\        P                  ! V4      '       * ;'       d    W8  ;'       d    W8  p. pV'       d   VP                  R4       MFVP                  RVR R	VR R
V R24       W8  d   VP                  R4       MVP                  R4       \        P                  ! V4      '       g&   V^8  d   VP                  RVR RVR RVR R24       RP                  V4      # )zj
Try to explain why Python missed a TV entry.
Looks for the Python bar corresponding to TV entry - 1 bar.
r]   r   z'UNKNOWN (no matching bar found in data)r  r   z9Python DID fire crossunder here (state diverged earlier?)zPython score at signal bar: .1fz (prev z, threshold )u@   → Score never dropped below threshold (score difference vs TV)uD   → Score was already below threshold (no prior above-threshold bar)zTV exported score=z vs Python score=u    (Δ=u   ) → SCORE_DIFF | )r;   emptyr  subrJ  argminrl  r:   r   r   r   r  rp   rL   )r  r   r0  r5   rL  py_signal_timetolr_  nearrA  rx   	score_now
score_prevtv_score_now
score_diffcrossunder_pypartss   &&&&             r   classify_tv_onlyr  _  s    vFj)F2N
1*CFO~33>K_8_`D=Dzzz8
**T&\%%n599;BBD
EC
++c
C+U5\:I=@1WS1W&889%PU,J!#/L79xx7M7M#i./SXY^S_J*--ttJ4QttXaXsMEPQ3Ic?'*UXIYYefuevvwxy'LL[\LL_`88JJN),s);;LYWZO[`aklo`p  qA  B  	C::er   c          
      h    V ^8  d   QhR\         R\        P                  R\        R\        R\
        /# )r   py_trader   r0  r4  r   )r?   r6   r   r   r   r%   )r   s   "r   r   r     s5     ; ;t ;bll ;U ;%);69;r   c           
     ~   V R,          pRVP                   9   p\        V4      pVRJp. pV'       Ed   V^8  Ed   V'       d   VP                  V^,
          R3,          M
\        R4      p	V'       d   VP                  V^,
          R3,          M
\        R4      p
V'       d   VP                  V^,
          V3,          M
\        R4      pV'       d   VP                  V^,
          V3,          M
\        R4      p\        P
                  ! V	4      '       gV   \        P
                  ! V
4      '       g:   W8  ;'       d    W8  pTP                  RV	R RV
R RT R	V'       d   R
MR 24       \        P
                  ! V4      '       g   \        P
                  ! V4      '       g   W8  ;'       d    W8  pTP                  RVR RVR RV'       d   RMR 24       \        P
                  ! V
4      '       g<   \        W,
          4      ^8  d&   VP                  R\        W,
          4      R R24       EMV'       d   VP                  VR3,          M
\        R4      pV^ 8  d%   V'       d   VP                  V^,
          R3,          M
\        R4      pV'       d   VP                  WF3,          M
\        R4      p\        P
                  ! V4      '       gW   \        P
                  ! V4      '       g;   VV8  ;'       d    W8  pTP                  RVR RVR RT R	V'       d   R
MR 24       \        P
                  ! V4      '       g   V^ 8  d   VP                  V^,
          V3,          M
\        R4      p\        P
                  ! V4      '       * ;'       d    VV8  ;'       d    VV8  pTP                  RVR RVR RV'       d   RMR 24       \        P
                  ! V4      '       g>   \        VV,
          4      ^8  d'   VP                  R\        VV,
          4      R R24       V'       g   R# RP                  V4      # )u   Try to explain why Python fired an entry that TV didn't.

With use_entry_conf=True the crossunder was at bars t-2→t-1; the entry
fires at t (confirmation bar).  Without confirmation it is t-1→t.
r?  r  Nr   u   Python crossunder (t-2→t-1): r      → z (threshold z): YESzno crossunder?u   TV exported score (t-2→t-1): rI   zYES (TV should also fire)zNO (TV rightly quiet)zScore delta at crossunder bar: u    → SCORE_DIFFzPython crossunder: zTV exported score crossunder: zScore delta: UNKNOWNr  )	rJ   r   rl  r   r   r  rp   rJ  rL   )r  r   r0  r4  rA  	has_scorer  has_tv_scorer  xprevxcurrxprev_tvxcurr_tv
crossundertv_xur  r  r|  tv_prevs   &&&&               r   classify_py_onlyr    s    ;
C"goo5IW%F%LE~#(<EC!G%7785QV<<EC!G%7785QV<3?7;;sQw/U5\3?7;;sQw/U5\288E??2QQ9PJLL1%E%/sJ5L\2]_ ""bhhx&8&80RRx7QELL1(3uXcN S38/>UVX 88E??s5+;'<q'@>s5CS?TUX>YYhij >GW[[&8!89ERWL	ADqYW[[q*<!<=\abg\h
1=W[[-5<$$(;(;$7ZZi>YJLL%j%5U9S//sJ5L\2]_ xx!!69Aggkk#'6/25<G'**mmO1KmmRZ]lRlELL0U8C. Q38/>UVX 88I&&3y8/C+Dq+H}SX1E-Fs,K?[\::er   c                t    V ^8  d   QhR\         R\         R\        P                  R\        R\        R\        /# )r   r  r  r   r   r1  r   r  )r   s   "r   r   r     s=     3 3T 3T 3BLL 3+03BG3LO3r   c                   V R,          pVR,          pWe,
          P                  4       R,          pRVP                  4        RVP                  4        RVR R2.pVP                  RV R	,          R
 RVR,          R
 R24       V R,          p	V	\        V4      8  d   VP                  V	,          MRp
V
e   RVP
                  9   d
   V
R,          MRpRpVei   V	^8  db   RVP
                  9   dQ   VP                  V	^,
          ,          R,          pVP                  V	^,
          ,          R,          pW8  d	   W8  d   RpV'       d)   VP                  RVR R24       VP                  R4       MvV^ 8  dB   VP                  RVR R24       Ve   VP                  RVR 24       VP                  R4       M.VP                  RV 24       Ve   VP                  RVR R24       RP                  V4      # )u  Classify why matched entry has different exit.

Determines whether Python's exit was triggered by the trailing stop or by a
score crossunder, by checking whether the 2-bar crossunder pattern is present
at the Python exit bar.  Trailing stop and score-crossunder exits both call
strategy.close("long") in Pine, so TV's trade list cannot distinguish them —
only the Python-side patterns can.
r^     zPython exit z / TV exit u    (Δ z+.0fh)zPython P&L r   +.1fz% / TV P&L r   %r@  Nr  FTzPython exit bar score: r  u    → SCORE_CROSSUNDER_MISMATCHzTV and Python exited on different score-crossunder events. If score parity passes, this is usually downstream of an earlier lifecycle/export mismatch.zTrailing stop .0fu   % active → TRAILING_STOPzqPython trail_high uses bar high (same as Pine); stop triggered at close. Residual timing difference is intrinsic.z!No trailing stop; exit_threshold=u    → EXIT_CONFr  )total_secondsdaterp   r   r   rJ   rL   )r  r  r   r   r1  py_exittv_exitdiffr  r@  exit_rowr/  is_score_crossunderprev1prev2s   &&&&&          r   classify_exit_mismatchr    s    y!Gy!G //1D8DGLLN+;w||~6FeDQU;VXYZE	LL;x	248H]D[\`Caabcd
#H)1CL)@w||H%dH-5-AFX\c\k\kFkH'(rvE
  X]/AW__/TX\*+=>X\*+=>"u'="&.uSk9WXYj	
 
!	~nS%99STULL25+>?7	

 	88HIJLL25+^LM::er   c                  2)  aP \         P                  ! R \         P                  \        R7      p V P	                  RRRR7       V P	                  RRRR7       V P	                  RR	R
R7       V P	                  RRRR7       V P	                  RR	RR7       V P	                  R\
        ^RR7       V P	                  RRRR7       V P	                  R\
        ^RR7       V P	                  RRRR7       V P                  4       pVP                  ;'       g    \        VP                  4      pVf   \        R4       \        R4       Rp\        RV R \        V4       R!24        ^ R"IHp V! VP                  4      w  rEpV'       d.   \        R#4       V F  p\        R$V 24       K  	  \        R%4       TP                  pTf   \!        TP                  4      P"                  p	T	P%                  R&R'4      P'                  4       p
\)        TP*                  4      p\!        R(4      R)T R'T
 R*2,          pTP-                  4       '       d   \/        T4      p\        R+T 24       M\        R,T R-24       \        R.TP0                   24       \3        TP0                  4      pT Uu. uF  qR/,          '       d   K  TNK  	  ppT Uu. uF  qR/,          '       g   K  TNK  	  pp\        R0\5        T4       R1\5        T4       R224       T'       d   \7        T4      M/ p\        R3TP*                   R4TP                   24       \9        TP                  TTP*                  R57      p\:        P<                  ! \>        4      p\:        P<                  ! \@        4      p\C        TTTTR67      p\E        T4      pT Uu. uF  qR7,          T8  g   K  TNK  	  pp\        R8\5        T4       R9TPG                  4        R:TPG                  4        R;\5        T4       R<2	4       \I        TPK                  R=R>4      4      p\I        TPK                  R?R@4      4      p\I        TPK                  RARB4      4      pTPK                  RCRD4      pTPK                  RER4      p\        RF4       \        RGT RHT RI24       \        RJT RKT RI24       \        RLT RM24       \M        TTY!PN                  4      w  ppp\        T4      TPN                  ,          p. . p!p T Fe  w  p"p#T#RN,          \        T4      ,
          p$\Q        T"RN,          T$,
          4      T8:  d   T PS                  T"T#34       KR  T!PS                  T"T#34       Kg  	  T'       d   \U        RO T 4       4      M\:        P<                  ! RP4      p%T U&u. uF  p&T&R7,          T%8:  g   K  T&NK  	  p'p&T U&u. uF  p&T&R7,          T%8  g   K  T&NK  	  p(p&\W        TTTTT'       d   T%\        T4      ,
          MR	4      p)^Pp*\        RQRRT*,           24       \        RS4       \        RRT*,           4       \        RT\5        T4      RU RVT%PG                  4        RI24       \        RW\5        T4      RU 24       \        RX\5        T 4      RU RY\5        T 4      \U        \5        T4      ^4      ,          ^d,          RZ R[24       \        R\\5        T!4      RU 24       R]\5        T'4       R^T%PG                  4        R_\5        T(4       R`2p+\        Ra\5        T4      RU T+ 24       \        Rb\5        T4      RU 24       T'       d   \        Rc\5        T4      RU Rd24       \        RRT*,           4       T)e   T)Re,          p,T)Rf,          p-T,'       g   T-'       g   TPX                  '       d   \        Rg4       \        RhT)Ri,           RjT)Rk,           24       \        RlT)Rm,           RY\5        T-4       Rn24       T,'       dE   \        Ro4       T,Rp,           F,  w  p#p.p/\        RqT#Rr,           RsT. RtT#R7,           RuT/ 24       K.  	  T-'       d*   \        Rv4       T-Rp,           F  p.\        RwT. 24       K  	  Rx;p0p1T F?  pT0^TRy,          ^d,          ,           ,          p0T1^TRz,          ^d,          ,           ,          p1KA  	  T0^,
          ^d,          p2T1^,
          ^d,          p3 \:        PZ                  ! TP0                  R{R|7      oPSPP\                  P.                  P_                  4       SPn.        \a        TP3R} lR 4       R	4      p4T4'       d)   SPT4,          Pc                  4       Pd                  R,          M
\I        R~4      p5\f        ^d,          p6\5        T4      \5        T4      8H  p7\i        T5\H        4      ;'       d    \j        Pl                  ! T54      '       * ;'       d    T5p8\        4        \        RRT6,          R T2R RM24       \        RRR T5R RM24       T8'       dC   T7'       d;   \Q        T2T5,
          4      \Q        T54      ,          ^d,          p9\        RT9RZ R24       M,T8'       d%   \        R\5        T4       R\5        T4       R24       \        RRR T3R RM24       \        4        T '       Ed   \        RQRT*,           24       \        R\5        T 4       R24       \        RT*,           4       RRR RRR RRR RRR RRR RRR RRR RRR 2p:\        T:4       \        RR&T*^,
          ,          ,           4       T  EFp  w  p"p#T#R7,          \        T4      ,
          p;T#RN,          \        T4      ,
          p$T"R7,          T;,
          Po                  4       R,          p<T"RN,          T$,
          Po                  4       R,          p=T"Ry,          T#R,          ,
          p>\Q        T=4      ^8  d   RT=R R2MRp?\        RT#Rr,          R R\/        T"R7,          PG                  4       4      R R\/        T#R7,          PG                  4       4      R R\/        T"RN,          PG                  4       4      R R\/        T#RN,          PG                  4       4      R RT?R RT"Ry,          R RT#R,          R RT>R RM24       EKs  	  T!'       d   \        RQRT*,           24       \        R\5        T!4       R24       \        RT*,           4       T! F  w  p"p#\        RT#Rr,           R24       \q        T"T#TTT4      p/T/Ps                  R4       F  p@\        RT@ 24       K  	  TPt                  '       g   Ke  T"R,          f   Kr  \        \w        TT"R,          TPv                  4      4       K  	  T''       Ed   \        RQRT*,           24       \        R\5        T'4       R24       \        RT*,           4       T' F  p"\y        T"TT\{        T4      R7      p/\        RT"R7,          PG                  4        RT"RN,          PG                  4        RT"Ry,          R RM24       T/Ps                  R4       F  p@\        RT@ 24       K  	  TPX                  '       g   K  T"R,          f   K  \        \w        TT"R,          TPv                  4      4       K  	  T('       d   \        RQRT*,           24       \        R\5        T(4       RT%PG                  4        R24       \        RT*,           4       T( FJ  p"\        RT"R7,          PG                  4        RT"RN,          PG                  4        RT"Ry,          R R24       KL  	  T'       Ed   \        RQRT*,           24       \        R\5        T4       R24       \        RT*,           4       T EFo  p#\}        T#TTT4      p/\        RT#Rr,           RT#R7,          PG                  4        RT#RN,          PG                  4        RT#R,          R RM2	4       T/Ps                  R4       F  p@\        RT@ 24       K  	  \        T4      pAT#R7,          TA,
          pBTA^,          pCTR,          TBTC,
          8  TR,          TBTC,           8*  ,          pDTTD,          pETEP~                  '       d   K  TPX                  '       g   EK
  XEP                  TER,          P                  XB4      PQ                  4       P                  4       ,          pF\        \w        TTFTPv                  4      4       EKr  	  T'       d   \        RQRT*,           24       \        R4       \        RT*,           4       T FT  p#\        RT#Rr,           RT#R7,          PG                  4        RT#RN,          PG                  4        RT#R,          R RM2	4       KV  	  \        RQRRT*,           24       \        R4       \        RRT*,           4       ^ pGT' F-  p"\y        T"TT\{        T4      R7      pHRTH9   g   K$  XG^,          pGK/  	  T F#  p#\}        T#TTT4      pHRTH9   g   K  XG^,          pGK%  	  \5        T'4      \5        T4      ^,           8  pI^ pJ^ pKT! FB  w  pLpM\q        TLTMTTT4      pNRTN9   d   XJ^,          pJK'  RXN9   d   XK^,          pKK9  XK^,          pKKD  	  . pOXG^ 8  d6   XOPS                  RXG RTP                   RT RTP                   RT R24       XI'       d+   XOPS                  R\5        T'4       R\5        T4       R24       T''       g	   T'       d+   XOPS                  R\5        T'4       R\5        T4       R24       T)eW   T)Re,          '       g   T)Rf,          '       d9   XOPS                  R\5        T)Re,          4       R\5        T)Rf,          4       R24       XJ^ 8  d   XOPS                  RXJ R24       XK^ 8  d   XOPS                  RXK RTR R24       XO'       g   XOPS                  R4       XO F  pH\        TH4       \        4        K  	  \        R4       \        R4       \        R4       \        RRT*,           4       R	#   \         d     ELi ; iu upi u upi u upi u up&i u up&i   \         d    \I        R~4      p5 EL'i ; i)uJ   Compare TradingView trade list vs Python backtest — TV parity diagnostic)descriptionformatter_classepilogz--tv-tradesTz#TradingView exported trade-list CSV)r+  helpz--dataz;OHLCV+indicator data CSV (e.g. data/COINBASE_BTCUSD-4H.csv)z--paramsNzGWinner params CSV or JSON (auto-detected from data filename if omitted))defaultr  z--strategy-filestrategy_mlp_scores.pyzEStrategy Python file in strategies/ (default: strategy_mlp_scores.py)z--timeframezGTimeframe override (4H/6H/8H/12H/1D). Auto-detected from data filename.z--tolerance-barsz*Entry-match tolerance in bars (default: 2))typer  r  z	--verbose
store_truez2Show score context table for every divergent trade)actionr  z--score-contextzIBars of score context to show per divergence in verbose mode (default: 4)z--exit-detailz;Show detailed exit-mismatch tables for entry-matched tradeszB[WARN] Could not detect timeframe from filename. Defaulting to 4H.z4       Pass --timeframe 4H/6H/8H/12H/1D to override.r   zTimeframe: z  (TV fills 1 bar ahead = z offset))validate_fileuO   
  ⚠️  CHART-DATA INTEGRITY ERRORS — parity results below may be invalid:z       ERROR: uG          → re-export full clean history (tools/validate_chart_data.py)
r'   r(   zresults/winnersoptimization_winner_r   zAuto-detected params: z)[WARN] No params file found for strategy z. Using strategy defaults.z
Loading TV trades from: rb   zTV trades: z real signal  +  z margin-callzRunning Python strategy z on: )r   )r   r  r]   zPython trades: z (Pine timeCondition r  z; z total after time gate)r  r  r  r  r  r   r  Fr  z
Key params:z  Entry threshold:  z  (use_entry_conf=r  z  Exit threshold:   z  (use_exit_conf=z  Trailing stop:    r  r^   c              3   2   "   T F  qR ,          x  K  	  R# 5i)r^   Nr   )rV   r|   s   & r   rW   main.<locals>.<genexpr>p  s     5W||Ws   z
2099-01-01r  =z  MATCH SUMMARYz  Total TV real trades  : r  z  (coverage through z  Total Python trades   : z  Entry + exit matched  : z  (r  z% of TV)u     Entry matched, exit Δ : z  (IS: z, OOS after rI   u     — OOS are expected, not bugs)z  Python-only (extra)   : z  TV-only (missed)      : z  TV margin-call trades : z  (not modelled in Python)rf  rh  z
  TV/chart entry-marker check:z,    TV entries with exported chart marker : re  /rd  z,    Chart executable markers in TV window : rg  z not present in TV trade list)z*    First TV entries without chart marker::N   Nz	      TV#r\   z signal z (fill u   ) — z3    First chart executable markers missing from TV:z      r   r   r>  rA   rB   c              3   N   <"   T F  pVSP                   9   g   K  Vx  K  	  R # 5irT   rU   )rV   r0   	tv_df_raws   & r   rW   r    s(      +Fd	))) TFs   %
%r   r}  z)Python cumulative P&L (%.1f%%/side comm):z<42z>12,.1fzTV cumulative P&L:u!       → net vs TV relative diff: z.%  (residual = fill price / slippage / timing)u,       → ⚠️  trade counts differ (Python z vs TV zW); cumulative totals are NOT comparable. See per-trade table / unmatched section below.z(Python gross (no commission, reference):u   ─z  FULLY MATCHED (z trades)#z>3zPy Entryz>10 zTV EntryzPy ExitzTV ExitzPy P&L%z>8zTV P&L%u   Δ P&L%z>7r  r   z(+r  r  rY   6sz>8.1fz% z%  z>+7.1fu3     EXIT-MISMATCHED (same entry, different exit) — z tradesz
  TV#:r  z    r@  z  PYTHON-ONLY / IS (u3    trades — Python fires in IS period, TV does not))r4  z	
  Entry z  Exit z  P&L r  r?  z  PYTHON-ONLY / OOS (u!    trades — after TV export ends z, not a parity issue)z  Entry z%  [OOS]z  TV-ONLY (u&    trades — TV fires, Python does not)r   z<  TV MARGIN-CALL TRADES (micro-size, not modelled in Python)z  TV#z  DIAGNOSTIC RECOMMENDATIONS
SCORE_DIFFSCORE_CROSSUNDER_MISMATCHTRAILING_STOPz  [u    SCORE_DIFF] Python activation_score differs from the TV-exported score on crossunder bars.
    → For activation_scores, run tools/diagnose_tv_parity.py --data z
 --params u]   
      to see per-component breakdown.
    → For MLP, run tools/check_mlp_parity.py --data z' --weights <mlp_weights_file> --params zG
      and re-export from TradingView if mlp_score is missing or stale.z  [CASCADE RISK] Python has z extra IS trades vs u    TV-only.
    → Extra Python trades often stem from a single prior exit divergence that
      leaves Python "flat" while TV is "long", allowing Python to re-enter
      on bars where TV is already in position.z  [UNMATCHED TRADES] z Python-only IS trades and u
   TV-only trades remain.
    → Do not treat this run as trade-list parity. First confirm the chart export
      covers the full TV trade-list range and that the Strategy Tester export was
      generated from the same symbol, timeframe, preset, and script revision.z  [TV/CHART EXPORT MISMATCH] z0 TV entries lack a matching chart entry marker; uQ   chart executable markers are absent from the TV trade list.
    → The exported Data Window and Strategy Tester files do not describe the same
      Pine lifecycle, or the Strategy Tester export is from a different preset/script revision.
      Re-export both from the same chart state before interpreting Python lifecycle differences.uX   SCORE_CROSSUNDER_MISMATCH exits] TV/Python exits landed on different score-crossunder events.
    → First check score parity. If it passes, treat these as downstream lifecycle/export-state
      effects from an earlier unmatched entry or exit, not as score-computation drift.
    → Use --exit-detail flag to see score context on exit bars.z$ TRAILING_STOP exits] Trailing stop u   % active.
    → Python trail_high uses bar high (same as Pine); timing difference from close-evaluation vs
      intrabar evaluation in Pine. Not a bug — intrinsic fill difference.
    → Use --exit-detail flag to see score context on exit bars.zK  Parity looks good! Minor differences are expected from fill-price offset.zK  Tip: run with --verbose for score context tables on all divergent trades.zV       activation_scores: run tools/diagnose_tv_parity.py for per-component breakdown.zU       MLP: run tools/check_mlp_parity.py before interpreting trade-list differences.)zCumulative P&L %zCumulative PnL %r   )CargparseArgumentParserRawDescriptionHelpFormatter__doc__add_argumentrj   
parse_args	timeframer3   dataprintr;   tools.validate_chart_datar  ro   r   r   r*   replacer+   r   r   r   r%   rE  r   r   r   r   r6   rn   r   r   r;  rC  r  r   r:   rX  rG  rJ  rp   r  rw  verboserf   rJ   rg   rh   dropnar   COMMISSION_RATEr   r   r  r  r  splitexit_detailr  r  r   r  r  r  r  r  )Qparserargsr5   r  _derrs_dwarnsr(   _er   r*   asset_tfstrategy_name	candidaterE  r|   rN  	tv_marginr   r   
pine_startpine_endall_py_tradesrF  r0  r1  r   r4  r3  rQ  py_onlytv_onlyexit_tolerance
full_matchexit_mismatchrR  rU  tv_exit_adj
last_tv_dtp
py_only_ispy_only_oosmarker_checkWoos_note
tv_missingchart_missingrt  reasonpy_equity_netpy_equity_gross
py_pnl_netpy_pnl_grosscum_col
tv_cum_pnlpctcounts_alignedtv_cum_validrelhdrtv_entry_adjentry_dexit_dpnl_dflagpartrL  	py_bar_dtr  r_  r  rA  score_diff_countrcascade_riskexit_score_xunder_countexit_trailing_countr  r  labelrecsr  sQ                                                                                   @r   mainr)    s	   $$` <<F
 B  D
Z  \

f  h
)3Kd  f
f  h
*aI  K
|Q  S
)Qh  j
Z  \D ^^::/		:F~RSDE	Kx9)F:K9LH
UV	;*4995derd+, \]
 ++KDII##<<S)//1%d&8&89*+0D]OSTU]T^^b.cc	i.K*;-89=m_Lfgh 
&t~~&6
78t~~.I%<Iq{^^IG<%8Iq;II8	KG~%6s9~6Fl
ST)4[%"F	$T%7%7$8dii[
IJ!$))V4CUCUVGk*J||I&H"7F*(SG)'2M
 *IMqz]j-HMII	
#i.) *)01x}}6Gr}
5	7 VZZ(KUSTOVZZ(JUSTNVZZ(CSIJNzz"A5INzz"@$GM	M	  11CNCSST
UV	  00A-PQ
RS	  0
23 !-Y	6K^K^ _GWg v&)<)<<N "BJBmi&77r)}{*+~=r2h'  "b*  :A35W55bllS_F`J&Fw!!J-:*EAAwJF&Fw!!J-:*EAAwKF)*1
Yv&&tL 	A	Bs1ug,	O	SUG	&s7|B&77KJOOL]K^^_
`a	&s9~b&9
:;	&s:r&:#c*ocRUV]R^_`Na>abe>efi=jjr
st	'M(:2'>
?@Z)joo6G5H3{K[J\\|}H	&s7|B&7z
BC	&s7|B&7
89*3y>"*==WXY	SUG!"56
$%78$,,,46> 012!L4L3MO > 234 5&''EG
 BC-7^^)B	6#B{O#4HYK H!!#J 0vh@ .<
 KL!.r!2!2IF9+./ "3 '*)MOA)s 223A/ 2S 889  "A%,J#a'3.L
"[[+F	%--11779	+F +

 >EYw'..055b9%PU,
 C
C^s7|3N":u5NN"((::NO^^T^L	G	B:S@EjQXEYYZ
[\	B#C(G(<A
>?*z)*S_<sB1#c ;< = 	>	 	<S^<LGW ?@ 	A 
B9#>|G>TTU
VW	G z57)n!#j/!2(;<q	3r("Z,Aj-=R	#aPYZ]^`ajkm`nnopyz|o}}  AJ  KM  @N  Oc
dSAE]"# FBj>If,==Li=If,==K*~4CCELG)}3BBDLFmb&77E-0[1_6#,b)"DR_R(r*~**,-c2!C:8K8K8M4Ns3SSUr)}))+,S13r)}7I7I7K3LS2QQRSWXZR[[]i='r"]*;E)B#eF^STV ! 57)nCCDVCWW^_`q	#FBGB{O,A./+BG^^\FU+TFm$ ,BzN$>mGR
^T=O=OPQ $ z57)n$S_$55hijq	B%b'?SWXfSghFJr*~2245WR	]=O=O=Q<RRXY[\eYfgkXllmnoU+TFm$ ,|||; ;mGR_d>P>PQR  57)n%c+&6%77XYcYhYhYjXk  lA  B  	Cq	BHR
^002372i=;M;M;O:PPVWYZcWdeiVjjrst  w57)nCL>)OPQq	B%b'?FKFGB{O,HR
^5H5H5J4K7SUV_S`SeSeSgRhhnoqr  pA  BF  oG  GH  I  JU+TFm$ , #6*FJ&0I!C!&/Y_<T]`cTcAcdD D:::$,,,jjf!1!1)!<!@!@!B!I!I!KLmGS$2D2DEF   57)nLNq	BE"[/*(2j>3F3F3H2IQST]Q^QcQcQePfflmop}m~  @D  mE  EF  G  H  
Bs1ug,	
()	SUGR/$~J^_1!  R/6B1! 
 z?S\A%55L  +(&x7NTbc&%/#q(#%1$1$ , D!"# $UUYU^U^T__ijuiv wEEIYYKOv  xC  wD DUV	
 *3z?*;;OPST[P\~ ^= >	
 W#C
O#44OPST[P\~ ^\ ]	
 ())\:L-M-M+< 34566f< 2345 6op	
 ")* +P Q	
 Q%&&J>Z]J^ _P Q	
 aba  
WY	bd	ac	SUG[
  ( =8 JF GFJ  "5\
"sv   AAQ AQ#.AQ#:AQ(AQ()AQ-=AQ-AQ2-AQ29AQ7AQ7BAQ< QAQ QAQ Q<ARRAR__main__)r  rT   )r   )r  )F)4r  r  importlib.utilr   r   r   r   pathlibr   typingr   numpyr   pandasr6   r=   insertr%   r   r   r   configr   r   r   rp   r  r   r7   r,   r.   r3   r;   r   r   r   r   r   r   r   r   r;  rC  rX  r`  rw  r  r  r  r  r)  __name__r   r   r   <module>r3     s  0d    	 
     3tH~--/66==> ? 6 6 DN**,33::; <  *94 	2<<a 2<<a 2<<a 	2<<b!2<<Q udE4F(;BN*06 &&)RdNF)/\ 2n.&R;|3pyx zF r   