Ë
    Bp±jÒÏ  ã                   óÈ  — d Z ddlZddlZddlZddlZddlZddlmZ ddl	m
Z
 ddlZddlZej                  j!                  d e ee«      j'                  «       j(                  j(                  «      «       ddlmZmZmZ ej                  j3                   e ee«      j'                  «       j(                  j(                  «      «       dZefdeded	ed
efd„Z ej:                  d¬«       ej:                  d¬«       ej:                  d¬«       ej:                  d¬«       ej:                  d¬«      dœZdddddœZded
e
e   fd„Z ded
ej:                  fd„Z!ded
e"e#   fd„Z$ded
efd „Z%d!ed
e#fd"„Z&	 dHded#e#ded
ejN                  fd$„Z(d%ejN                  d
e
e   fd&„Z)d'ejT                  d%ejN                  d
efd(„Z+d
e,fd)„Z-d*ej\                  d+ej\                  d,ej\                  d-ej\                  d.ed
e/ej\                  ej\                  ej\                  f   fd/„Z0	 dId%ejN                  d#e#d0ejb                  d1e
ejb                     d
ejN                  f
d2„Z2d%ejN                  d
e"e#   fd3„Z3	 dJd4e"e#   d5e"e#   ded6e4d
e/e"e/   e"e#   e"e#   f   f
d7„Z5d%ejN                  d8ed
e
ejT                     fd9„Z6	 dId4e"e#   d%ejN                  ded0ejb                  d1e
ejb                     d
e
e#   fd:„Z7dKd%ejN                  d;e4d<e4d
efd=„Z8d>e#d%ejN                  d?eded
ef
d@„Z9	 dLdAe#d%ejN                  d?edBe,d
ef
dC„Z:dAe#d>e#d%ejN                  d.edDed
efdE„Z;dF„ Z<e=dGk(  r e<«        yy)MuÊ  
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{®Gázt?Úentry_pxÚexit_pxÚcommission_rateÚreturnc                 ó8   — | d|z   z  }|d|z
  z  }||z
  |z  dz  S )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).é   éd   © )r   r	   r
   Ú	eff_entryÚeff_exits        úh/Users/jameslopez/projects/TradingBot25/.worktrees/mlp-comparable-measurement/tools/compare_tv_trades.pyÚnet_pnl_pctr   L   s7   € ð
 ˜A Ñ/Ñ0€IØ˜1˜Ñ.Ñ/€HØ�yÑ  IÑ-°Ñ3Ð3ó    é   ©Úhoursé   é   é   r   )Údays)Ú4HÚ6HÚ8HÚ12HÚ1Dr   r   r   r   )Ú240Ú360Ú480Ú720Ú	data_pathc                 óD  — t        | «      j                  j                  «       }t        D ].  }|j	                  d|› �«      s|j	                  d|› �«      sŒ,|c S  t
        j                  «       D ]  \  }}|j	                  d|› �«      sŒ|c S  |j	                  d«      ryy)z¼Infer 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ßˆØ�=‰=˜1˜R˜D˜Ô" d§m¡m°a¸°t°HÕ&=ØŠIð ô #×(Ñ(Ö*‰ˆˆbØ�=‰=˜2˜d˜V˜Õ%ØŠIð +ð ‡}�}�VÔØØr   Útf_strc                 óV   — t         j                  | t        j                  d¬«      «      S )Nr   r   )r,   ÚgetÚpdÚ	Timedelta)r4   s    r   Ú	tf_offsetr9   x   s   € Ü×Ñ˜F¤B§L¡L°qÔ$9Ó:Ð:r   Úpathc                 óf  ‡ ‡— t        j                  ‰ d¬«      Š‰j                  j                  j	                  «       ‰_        dt        dt        fˆˆ fd„} |ddd«      } |d	«      } |d
dd«      } |dd«      } |ddd«      }t        ˆfd„dD «       d«      }i }‰j                  «       D ]n  \  }	}
	 t        |
|   «      }t        |
j                  |d«      «      j	                  «       j                  «       }||vri ||<   d|v r	|
||   d<   Œbd|v sŒg|
||   d<   Œp g }t        |«      D ]Þ  }||   }d|vsd|vrŒ|d   }|d   }	 t        j                  t        ||   «      «      }t        j                  t        ||   «      «      }t        ||   «      }t        ||   «      }t        ||   «      }|r)t        |j                  |d«      «      j	                  «       nd}|j!                  |||||||d|j                  «       v dœ«       Œà |S # t        t        f$ r Y �Œsw xY w# t        $ r Y �Œw xY w)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©ÚencodingÚnamesr   c                  óv   •— | D ]  }|‰j                   v sŒ|c S  t        d‰› ddj                  | «      › �«      ‚)Nz%None of these columns are present in ú: r)   )ÚcolumnsÚKeyErrorÚjoin)r?   r0   Údfr:   s     €€r   Úcolzload_tv_trades.<locals>.col‹   sD   ø€ ÛˆDØ�r—z‘zÒ!Ø’ð ô Ð>¸t¸fÀBÀtÇyÁyÐQVÓGWÐFXÐ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   ó@   •K  — | ]  }|‰j                   v sŒ|–— Œ y ­w©N©rB   )Ú.0r0   rE   s     €r   Ú	<genexpr>z!load_tv_trades.<locals>.<genexpr>–   s   øè ø€ ÐRÑ(; ¸tÀrÇzÁzÒ?Q”tÑ(;ùs   ƒ—)ÚSignalÚOrderNÚ ÚentryÚexitÚmargin)Ú	trade_numÚentry_dtÚexit_dtÚentry_priceÚ
exit_pricer   Úexit_signalÚ	is_margin)r7   Úread_csvrB   ÚstrÚstripÚnextÚiterrowsÚintÚ
ValueErrorrC   r6   ÚlowerÚsortedÚ	TimestampÚfloatÚ	ExceptionÚappend)r:   rF   Ú	trade_colÚtype_colÚtime_colÚ	price_colÚpnl_colÚ
signal_colÚrawr(   ÚrowÚnumÚt_typeÚtradesÚtÚe_rowÚx_rowrV   rW   r   r	   Úpnl_pctÚsignalrE   s   `                      @r   Úload_tv_tradesry   ~   sV  ù€ ô 
�‰�T KÔ	0€BØ—‘—‘×%Ñ%Ó'€B„Jð[”Cð [œCö [ñ �I˜~¨~Ó>€IÙ�6‹{€HÙ�? K°Ó8€HÙ�K Ó)€IÙ�+˜{¨NÓ;€GÜÓRÑ(;ÓRÐTXÓY€Jà€CØ—+‘+–-‰ˆˆ3ð	Ü�c˜)‘nÓ%ˆCô �S—W‘W˜X rÓ*Ó+×1Ñ1Ó3×9Ñ9Ó;ˆØ�c‰>ØˆC�‰HØ�fÑØ #ˆC�‰H�WÒØ�vÒØ"ˆC�‰H�VÒð  ð €FÜ�cŽ{ˆØ�‰HˆØ˜!Ñ˜v¨Q™ØØ�'‘
ˆØ�&‘	ˆð	ÜŸ™¤S¨¨x©Ó%9Ó:ˆHÜŸ™¤S¨¨x©Ó%9Ó:ˆGÜ˜e IÑ.Ó/ˆHÜ˜e IÑ.Ó/ˆGÜ˜e G™nÓ-ˆGÙBLœ˜EŸI™I j°"Ó5Ó6×<Ñ<Ô>ÐRTˆFð 	�‰ØØ$Ø#Ø$Ø#Ø#Ø"Ø$¨¯©«Ð6ñ	
õ 		ð ð2 €MøôI œHÐ%ò 	Úð	ûô0 ò 	Úð	ús%   Â3HÅBH#ÈH ÈH È#	H0È/H0Ústrategy_filec                 óN   — t        | «      j                  }|j                  d«      S )z¯Return winner-file stem for a strategy filename.

    Examples:
      strategy_activation_scores.py -> activation_scores
      strategy_mlp_scores.py        -> mlp_scores
    Ú	strategy_)r   r*   Úremoveprefix)rz   r*   s     r   Ústrategy_stemr~   Å   s%   € ô �Ó×#Ñ#€DØ×Ñ˜[Ó)Ð)r   Úparams_pathc                 ó‚  — | rt         j                  j                  | «      si S | j                  d«      r]t	        j
                  | «      j                  d   j                  «       }h d£}|j                  «       D ��ci c]  \  }}||vsŒ||“Œ c}}S | j                  d«      rŠt        | «      5 }t        j                  |«      }d d d «       i }j                  «       D ]J  \  }}t        |t        «      r0d|v r|j                  dd g«      d   n|j                  dd«      ||<   ŒF|||<   ŒL |S i S c c}}w # 1 sw Y   ŒrxY w)Nú.csvr   >   ú% In MarketúTotal P&L %úCalmar RatioúP&L/DD RatioúSharpe RatioúTotal TradesúSortino RatioúMax Drawdown %ÚverifiedÚ	CPU_ScoreÚ	CompositeÚ	GPU_ScoreÚ_pnl_dd_percentilez.jsonÚvaluesÚstart)Úosr:   Úexistsr-   r7   r\   ÚilocÚto_dictr/   ÚopenÚjsonÚloadÚ
isinstanceÚdictr6   )r   rp   ÚdropÚkÚvÚfro   Úflats           r   Úload_paramsrŸ   Ð   s  € ÙœbŸg™gŸn™n¨[Ô9Øˆ	Ø×Ñ˜FÔ#Ü�k‰k˜+Ó&×+Ñ+¨AÑ.×6Ñ6Ó8ˆòYˆð "%§¡¤Ô>¡™˜˜A°¸²��1‘ Ò>Ð>Ø×Ñ˜GÔ$Ü�+Ô !Ü—)‘)˜A“,ˆC÷ ð ˆØ—I‘I–K‰DˆAˆqÜ˜!œTÔ"Ø8@ÀA¹˜!Ÿ%™% ¨4¨&Ó1°!Ò4È1Ï5É5ÐQXÐZ[ÓK\��Q’à��Q’ð	  ð
 ˆØ€Iùó ?çÐús   Á<D/Â	D/Â.D5Ä5D>Úparamsc                 ó.  — t        |«      }|j                  «       s7t        t        «      j                  «       j                  j                  dz  |z  }|j                  «       st        d|› �«      ‚t        j                  j                  d|«      }t        j                  j                  |«      }|t        j                  d<   |j                  j                  |«       t        j                   | «      }|j"                  j$                  j'                  «       j$                  j)                  «       |_        t        j*                  |d   d¬«      j,                  j/                  d«      |d<    |j0                  |fi |¤Ž}t3        |«      |j4                  d<   |S )	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_moduler7   r\   rB   r]   rc   r^   Úto_datetimeÚdtÚtz_localizeÚgenerate_signalsr~   Úattrs)r%   r    rz   Ústrategy_pathÚspecÚmodrE   Úsignalss           r   Úrun_python_strategyr¼   è   s=  € ô ˜Ó'€MØ×$Ñ$Ô&ÜœX›×.Ñ.Ó0×7Ñ7×>Ñ>ÀÑMÐP]Ñ]ˆØ×ÑÔ!ÜÐ";¸M¸?Ð KÓLÐLä�>‰>×1Ñ1Ð2CÀ]ÓS€DÜ
�.‰.×
)Ñ
)¨$Ó
/€CØ%(„C‡K�KÐ!Ñ"Ø‡K�K×Ñ˜CÔ ä	�‰�YÓ	€BØ—‘—‘×%Ñ%Ó'×+Ñ+×1Ñ1Ó3€B„JÜ—‘  6¡
°Ô5×8Ñ8×DÑDÀTÓJ€B€v�Jð #ˆc×"Ñ" 2Ñ0¨Ñ0€GÜ%2°=Ó%A€G‡M�M�/Ñ"Ø€Nr   r»   c                 ó�   — | j                   j                  d«      }|dk(  rd}n
|dk(  rd}nd}|D ]  }|| j                  v sŒ|c S  y)zCReturn the TV-exported score column present in a signal/data frame.r~   Ú
mlp_scores)Ú	mlp_scoreÚmlp_score_pocÚactivation_scores)Úactivation_score_pocÚactivation_scores_poc)rÂ   rÃ   r¿   rÀ   N)r·   r6   rB   )r»   ÚstrategyÚ
candidatesrF   s       r   Útv_score_columnrÆ     sX   € à�}‰}× Ñ  Ó1€HØ�<ÒØ3‰
Ø	Ð(Ò	(ØF‰
ð4ˆ
ãˆØ�'—/‘/Ò!ØŠJð ð r   rp   c                 óh   — t        |«      }|€t        d«      S | j                  |t        d«      «      S )NÚnan)rÆ   rf   r6   )rp   r»   rF   s      r   Útv_score_valuerÉ     s0   € Ü
˜'Ó
"€CØ
€{Ü�U‹|ÐØ�7‰7�3œ˜e›Ó%Ð%r   c                 óx   — t        | t        «      r | j                  «       j                  «       dv S t	        | «      S )N>   Ú1ÚyÚonÚyesÚtrue)r˜   r]   r^   rc   Úbool)Úvalues    r   Ú_param_boolrÒ     s1   € Ü�%œÔØ�{‰{‹}×"Ñ"Ó$Ð(GÐGÐGÜ�‹;Ðr   ÚentriesÚexitsÚ	close_arrÚhigh_arrÚtrail_stop_pctc                 óº  — t        | «      }t        j                  |t        j                  ¬«      }t        j                  |t        ¬«      }t        j                  |t        ¬«      }d}	d}
d}t        |«      D ]]  }|	r:d}|dkD  r ||k7  r||   |
kD  r||   }
||   |
d|z
  z  k  }||   s|r"d}	d||<   d}
d}n| |   rd}	d||<   ||   }
|dz   }|	rdnd||<   Œ_ |||fS )	z6Replay Pine's flat/long lifecycle from raw conditions.©ÚdtypeFç        éÿÿÿÿç      ð?Tr   r   )ÚlenÚnpÚ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Ü�X‰X�aœrŸx™xÔ(€FÜ—‘˜!¤4Ô(€JÜ—‘˜¤$Ô'€Ià€HØ€JØ€Hä�1ŽXˆÙØˆIØ Ò#Ø˜’= X¨a¡[°:Ò%=Ø!)¨!¡�JØ% a™L¨J¸#ÀÑ:NÑ,OÑO�	à�QŠx™9Ø �Ø#�	˜!‘Ø �
Ø‘à�qŠzØ�Ø $�
˜1‘Ø& q™\�
Ø˜q™5�Ù!‘A qˆˆqŠ	ð' ð* �:˜yÐ(Ð(r   r�   Úendc           	      óN	  — h d£}|j                  | j                  «      s| S | j                  «       }| j                  j	                  d«      dk(  �rddlm} t        |«      }||d<   ||d<   t        j                  |j	                  dt        j                  d	|j                  ¬
«      «      d¬«      j                  d	«      j                  t        j                  ¬«      } |||||d   j                  t        j                  ¬«      |d   j                  t        j                  ¬«      «      }	|	j                  j!                  | j                  «       |	S |d   }
t#        |j	                  dd«      «      }t#        |j	                  dd«      «      }t#        |j	                  dd«      «      }t%        |j	                  dd«      «      }t%        |j	                  dd«      «      }|r0|
j'                  d«      |k\  |
j'                  d«      |k  z  |
|k  z  }nrt        j                  d|j                  ¬
«      }d|j                  v r|d   j                  d	«      d	k7  }|
j'                  d«      |k\  |
j'                  d«      |k  z  |z  }|rT|
j'                  d«      |k\  |
j'                  d«      |k  z  |
|
j'                  d«      kD  z  |j'                  dd¬«       z  }n|
j'                  d«      |k\  |
|k  z  }t)        |j	                  dd«      «      }t#        |j	                  dd «      «      }|dkD  r%|
j+                  |d¬!«      j-                  «       |kD  }n!t        j                  d|j                  ¬
«      }t%        |j	                  d"d«      «      rd#|j                  v r||d#   dk\  z  }t        j.                  |d$   «      }||k\  }|�|||k  z  }||z  |z  j                  d«      j                  t0        ¬«      }||z  j                  d«      j                  t0        ¬«      }t#        |j	                  d%d	«      «      d&z  }t3        |||d   j                  t        j                  ¬«      |d   j                  t        j                  ¬«      |«      \  }}}||d'<   ||d(<   ||d)<   |S )*ai  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.
    >   Úhighr¤   ÚcloseÚactivation_scorer~   r¾   r   )Ú_score_to_signalsÚ_pine_time_startÚ_pine_time_endÚstoch_peak_normrÛ   ©ÚindexÚcoerce©ÚerrorsrÙ   rð   rï   rñ   Ú!i_long_entry_activation_thresholdç     €Z@Ú i_long_exit_activation_thresholdç     �a@Ú-i_long_exit_activation_confirmation_thresholdgÍÌÌÌÌ4@@Úi_use_long_exit_confirmationTÚi_use_long_entry_confirmationFé   r   )Ú
fill_valueÚi_regime_windowÚi_regime_entry_min_scoreg     @�À)ÚwindowÚmin_periodsÚi_mvrv_suppress_bearÚmvrv_regimer¤   Úi_trailing_stop_thresholdg      Y@rç   Úexecute_entryÚexecute_exit)ÚissubsetrB   Úcopyr·   r6   Ústrategies.strategy_mlp_scoresrò   r™   r7   Ú
to_numericÚSeriesr÷   ÚfillnaÚto_numpyrß   Úfloat64Úupdaterf   rÒ   Úshiftra   ÚrollingÚmeanr³   rÐ   rì   )r»   r    r�   rí   ÚrequiredrE   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  sX  € ò =€HØ×Ñ˜WŸ_™_Ô-Øˆà	�‰‹€BØ‡}�}×Ñ˜Ó)¨\Ó9ÝDä˜V›ˆØ,1ˆÐ(Ñ)Ø*-ˆÐ&Ñ'Ü—]‘]Ø�F‰FÐ$¤b§i¡i°¸2¿8¹8Ô&DÓEØô
÷ ‰&�‹+—h‘h¤R§Z¡Z�hÓ0ð 	ñ %ØØØØˆw‰K× Ñ ¤r§z¡zÐ Ó2Øˆv‰J×Ñ¤b§j¡jÐÓ1ó
ˆð 	�‰×Ñ˜gŸm™mÔ,ØˆàÐ!Ñ"€EÜ˜FŸJ™JÐ'JÈEÓRÓS€OÜ˜6Ÿ:™:Ð&HÈ%ÓPÓQ€NÜ §
¡
Ð+ZÐ\cÓ dÓeÐÜ §
¡
Ð+IÈ4Ó PÓQ€MÜ  §¡Ð,KÈUÓ!SÓT€Náà�[‰[˜‹^˜~Ñ-Ø�[‰[˜‹^˜nÑ,ñ.àÐ(Ñ(ñ*ñ 	ô —Y‘Y˜u¨B¯H©HÔ5ˆ
Ø §
¡
Ñ*ØÐ-Ñ.×5Ñ5°cÓ:¸cÑAˆJà�[‰[˜‹^˜~Ñ-Ø�[‰[˜‹^˜nÑ,ñ.àñð 	ñ à�[‰[˜‹^˜Ñ.Ø�[‰[˜‹^˜oÑ-ñ/à�U—[‘[ “^Ñ#ñ%ð �^‰^˜A¨%ˆ^Ó0Ð0ñ1ñ 	ð —[‘[ “^ Ñ6¸5À?Ñ;RÑSˆ	ä˜Ÿ
™
Ð#4°aÓ8Ó9€MÜ�v—z‘zÐ"<¸gÓFÓG€JØ�qÒØ—M‘M¨ÀA�MÓF×KÑKÓMÐPZÑZ‰	ä—I‘I˜d¨"¯(©(Ô3ˆ	ä�6—:‘:Ð4°eÓ<Ô=À-ÐSU×S]ÑS]ÑB]Ø  MÑ!2°aÑ!7Ñ8ˆ	ä�>‰>˜"˜V™*Ó%€DØ�e‰m€GØ
€Ø˜T S™[Ñ)ˆà˜YÑ&¨Ñ0×8Ñ8¸Ó?×HÑHÌtÐHÓT€IØ˜7Ñ"×*Ñ*¨5Ó1×:Ñ:ÄÐ:ÓF€HÜ˜6Ÿ:™:Ð&AÀ3ÓGÓHÈ5ÑP€Nä$5ØØØ
ˆ7‰×Ñ¤2§:¡:ÐÓ.Ø
ˆ6‰
×Ñ¤"§*¡*ÐÓ-Øó%Ñ!€FˆJ˜	ð €B€z�NØ$€B€ÑØ"€B€~ÑØ€Ir   c                 ó
  — g }d}dx}x}}| j                  «       D ]e  \  }}|s|d   rd}|d   }|d   }|}Œ|sŒ|d   sŒ%d}|d   }|d   }	|	|z
  |z  dz  }
|j                  ||||	t        ||	«      |
||d	œ«       dx}x}}Œg |S )
z4Walk signals DataFrame and extract entry/exit pairs.FNr  Tr¤   rð   r  r   )rV   rW   rX   rY   rw   Úgross_pnl_pctÚ	entry_idxÚexit_idx)r`   rh   r   )r»   rs   rä   rV   r   r,  Úidxrp   rW   r	   Ú	gross_pnls              r   Úextract_python_tradesr0  °  s×   € à€FØ€FØ&*Ð*€HÐ*ˆx˜)à×$Ñ$Ö&‰ˆˆSÙ˜#˜oÒ.ØˆFØ˜F™ˆHØ˜G™ˆHØ‰IÚ˜˜NÓ+ØˆFØ˜6‘{ˆGØ˜7‘|ˆGØ  8Ñ+¨xÑ7¸#Ñ=ˆIØ�M‰MØ!)Ø!(Ø!)Ø!(ô "-¨X°wÓ!?Ø!*Ø!*Ø!$ñô ð /3Ð2ˆHÐ2�x¡)ð/ 'ð0 €Mr   Ú	tv_tradesÚ	py_tradesÚtolerance_barsc                 ó®  — t        |«      }||z  }| D �cg c]
  }|d   rŒ	|‘Œ }}t        |«      }t        |«      }	g }
|D ]Š  }d}|t        j                  d¬«      z   }|D ]+  }|d   |z
  }t	        |d   |z
  «      }||k  sŒ"||k  sŒ(|}|}Œ- |€ŒQ|
j                  ||f«       |j                  |«       ||	v sŒz|	j                  |«       ŒŒ |
|	|fS c c}w )a�  
    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
    r[   Nr   )ÚsecondsrV   )r9   Úlistr7   r8   Úabsrh   Úremove)r1  r2  r4   r3  ÚoffsetÚ	tolerancert   Útv_realÚavailable_tvÚunmatched_pyÚmatchedÚpyÚbestÚbest_errÚtvÚtv_adjÚerrs                    r   Úmatch_tradesrE  Ó  sþ   € ô" ˜&Ó!€FØ˜Ñ'€Iá#Ó:™)�Q¨1¨[«>Šq˜)€GÐ:Ü˜“=€LÜ˜	“?€LØ€GãˆØˆØœrŸ|™|°AÔ6Ñ6ˆÛˆBà˜
‘^ fÑ,ˆFÜ�b˜‘n vÑ-Ó.ˆCØ�iÓ C¨(£NØ�Ø‘ð ð ÑØ�N‰N˜B ˜:Ô&Ø×Ñ Ô%Ø�\Ò!Ø×#Ñ# BÕ'ð ð  �L ,Ð.Ð.ùò+ ;s
   •
C CrB   c                 óú   — g }|D ]N  }|| j                   vrŒt        j                  | |   d¬«      j                  d«      dk7  }|j	                  |«       ŒP |sy|d   j                  «       }|dd D ]  }||z  }Œ	 |S )zHReturn truthy marker mask for any available exported Data Window column.rø   rù   rÛ   Nr   r   )rB   r7   r  r  rh   r  )r»   rB   ÚmasksrF   ÚmarkerÚoutÚmasks          r   Ú_marker_maskrK    s…   € à€EÛˆØ�g—o‘oÑ%ØÜ—‘˜w s™|°HÔ=×DÑDÀSÓIÈSÑPˆØ�‰�VÕð	 ñ
 ØØ
�‰(�-‰-‹/€CØ�a�b“	ˆØ�D‰j‰ð à€Jr   c                 ó:  — t        |dd«      }|�d|j                  vryt        |d«      }|€!t        j                  d|j                  ¬«      }| D �cg c]
  }|d   rŒ	|‘Œ }}t        |«      }	t        j                  |d   «      }
t        |j                  |
«      D ��ci c]  \  }}||“Œ
 }}}g }t        «       }|D ]p  }|d	   |	z
  }|j                  |«       |j                  |«      }|€|j                  ||d
f«       ŒDt        |j                  |   «      rŒ]|j                  ||df«       Œr || z  |
|k\  z  }|�||
|k  z  }t        |
|   «      }t        ||z
  «      }dt        |«      t        |«      t        |«      z
  |t        |«      |dœS c c}w c c}}w )a1  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ö   r[   rV   z#no chart bar at adjusted entry timez.no exported Entry marker on adjusted entry barT)Ú	availableÚtv_countÚtv_with_markerÚtv_without_markerÚchart_exec_countÚchart_without_tv)rK  rB   r7   r  r÷   r9   r³   ÚzipÚsetÚaddr6   rh   rÐ   Úlocrd   rÞ   )r1  r»   r4   r�   rí   Úentry_markerÚmissed_entryrt   Úreal_tvr9  Úsignal_timesr.  ÚtsÚtime_to_idxrP  Útv_signal_timesrB  Ú	signal_dtÚ
chart_execÚchart_exec_timesrR  s                        r   Úcheck_tv_entry_markersra    sÁ  € ô   Ð);Ð=PÓQ€LØÐ˜v¨W¯_©_Ñ<Øä ¨Ó8€LØÐÜ—y‘y ¨g¯m©mÔ<ˆá#Ó:™)�Q¨1¨[«>Šq˜)€GÐ:Ü�vÓ€FÜ—>‘> '¨&¡/Ó2€LÜ*-¨g¯m©m¸\Ô*JÔKÑ*J™w˜s B�2�s‘7Ð*J€KÑKàÐÜ“e€OÛˆØ�z‘N VÑ+ˆ	Ø×Ñ˜IÔ&Ø�o‰o˜iÓ(ˆØˆ;Ø×$Ñ$ b¨)Ð5ZÐ%[Õ\Ü�l×&Ñ& sÑ+Õ,Ø×$Ñ$ b¨)Ð5eÐ%fÕgð ð   Ñ-°ÀÑ1FÑG€JØ
€Ø <°3Ñ#6Ñ7ˆ
Ü˜<¨
Ñ3Ó4ÐÜÐ.°Ñ@ÓAÐð Ü˜“LÜ˜g›,¬Ð->Ó)?Ñ?Ø.ÜÐ 0Ó1Ø,ñð ùò- ;ùó Ls   Á
FÁFÂFÚbar_idxÚcontextc                 ó¸  — t        d||z
  «      }t        t        | «      dz
  ||z   «      }| j                  ||dz    }t	        | «      }|xs d}ddd›ddd›dd	d
›d|d›ddd›ddd›�g}|j                  d«       t        |j                  «       «      D ]µ  \  }	\  }
}|
|k(  rdnd}t        || «      }t        j                  |«      s|d›nd}d| j                  v r|d   d›nd}|j                  dd«      rdnd}|j                  dd«      rdnd}|j                  d|
d›dt        |d   «      dd d›d|d
›d|d›d|d›d|d›|› �«       Œ· dj                  |«      S )z;Return a compact table of activation scores around bar_idx.r   r   Útv_scoreú  Úbarú>4r¤   z>19r  z>9z>12rR   z>5rS   zF  --------------------------------------------------------------------z <<<rQ   z.2fz   n/arñ   r  FÚEÚ.r  ÚXNé   Ú
)ÚmaxÚminrÞ   r“   rÆ   rh   Ú	enumerater`   rÉ   rß   ÚisnanrB   r6   r]   rD   )r»   rb  rc  ÚloÚhiÚrowsÚtv_colÚtv_labelÚlinesrê   Úridxrp   rH  re  Ú
tv_score_sÚscore_vÚentry_fÚexit_fs                     r   Úscore_contextr}  H  s£  € ä	ˆQ�˜'Ñ!Ó	"€BÜ	ŒS�‹\˜AÑ˜w¨Ñ0Ó	1€BØ�<‰<˜˜2 ™6Ð"€DÜ˜WÓ%€FØÒ#˜€Hà�%˜�˜2˜f S˜\¨¨G°B¨<°r¸(À3¸ÀrÈ'ÐRTÈÐUWÐX^Ð_aÐWbÐcÐd€EØ	‡L�L�Ô!Ü# D§M¡M£OÖ4‰ˆ‰;ˆD�#Ø 7š?‘°ˆÜ! # wÓ/ˆÜ.0¯h©h°xÔ.@˜ ‘~Àhˆ
Ø6HÈGÏOÉOÑ6[�SÐ+Ñ,¨SÑ1ÐaiˆØŸ™ °%Ô8‘#¸cˆØŸ™ °%Ô8‘#¸cˆØ�‰Ø��b�	˜œC  F¡Ó,¨S¨bÐ1°#Ð6°b¸À¸ÀBÀzÐRUÐFVÐVXÐY`ÐacÐXdÐdfÐgmÐnpÐfqÐrxÐqyÐzõ	
ð 5ð �9‰9�UÓÐr   Útv_trader  c           	      óž  — t        |«      }| d   |z
  }|dz  }|d   ||z
  k\  |d   ||z   k  z  }||   }|j                  ry|j                  |d   j                  |«      j	                  «       j                  «          }	|j                  |	   }
|
j                  dt        d«      «      }|	dkD  r|j                  |	dz
  df   n
t        d«      }t        |
|«      }t        j                  |«      st	        ||z
  «      n
t        d«      }t        j                  |«       xr ||k\  xr ||k  }g }|r|j                  d	«       nE|j                  d
|d›d|d›d|› d�«       ||k\  r|j                  d«       n|j                  d«       t        j                  |«      s#|dkD  r|j                  d|d›d|d›d|d›d�«       dj                  |«      S )zv
    Try to explain why Python missed a TV entry.
    Looks for the Python bar corresponding to TV entry - 1 bar.
    rV   r  r¤   z'UNKNOWN (no matching bar found in data)rñ   rÈ   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ú | )r9   Úemptyr÷   Úsubr7  ÚargminrV  r6   rf   rÉ   rß   rq  rh   rD   )r~  r»   r  r4   r9  Úpy_signal_timeÚtolrJ  Únearr.  rp   Ú	score_nowÚ
score_prevÚtv_score_nowÚ
score_diffÚcrossunder_pyÚpartss                    r   Úclassify_tv_onlyr�  _  së  € ô �vÓ€FØ˜jÑ)¨FÑ2€NØ
�1‰*€Cà�F‰O˜~°Ñ3Ñ3¸À¹È>Ð\_ÑK_Ñ8_Ñ`€DØ�4‰=€DØ‡z‚zØ8à
�*‰*�T˜&‘\×%Ñ% nÓ5×9Ñ9Ó;×BÑBÓDÑ
E€CØ
�+‰+�cÑ
€CØ—‘Ð+¬U°5«\Ó:€IØ=@À1ºW�—‘˜S 1™WÐ&8Ð8Ò9Ì%ÐPUË,€Jä! # wÓ/€LÜ79·x±xÀÔ7M”#�i ,Ñ.Ô/ÔSXÐY^ÓS_€JäŸ™ *Ó-Ð-Òt°JÀ/Ñ4QÒtÐXaÐdsÑXs€Mà€EÙØ�‰ÐPÕQà�‰Ð3°I¸c°?À'È*ÐUXÐIYÐYeÐfuÐevÐvwÐxÔyØ˜Ò'Ø�L‰LÐ[Õ\à�L‰LÐ_Ô`ä�8‰8�JÔ J°¢NØ�‰Ð)¨,°sÐ);Ð;LÈYÐWZÈOÐ[`ÐakÐloÐ`pð  qAð  Bô  	Cà�:‰:�eÓÐr   Úpy_trader"  c           
      ó†  — | d   }d|j                   v }t        |«      }|du}g }|�r‡|dk\  �r�|r|j                  |dz
  df   n
t        d«      }	|r|j                  |dz
  df   n
t        d«      }
|r|j                  |dz
  |f   n
t        d«      }|r|j                  |dz
  |f   n
t        d«      }t	        j
                  |	«      sDt	        j
                  |
«      s/|	|k\  xr |
|k  }|j                  d|	d›d	|
d›d
|› d|rdnd› �«       t	        j
                  |«      �st	        j
                  |«      �sø||k\  xr ||k  }|j                  d|d›d	|d›d|rdnd› �«       t	        j
                  |
«      �s¶t        |
|z
  «      dkD  �r¤|j                  dt        |
|z
  «      d›d�«       �n€|r|j                  |df   n
t        d«      }|dkD  r|r|j                  |dz
  df   n
t        d«      }|r|j                  ||f   n
t        d«      }t	        j
                  |«      sDt	        j
                  |«      s/||k\  xr ||k  }|j                  d|d›d	|d›d
|› d|rdnd› �«       t	        j
                  |«      s°|dkD  r|j                  |dz
  |f   n
t        d«      }t	        j
                  |«       xr ||k\  xr ||k  }|j                  d|d›d	|d›d|rdnd› �«       t	        j
                  |«      s3t        ||z
  «      dkD  r"|j                  dt        ||z
  «      d›d�«       |sydj                  |«      S )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  rÈ   r   u   Python crossunder (t-2â†’t-1): r€  õ    â†’ z (threshold z): ÚYESzno crossunder?u   TV exported score (t-2â†’t-1): rA   zYES (TV should also fire)zNO (TV rightly quiet)r‚  zScore delta at crossunder bar: u    â†’ SCORE_DIFFr   zPython crossunder: zTV exported score crossunder: zScore delta: ÚUNKNOWNrƒ  )	rB   rÆ   rV  rf   rß   rq  rh   r7  rD   )r‘  r»   r  r"  r.  Ú	has_scoreru  Úhas_tv_scorer�  ÚxprevÚxcurrÚxprev_tvÚxcurr_tvÚ
crossunderÚtv_xurŠ  r‹  re  Útv_prevs                      r   Úclassify_py_onlyrŸ  ˆ  si  € ð �;Ñ
€CØ" g§o¡oÐ5€IÜ˜WÓ%€FØ Ð%€Là€Eâ˜# ›(á<E�—‘˜C !™GÐ%7Ð7Ò8Ì5ÐQVË<ˆÙ<E�—‘˜C !™GÐ%7Ð7Ò8Ì5ÐQVË<ˆÙ3?�7—;‘;˜s Q™w¨˜Ò/ÄUÈ5Ã\ˆÙ3?�7—;‘;˜s Q™w¨˜Ò/ÄUÈ5Ã\ˆä—‘˜”¤2§8¡8¨E¤?Ø ?Ñ2ÒQ¸ÀÑ9PˆJØ�L‰LØ1°%¸°¸EÀ%ÈÀØ˜Ð/¨s¹J±5ÐL\Ð2]ð_ôô —‘˜Õ"¤b§h¡h¨xÕ&8Ø Ñ0ÒR°xÀ/Ñ7QˆEØ�L‰LØ1°(¸3°¸uÀXÈcÀNð SÙ38Ñ/Ð>UÐVðXôô —8‘8˜E•?¤s¨5°8Ñ+;Ó'<¸qÓ'@Ø—‘Ð>¼sÀ5È8ÑCSÓ?TÐUXÐ>YÐYhÐiÖjñ >G�W—[‘[ Ð&8Ð!8Ò9ÌEÐRWËLˆ	ØADÀqÂÉY�W—[‘[  q¡Ð*<Ð!<Ò=Ô\aÐbgÓ\hˆ
Ù1=�W—[‘[  f Ò-Ä5ÈÃ<ˆä—‘˜Ô$¬¯©°Ô(;Ø$¨Ñ7ÒZ¸iÈ/Ñ>YˆJØ�L‰LØ% j°Ð%5°U¸9ÀS¸/Ø˜Ð/¨s¹J±5ÐL\Ð2]ð_ôô �x‰x˜Ô!Ø69¸A²g�g—k‘k #¨¡'¨6 /Ò2Ä5ÈÃ<ˆGÜŸ™ 'Ó*Ð*Òm°¸OÑ1KÒmÐRZÐ]lÑRlˆEØ�L‰LØ0°¸°¸UÀ8ÈCÀ.ð QÙ38Ñ/Ð>UÐVðXôô —8‘8˜IÔ&¬3¨y¸8Ñ/CÓ+DÀqÒ+HØ—‘˜}¬S°¸XÑ1EÓ-FÀsÐ,KÈ?Ð[Ô\áØØ�:‰:�eÓÐr   r  c                 ó<  — | d   }|d   }||z
  j                  «       dz  }d|j                  «       › d|j                  «       › d|d›d�g}|j                  d| d	   d
›d|d   d
›d�«       | d   }	|	t        |«      k  r|j                  |	   nd}
|
�d|j
                  v r|
d   nd}d}|�I|	dk\  rDd|j
                  v r6|j                  |	dz
     d   }|j                  |	dz
     d   }||k\  r||k  rd}|r(|j                  d|d›d�«       |j                  d«       np|dkD  r?|j                  d|d›d�«       |�|j                  d|d›�«       |j                  d«       n,|j                  d|› �«       |�|j                  d|d›d�«       d j                  |«      S )!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.
    rW   é  zPython exit z / TV exit u    (Î” z+.0fúh)zPython P&L rw   ú+.1fz% / TV P&L r   Ú%r-  Nrñ   Fr  r   TzPython exit bar score: r€  u    â†’ SCORE_CROSSUNDER_MISMATCHz–TV and Python exited on different score-crossunder events. If score parity passes, this is usually downstream of an earlier lifecycle/export mismatch.r   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Údaterh   rÞ   r“   rB   rD   )r‘  r~  r»   r×   r  Úpy_exitÚtv_exitÚdiffr�  r-  Úexit_rowr  Úis_score_crossunderÚprev1Úprev2s                  r   Úclassify_exit_mismatchr¯  Æ  sú  € ð �yÑ!€GØ�yÑ!€GØ˜Ñ ×/Ñ/Ó1°DÑ8€Dà˜GŸL™L›NÐ+¨;°w·|±|³~Ð6FÀeÈDÐQUÈ;ÐVXÐYÐZ€EØ	‡L�L�;˜x¨	Ñ2°4Ð8¸ÀHÈ]ÑD[Ð\`ÐCaÐabÐcÔdà˜
Ñ#€HØ)1´C¸³LÒ)@ˆw�|‰|˜HÒ%Àd€Hà-5Ð-AÐFXÐ\c×\kÑ\kÑFkˆHÐ'Ò(Ðrv€Eð
  ÐØÐ˜X¨š]Ð/AÀWÇ_Á_Ñ/TØ—‘˜X¨™\Ñ*Ð+=Ñ>ˆØ—‘˜X¨™\Ñ*Ð+=Ñ>ˆØ�NÒ" u¨~Ò'=Ø"&ÐáØ�‰Ð.¨u°S¨kÐ9WÐXÔYØ�‰ðjõ	
ð 
˜!Ò	Ø�‰�~ n°SÐ%9Ð9SÐTÔUØÐØ�L‰LÐ2°5¸°+Ð>Ô?Ø�‰ð7õ	
ð
 	�‰Ð8¸Ð8HÐIÔJØÐØ�L‰LÐ2°5¸°+¸^ÐLÔMà�:‰:�eÓÐr   c                  óÄ"  ‡P— t        j                  dt         j                  t        ¬«      } | j	                  ddd¬«       | j	                  ddd¬«       | j	                  d	d d
¬«       | j	                  ddd¬«       | j	                  dd d¬«       | j	                  dt
        dd¬«       | j	                  ddd¬«       | j	                  dt
        dd¬«       | j	                  ddd¬«       | j                  «       }|j                  xs t        |j                  «      }|€t        d«       t        d«       d }t        d!|› d"t        |«      › d#�«       	 d$d%lm}  ||j                  «      \  }}}|r+t        d&«       |D ]  }t        d'|› �«       Œ t        d(«       |j                  }|€¢t!        |j                  «      j"                  }	|	j%                  d)d*«      j'                  «       }
t)        |j*                  «      }t!        d+«      d,|› d*|
› d-�z  }|j-                  «       rt/        |«      }t        d.|› �«       nt        d/|› d0�«       t        d1|j0                  › �«       t3        |j0                  «      }|D �cg c]
  }|d2   rŒ	|‘Œ }}|D �cg c]
  }|d2   sŒ	|‘Œ }}t        d3t5        |«      › d4t5        |«      › d5�«       |rt7        |«      ni }t        d6|j*                  › d7|j                  › �«       t9        |j                  ||j*                  ¬8«      }t;        j<                  t>        «      }t;        j<                  t@        «      }tC        ||||¬9«      }tE        |«      }|D �cg c]  }|d:   |k\  sŒ|‘Œ }}t        d;t5        |«      › d<|jG                  «       › d=|jG                  «       › d>t5        |«      › d?�	«       tI        |jK                  d@dA«      «      }tI        |jK                  dBdC«      «      }tI        |jK                  dDdE«      «      }|jK                  dFdG«      }|jK                  dHd«      }t        dI«       t        dJ|› dK|› dL�«       t        dM|› dN|› dL�«       t        dO|› dP�«       tM        ||||jN                  «      \  }}}t        |«      |jN                  z  }g g }!} |D ]Q  \  }"}#|#dQ   t        |«      z
  }$tQ        |"dQ   |$z
  «      |k  r| jS                  |"|#f«       Œ?|!jS                  |"|#f«       ŒS |rtU        dR„ |D «       «      nt;        j<                  dS«      }%|D �&cg c]  }&|&d:   |%k  sŒ|&‘Œ }'}&|D �&cg c]  }&|&d:   |%kD  sŒ|&‘Œ }(}&tW        |||||r|%t        |«      z
  nd «      })dT}*t        dUdV|*z  › �«       t        dW«       t        dV|*z  › «       t        dXt5        |«      dY›dZ|%jG                  «       › dL�«       t        d[t5        |«      dY›�«       t        d\t5        | «      dY›d]t5        | «      tU        t5        |«      d^«      z  d_z  d`›da�«       t        dbt5        |!«      dY›�«       dct5        |'«      › dd|%jG                  «       › det5        |(«      › df�}+t        dgt5        |«      dY›|+› �«       t        dht5        |«      dY›�«       |rt        dit5        |«      dY›dj�«       t        dV|*z  › «       |)�·|)dk   },|)dl   }-|,s|-s|jX                  r�t        dm«       t        dn|)do   › dp|)dq   › �«       t        dr|)ds   › d]t5        |-«      › dt�«       |,r6t        du«       |,d dv D ]#  \  }#}.}/t        dw|#dx   › dy|.› dz|#d:   › d{|/› �«       Œ% |-r#t        d|«       |-d dv D ]  }.t        d}|.› �«       Œ d~x}0}1|D ]  }|0d^|d   d_z  z   z  }0|1d^|d€   d_z  z   z  }1Œ  |0d^z
  d_z  }2|1d^z
  d_z  }3	 t;        jZ                  |j0                  d�¬‚«      ŠP‰Pj\                  j.                  j_                  «       ‰P_.        ta        ˆPfdƒ„d„D «       d «      }4|4r ‰P|4   jc                  «       jd                  d…   n
tI        d†«      }5tf        d_z  }6t5        |«      t5        |«      k(  }7ti        |5tH        «      xr tk        jl                  |5«       xr |5}8t        «        t        d‡dˆ|6z  d‰›|2dŠ›dP�«       t        d‡d‹d‰›|5dŠ›dP�«       |8r0|7r.tQ        |2|5z
  «      tQ        |5«      z  d_z  }9t        dŒ|9d`›d��«       n&|8r$t        dŽt5        |«      › d�t5        |«      › d��«       t        d‡d‘d‰›|3dŠ›dP�«       t        «        | �rœt        dUd’|*z  › �«       t        d“t5        | «      › d”�«       t        d’|*z  › «       d‡d•d–›d‡d—d˜›d™dšd˜›d‡d›d˜›d™dœd˜›d‡d�dž›d™dŸdž›d‡d d¡›�}:t        |:«       t        d‡d)|*dz
  z  z   «       | D �]  \  }"}#|#d:   t        |«      z
  };|#dQ   t        |«      z
  }$|"d:   |;z
  jo                  «       d¢z  }<|"dQ   |$z
  jo                  «       d¢z  }=|"d   |#d£   z
  }>tQ        |=«      d^kD  rd¤|=d¥›d¦�nd§}?t        d‡|#dx   d–›d‡t/        |"d:   jG                  «       «      d˜›d™t/        |#d:   jG                  «       «      d˜›d‡t/        |"dQ   jG                  «       «      d˜›d™t/        |#dQ   jG                  «       «      d˜›d™|?d¨›d‡|"d   d©›dª|#d£   d©›d«|>d¬›dP�«       �Œ  |!r½t        dUd’|*z  › �«       t        d­t5        |!«      › d®�«       t        d’|*z  › «       |!D ]€  \  }"}#t        d¯|#dx   › d°�«       tq        |"|#|||«      }/|/js                  d±«      D ]  }@t        d²|@› �«       Œ |jt                  sŒX|"d³   €Œ^t        tw        ||"d³   |jv                  «      «       Œ‚ |'rìt        dUd’|*z  › �«       t        d´t5        |'«      › dµ�«       t        d’|*z  › «       |'D ]¯  }"ty        |"||t{        |«      ¬¶«      }/t        d·|"d:   jG                  «       › d¸|"dQ   jG                  «       › d¹|"d   dº›dP�«       |/js                  d±«      D ]  }@t        d²|@› �«       Œ |jX                  sŒ‡|"d»   €Œ�t        tw        ||"d»   |jv                  «      «       Œ± |(r‹t        dUd’|*z  › �«       t        d¼t5        |(«      › d½|%jG                  «       › d¾�«       t        d’|*z  › «       |(D ]=  }"t        d¿|"d:   jG                  «       › d¸|"dQ   jG                  «       › d¹|"d   dº›dÀ�«       Œ? |�r_t        dUd’|*z  › �«       t        dÁt5        |«      › dÂ�«       t        d’|*z  › «       |D �]!  }#t}        |#|||«      }/t        d¯|#dx   › d¿|#d:   jG                  «       › d¸|#dQ   jG                  «       › d¹|#d£   dº›dP�	«       |/js                  d±«      D ]  }@t        d²|@› �«       Œ t        |«      }A|#d:   |Az
  }B|Adz  }C|dÃ   |B|Cz
  k\  |dÃ   |B|Cz   k  z  }D||D   }E|Ej~                  rŒ¸|jX                  sŒÅEj€                  |EdÃ   jƒ                  B«      jQ                  «       j…                  «          }Ft        tw        ||F|jv                  «      «       �Œ$ |rst        dUd’|*z  › �«       t        dÄ«       t        d’|*z  › «       |D ]C  }#t        dÅ|#dx   › d¿|#d:   jG                  «       › d¸|#dQ   jG                  «       › d¹|#d£   dº›dP�	«       ŒE t        dUdV|*z  › �«       t        dÆ«       t        dV|*z  › «       d$}G|'D ]$  }"ty        |"||t{        |«      ¬¶«      }HdÇ|Hv sŒ Gd^z  }GŒ& |D ]  }#t}        |#|||«      }HdÇ|Hv sŒGd^z  }GŒ t5        |'«      t5        |«      dvz   kD  }Id$}Jd$}K|!D ]-  \  }L}Mtq        |L|M|||«      }NdÈ|Nv rJd^z  }JŒdÉNv rKd^z  }KŒ)Kd^z  }KŒ/ g }OGd$kD  r5OjS                  dÊG› dË|j                  › dÌ|› dÍ|j                  › dÎ|› dÏ�«       Ir*OjS                  dÐt5        |'«      › dÑt5        |«      › dÒ�«       |'s|r*OjS                  dÓt5        |'«      › dÔt5        |«      › dÕ�«       |)�:|)dk   s|)dl   r0OjS                  dÖt5        |)dk   «      › d×t5        |)dl   «      › dØ�«       Jd$kD  rOjS                  dÊJ› dÙ�«       Kd$kD  rOjS                  dÊK› dÚ|d¥›dÛ�«       OsOjS                  dÜ«       OD ]  }Ht        |H«       t        «        Œ t        dÝ«       t        dÞ«       t        dß«       t        dV|*z  › «       y # t        $ r Y �ŒŽw xY wc c}w c c}w c c}w c c}&w c c}&w # t        $ r tI        d†«      }5Y �	Œw xY w)àNuJ   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--paramszGWinner 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-barsr  z*Entry-match tolerance in bars (default: 2))Útyperµ  r´  z	--verboseÚ
store_truez2Show score context table for every divergent trade)Úactionr´  z--score-contextr   zIBars 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)r   )Ú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: r[   zTV trades: z real signal  +  z margin-callzRunning Python strategy z on: )rz   )r�   rí   rV   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¤  rW   c              3   ó&   K  — | ]	  }|d    –— Œ y­w)rW   Nr   )rM   rt   s     r   rN   zmain.<locals>.<genexpr>p  s   è ø€ Ð5©W¨�q˜•|©Wùs   ‚z
2099-01-01éP   rm  Ú=z  MATCH SUMMARYz  Total TV real trades  : rh  z  (coverage through z  Total Python trades   : z  Entry + exit matched  : z  (r   r   r€  z% of TV)u     Entry matched, exit Î” : z  (IS: z, OOS after rA   u     â€” OOS are expected, not bugs)z  Python-only (extra)   : z  TV-only (missed)      : z  TV margin-call trades : z  (not modelled in Python)rP  rR  z
  TV/chart entry-marker check:z,    TV entries with exported chart marker : rO  Ú/rN  z,    Chart executable markers in TV window : rQ  z not present in TV trade list)z*    First TV entries without chart marker:r‚  z	      TV#rU   z signal z (fill u   ) â€” z3    First chart executable markers missing from TV:z      rÝ   rw   r+  r<   r=   c              3   ó>   •K  — | ]  }|‰j                   v r|–— Œ y ­wrK   rL   )rM   r0   Ú	tv_df_raws     €r   rN   zmain.<locals>.<genexpr>²  s'   øè ø€ ð +ÑF�dØ˜	×)Ñ)Ñ)ô ÑFùs   ƒ)zCumulative P&L %zCumulative PnL %rÜ   rÈ   rf  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¢  rQ   Ú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))r"  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.)CÚargparseÚArgumentParserÚRawDescriptionHelpFormatterÚ__doc__Úadd_argumentra   Ú
parse_argsÚ	timeframer3   ÚdataÚprintr9   Útools.validate_chart_datarº  rg   r    r   r*   Úreplacer+   r~   rz   r’   r]   r1  ry   rÞ   rŸ   r¼   r7   re   r   r   r)  r0  r§  rf   r6   rE  r3  r7  rh   rn  ra  Úverboser\   rB   r^   r_   Údropnar“   ÚCOMMISSION_RATEr˜   rß   rq  r¦  r¯  ÚsplitÚexit_detailr}  rŸ  rÐ   r�  r„  r÷   r…  r†  )QÚparserÚargsr4   rº  Ú_derrsÚ_dwarnsr(   Ú_er   r*   Úasset_tfÚstrategy_nameÚ	candidater1  rt   r;  Ú	tv_marginr    r»   Ú
pine_startÚpine_endÚall_py_tradesr2  r  r  r×   r"  r!  r>  Úpy_onlyÚtv_onlyÚexit_toleranceÚ
full_matchÚexit_mismatchr?  rB  Útv_exit_adjÚ
last_tv_dtÚpÚ
py_only_isÚpy_only_oosÚmarker_checkÚWÚoos_noteÚ
tv_missingÚchart_missingr^  Ú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Úpartr9  Ú	py_bar_dtrˆ  rJ  r‰  r.  Ú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Ó:KÐ9LÈHÐ
UÔVð	Ý;Ù*¨4¯9©9Ó5Ñˆ�˜ÙÜÐdÔeÛ�Ü˜ r dÐ+Õ,ð äÐ\Ô]ð
 —+‘+€KØÐä�D—I‘I‹×#Ñ#ˆØ—<‘<  SÓ)×/Ñ/Ó1ˆÜ% d×&8Ñ&8Ó9ˆÜÐ*Ó+Ð0DÀ]ÀOÐSTÐU]ÐT^Ð^bÐ.cÑcˆ	Ø×ÑÔÜ˜i›.ˆKÜÐ*¨;¨-Ð8Õ9äÐ=¸m¸_ÐLfÐgÔhô 
Ð& t§~¡~Ð&6Ð
7Ô8Ü˜tŸ~™~Ó.€IÙ%Ó<™I�q¨Q¨{«^’˜I€GÐ<Ù%Ó8™I�q¨¨;«’˜I€IÐ8Ü	ˆKœ˜G›�~Ð%6´s¸9³~Ð6FÀlÐ
SÔTá)4Œ[˜Ô%¸"€Fä	Ð$ T×%7Ñ%7Ð$8¸¸d¿i¹i¸[Ð
IÔJÜ! $§)¡)¨VÀ4×CUÑCUÔV€GÜ—‘œkÓ*€JÜ�|‰|œIÓ&€HÜ" 7¨F¸*È(ÔS€GÜ)¨'Ó2€Mñ
 *ÓI™M�q¨Q¨z©]¸jÓ-H’˜M€IÐIÜ	Ø
œ#˜i›.Ð)ð *Ø)Ÿ™Ó0Ð1°°x·}±}³Ð6GÀrÜˆ}ÓÐ
Ð5ð	7ôô ˜VŸZ™ZÐ(KÈUÓSÓT€OÜ˜VŸZ™ZÐ(JÈUÓSÓT€NÜ˜VŸZ™ZÐ(CÀSÓIÓJ€NØ—z‘zÐ"AÀ5ÓI€NØ—z‘zÐ"@À$ÓG€Mä	ˆMÔÜ	Ð  Ð 1Ð1CÀNÐCSÐSTÐ
UÔVÜ	Ð  Ð 0Ð0AÀ-ÀÐPQÐ
RÔSÜ	Ð  Ð 0°Ð
2Ô3ô !-¨Y¸	À6È4×K^ÑK^Ó _Ñ€GˆW�gô ˜vÓ&¨×)<Ñ)<Ñ<€NØ " B�€JÛ‰ˆˆBØ˜‘m¤i°Ó&7Ñ7ˆÜˆr�)‰}˜{Ñ*Ó+¨~Ò=Ø×Ñ˜r 2˜hÕ'à× Ñ  " b Õ*ð ñ :A”3Ñ5©WÓ5Ô5ÄbÇlÁlÐS_ÓF`€JÙ&ÓF™w˜!¨!¨J©-¸:Ó*E’A˜w€JÐFÙ&ÓF™w˜!¨!¨J©-¸:Ó*E’A˜w€KÐFÜ)ØØØØÙ*1ˆ
”Y˜vÓ&Ò&°tó€Lð 	€AÜ	ˆBˆs�1‰uˆgˆ,ÔÜ	ˆOÔÜ	ˆS�‰UˆGÔÜ	Ð&¤s¨7£|°BÐ&7Ð7KÈJÏOÉOÓL]ÐK^Ð^_Ð
`ÔaÜ	Ð&¤s¨9£~°bÐ&9Ð
:Ô;Ü	Ð&¤s¨:£°rÐ&:¸#¼cÀ*»oÌcÔRUÐV]ÓR^Ð_`ÓNaÑ>aÐbeÑ>eÐfiÐ=jÐjrÐ
sÔtÜ	Ð'¬¨MÓ(:¸2Ð'>Ð
?Ô@Øœ˜Z›Ð)¨°j·o±oÓ6GÐ5HÈÌ3È{ÓK[ÐJ\Ð\|Ð}€HÜ	Ð&¤s¨7£|°BÐ&7¸°zÐ
BÔCÜ	Ð&¤s¨7£|°BÐ&7Ð
8Ô9ÙÜÐ*¬3¨y«>¸"Ð*=Ð=WÐXÔYÜ	ˆS�‰UˆGÔàÐØ!Ð"5Ñ6ˆ
Ø$Ð%7Ñ8ˆÙ™¨$¯,ª,ÜÐ4Ô6ÜØ>ØÐ 0Ñ1Ð2°!°LÀÑ4LÐ3MðOôô Ø>ØÐ 2Ñ3Ð4ð 5Ü˜Ó&Ð'Ð'EðGôñ
 ÜÐBÔCØ-7¸¸«^Ñ)�B˜	 6ÜØ# B {¡OÐ#4°H¸Y¸Kð H!Ø!# J¡Ð 0°°v°hð@õð .<ñ
 ÜÐKÔLØ!.¨r°Ó!2�IÜ˜F 9 +Ð.Õ/ð "3ð '*Ð)€M�OÛˆØ˜A  )¡¨sÑ 2Ñ2Ñ3ˆØ˜A  /Ñ 2°SÑ 8Ñ8Ñ9‰ð ð " AÑ%¨Ñ,€JØ# aÑ'¨3Ñ.€Lð
"Ü—[‘[ §¡¸+ÔFˆ	Ø%×-Ñ-×1Ñ1×7Ñ7Ó9ˆ	ÔÜó+ÑFó +àó
ˆñ
 >E�Y˜wÑ'×.Ñ.Ó0×5Ñ5°bÒ9Ì%ÐPUË,ˆ
ô ˜CÑ
€CÜ˜“^¤s¨7£|Ñ3€NÜ" :¬uÓ5ÒN¼"¿(¹(À:Ó:NÐOÒ^ÐT^€LÜ	„GÜ	ˆBÐ:¸SÑ@ÀÐEÀjÐQXÐEYÐYZÐ
[Ô\Ü	ˆBÐ# CÐ(¨°GÐ(<¸AÐ
>Ô?Ù™Ü�*˜zÑ)Ó*¬S°«_Ñ<¸sÑBˆÜÐ1°#°c°ð ;<ð =õ 	>á	ô 	Ð<¼SÀ»^Ð<LÈGÜ�W“�ð ?ð@ô 	Aô 
ˆBÐ9¸#Ð>¸|ÈGÐ>TÐTUÐ
VÔWÜ	„Gò Ü��5˜‘7�)ˆnÔÜÐ!¤# j£/Ð!2°(Ð;Ô<Ü��q‘�	ÔØ�3�r�(˜"˜Z¨Ð,¨A¨j¸Ð-=¸RÀ	È#¸ÈaÐPYÐZ]ÈÐ^`ÐajÐkmÐ`nÐnoÐpyÐz|Ðo}Ð}ð  AJð  KMð  @Nð  OˆÜˆcŒ
Üˆd�S˜A ™E‘]Ñ"Ô#Ü ‰FˆB�Ø˜j™>¬I°fÓ,=Ñ=ˆLØ˜i™=¬I°fÓ,=Ñ=ˆKØ˜*‘~¨Ñ4×CÑCÓEÈÑLˆGØ˜)‘}¨Ñ3×BÑBÓDÈÑLˆFØ˜‘m b¨Ñ&7Ñ7ˆEÜ-0°«[¸1ª_˜˜6 #˜, bÑ)À"ˆDÜØ�R˜‘_ RÐ(¨Ü�r˜*‘~×*Ñ*Ó,Ó-¨cÐ2°!´C¸¸:¹×8KÑ8KÓ8MÓ4NÈsÐ3SÐSUÜ�r˜)‘}×)Ñ)Ó+Ó,¨SÐ1°´3°r¸)±}×7IÑ7IÓ7KÓ3LÈSÐ2QÐQRÐSWÐXZÐR[Ð[]Ø�i‘= Ð' r¨"¨]Ñ*;¸EÐ)BÀ#ÀeÈFÀ^ÐSTðVöð !ñ Ü��5˜‘7�)ˆnÔÜÐCÄCÈÓDVÐCWÐW^Ð_Ô`Ü��q‘�	ÔÛ#‰FˆB�Ü�G˜B˜{™OÐ,¨AÐ.Ô/Ü+¨B°°G¸^È^Ó\ˆFØŸ™ UÖ+�Ü˜˜T˜F�mÕ$ð ,à×Ó B z¡NÑ$>Ü”m G¨R°
©^¸T×=OÑ=OÓPÕQð $ñ Ü��5˜‘7�)ˆnÔÜÐ$¤S¨£_Ð$5Ð5hÐiÔjÜ��q‘�	ÔÛˆBÜ% b¨'°?ÔSWÐXfÓSgÔhˆFÜ�J˜r *™~×2Ñ2Ó4Ð5°W¸RÀ	¹]×=OÑ=OÓ=QÐ<RÐRXÐY[Ð\eÑYfÐgkÐXlÐlmÐnÔoØŸ™ UÖ+�Ü˜˜T˜F�mÕ$ð ,à�|‹|  ;¡Ñ ;Ü”m G¨R°©_¸d×>PÑ>PÓQÕRð ñ Ü��5˜‘7�)ˆnÔÜÐ%¤c¨+Ó&6Ð%7Ð7XÐYc×YhÑYhÓYjÐXkð  lAð  Bô  	CÜ��q‘�	ÔÛˆBÜ�H˜R 
™^×0Ñ0Ó2Ð3°7¸2¸i¹=×;MÑ;MÓ;OÐ:PÐPVÐWYÐZcÑWdÐeiÐVjÐjrÐsÕtð ò Ü��5˜‘7�)ˆnÔÜ�œC ›L˜>Ð)OÐPÔQÜ��q‘�	ÔÜˆBÜ% b¨'°?ÀFÓKˆFÜ�G˜B˜{™OÐ,¨H°R¸
±^×5HÑ5HÓ5JÐ4KÈ7ÐSUÐV_ÑS`×SeÑSeÓSgÐRhÐhnÐoqÐrñ  pAð  BFð  oGð  GHð  Iô  JØŸ™ UÖ+�Ü˜˜T˜F�mÕ$ð ,ô # 6Ó*ˆFØ˜J™¨&Ñ0ˆIØ !™ˆCØ! &™/¨Y¸©_Ñ<ÀÈÁÐT]Ð`cÑTcÑAcÑdˆDØ  ™ˆDØ—:“: $§,£,Ø—j‘j  f¡×!1Ñ!1°)Ó!<×!@Ñ!@Ó!B×!IÑ!IÓ!KÑL�Ü”m G¨S°$×2DÑ2DÓEÖFð ñ  Ü��5˜‘7�)ˆnÔÜÐLÔNÜ��q‘�	ÔÛˆBÜ�E˜"˜[™/Ð*¨(°2°j±>×3FÑ3FÓ3HÐ2IÈÐQSÐT]ÑQ^×QcÑQcÓQeÐPfÐflÐmoÐp}Ñm~ð  @Dð  mEð  EFð  Gõ  Hð ô 
ˆBˆs�1‰uˆgˆ,ÔÜ	Ð
(Ô)Ü	ˆS�‰UˆGÔØÐÛˆÜ˜R ¨/Ì$È~ÓJ^Ô_ˆØ˜1ÒØ Ñ!Ñð ó ˆÜ˜R ¨/¸6ÓBˆØ˜1ÒØ Ñ!Ñð ô
 �z“?¤S¨£\°AÑ%5Ñ5€Lð  ÐØÐÛ+Ñˆ�(Ü& x°¸7ÀNÐTbÓcˆØ&¨%Ñ/Ø# qÑ(Ñ#Ø Ñ%Ø 1Ñ$Ñà 1Ñ$Ñð ,ð €DØ˜!ÒØ�‰ØÐ"Ð#ð $UØUY×U^ÑU^ÐT_Ð_iÐjuÐivð wEàEIÇYÁYÀKÐOvð  xCð  wDð DUðVô	
ñ Ø�‰Ø*¬3¨z«?Ð*;Ð;OÔPSÐT[ÓP\È~ð ^=ð >ô	
ñ ‘WØ�‰Ø#¤C¨
£OÐ#4Ð4OÔPSÐT[ÓP\È~ð ^\ð ]ô	
ð ÐØÐ(Ò)¨\Ð:LÒ-Mà�‰Ø+Ü�<Ð 3Ñ4Ó5Ð6Ð6fÜ�<Ð 2Ñ3Ó4Ð5ð 6oðpô	
ð  Ò"Ø�‰ØÐ)Ð*ð +Pð Qô	
ð ˜QÒØ�‰ØÐ%Ð&Ð&JÈ>ÐZ]ÐJ^ð _Pð Qô	
ñ Ø�‰ÐaÔbÛˆÜˆaŒÜ�ð ô 
ÐWÔYÜ	ÐbÔdÜ	ÐaÔcÜ	ˆS�‰UˆGÕøô[
 ò Úðüò( =ùÚ8ùò JùòF GùÚFøôJ ò "Ü˜5“\‹
ð"úsv   ÅA	AD É=
AD.ÊAD.Ê
AD3ÊAD3Í-AD8Í;AD8Ô5AD=ÕAD=ÕAEÕAEÞ?BAE ÁD	AD+ÁD*AD+ÁEAEÁEAEÚ__main__)r¶  rK   )r  )r‚  )F)>rÌ  rÉ  Úimportlib.utilr«   r–   r‘   r¯   Úpathlibr   Útypingr   Únumpyrß   Úpandasr7   r:   Úinsertr]   r§   r¨   r©   Úconfigr   r   r   rh   rÖ  rf   r   r8   r,   r.   r3   r9   r6  r™   ry   r~   rŸ   Ú	DataFramer¼   rÆ   r  rÉ   rÐ   rÒ   ÚndarrayÚtuplerì   re   r)  r0  ra   rE  rK  ra  r}  r�  rŸ  r¯  r  Ú__name__r   r   r   Ú<module>r     s‹  ðñ0ód Û Û Û 	Û 
Ý Ý ã Û à ‡�‡��‘3‘t˜H“~×-Ñ-Ó/×6Ñ6×=Ñ=Ó>Ô ?ß 6Ñ 6à ‡�‡�‘‘D˜“N×*Ñ*Ó,×3Ñ3×:Ñ:Ó;Ô <ð €ð *9ñ4˜%ð 4¨%ð 4Ø!&ð4Ø=Bó4ð ˆ2�<‰<˜aÔ Øˆ2�<‰<˜aÔ Øˆ2�<‰<˜aÔ Øˆ2�<‰<˜bÔ!Øˆ2�<‰<˜QÔñ€ð  d°4ÀÑF€ð ð ¨°©ó ð(;�cð ;˜bŸl™ló ;ðB˜ð B  d¡ó BðN* ð *¨ó *ð˜Sð  Tó ð2 .Fñ 3ð °ð Ø'*ðØJLÏ,É,óð6˜RŸ\™\ð ¨h°s©mó ð &˜Ÿ	™	ð &¨B¯L©Lð &¸Uó &ð˜$ó ð&)Ø�Z‰Zð&)à�:‰:ð&)ð �z‰zð&)ð �j‰jð	&)ð
 ð&)ð ˆ2�:‰:�r—z‘z 2§:¡:Ð-Ñ.ó&)ðZ #'ñ	dØ�\‰\ðdàðdð �<‰<ðdð 
�"—,‘,Ñ	ð	dð
 ‡\�\ódðN 2§<¡<ð °D¸±Jó ðN ñ	)/Ø�d‘ð)/à�d‘ð)/ð ð)/ð ð	)/ð
 ˆ4�‰;˜˜T™
 D¨¡JÐ.Ñ/ó)/ð\˜"Ÿ,™,ð °#ð ¸(À2Ç9Á9Ñ:Mó ð* #'ñ2Ø�D‰zð2à�\‰\ð2ð ð2ð �<‰<ð	2ð
 
�"—,‘,Ñ	ð2ð ˆd�^ó2ñn˜2Ÿ<™<ð °#ð Àð ÈCó ð.&˜tð &¨b¯l©lð &ÈUð &Ø ð&Ø%(ó&ðT -2ñ;˜tð ;¨b¯l©lð ;ÈUð ;Ø%)ð;Ø69ó;ð|3 Tð 3°Tð 3ÀBÇLÁLð 3Ø+0ð3ØBGð3ØLOó3òpyðx ˆzÒÙ…Fð r   