+
    gj"  c                      R t ^ RIt^ RIHu Ht ^ RIt^ RIt^ RI	H
t ]P                  P                  ]P                  P                  ]P                  P                  ]4      R4      4      tRt ! R R4      t ! R R4      t ! R R	4      tR# )
u  
Regression tests for tools/mlp_results_table.py multi-asset global-state hazard.

Backlog item (observations.md): "No test for mlp_results_table.py with
non-BTC assets (default-arg bug was latent from day one)."

Contract under test
--------------------
`ASSET` and `TF_MAP` are two separate mutable module globals. `main()` keeps
them paired by reassigning both, in order, before evaluating any timeframe:

    ASSET  = args.asset
    TF_MAP = _tf_map(ASSET)

Any *other* caller of `evaluate_tf()` / `winner_path()` that updates one
global without the other can silently pair one asset's price data with a
different asset's optimized winner CSV — wrong economics, no error raised.
Confirmed empirically before the fix in this file: setting only
`mrt.ASSET = "COINBASE_ETHUSD"` (leaving the default BTC `TF_MAP` in place)
made `evaluate_tf("4H")` read `data/mlp/COINBASE_BTCUSD, 240.csv` (which
exists) together with the real
`results/winners/optimization_winner_strategy_mlp_scores_COINBASE_ETHUSD_4H.csv`
winner (which also exists) — both checks in `evaluate_tf` passed and it
proceeded into `strat.generate_signals` with mismatched asset data/params
(a `ValueError` in this particular BTC/ETH feature-column combination, but
nothing guarantees that in general — a compatible combination would silently
produce a wrong-but-plausible-looking result).

The fix: `evaluate_tf` no longer reads the module-global `TF_MAP` at all. It
resolves the asset once (explicit `asset=` kwarg, else the `ASSET` global)
and derives *both* the data file and the winner CSV path from that single
resolved value, so the two halves can no longer point at different assets
regardless of what `TF_MAP` happens to contain.

Only `COINBASE_BTCUSD` has real price CSVs under data/mlp/ in this repo, so
these tests exercise `_tf_map`, `winner_path`, and the global-pairing/
`evaluate_tf` guard directly rather than a full non-BTC backtest.
Nz..COINBASE_ETHUSDc                      a  ] tR t^2t o RtR t]P                  P                  R]	! ]
P                  P                  4       4      4      R 4       tR tRtV tR# )	TestTfMapzD`_tf_map(asset)` must build asset-specific paths, not just BTC ones.c                n   \         P                  ! \        4      pVP                  q"! 4       p\	        V4      p\         P
                  qUP                  qf! 4       p\	        V4      qV8H  q'       Eg7   \        P                  ! RV	3RWH34      RR\        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MRRR\        P                  ! 4       9   g   \        P                  ! V4      '       d   \        P                  ! V4      MRR\        P                  ! V4      R\        P                  ! V4      R\        P                  ! V4      RR\        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MRR	R
\        P                  ! 4       9   g!   \        P                  ! \         4      '       d   \        P                  ! \         4      MR
R\        P                  ! V4      R\        P                  ! V4      R\        P                  ! V4      R\        P                  ! V4      /,          p
RRV
/,          p\        \        P                  ! V4      4      hR;p;p;p;p	;p;p;rxR# )==py0setpy1tf_mappy3py5py7py9py10mrtpy12py14py16py18zassert %(py20)spy20Nr   )z%(py7)s
{%(py7)s = %(py0)s(%(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.keys
}()
})
} == %(py18)s
{%(py18)s = %(py9)s(%(py16)s
{%(py16)s = %(py14)s
{%(py14)s = %(py12)s
{%(py12)s = %(py10)s._TF_PERIODS
}.keys
}()
})
})r   _tf_mapNON_BTC_ASSETkeysr   _TF_PERIODS
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanation)selfr	   @py_assert2@py_assert4@py_assert6@py_assert11@py_assert13@py_assert15@py_assert17@py_assert8@py_format19@py_format21s   &           G/Users/jameslopez/projects/TradingBot25/tests/test_mlp_results_table.py,test_returns_a_path_per_configured_timeframe6TestTfMap.test_returns_a_path_per_configured_timeframe5   s`   ]+;;@;=@s=!@@)=)=@)=)?@S)?%@@%@@@@@@!@@@@@@s@@@@s@@@@@@@6@@@@6@@@;@@@=@@@!@@@@@@S@@@@S@@@@@@@@@@@@@@@@@)=@@@)?@@@%@@@@@@@@@@    z	tf,periodc                t   \         P                  ! \        4      pW1,          pR \         RV R2qTV8H  qf'       gy   \        P                  ! RV3R	WE34      R\        P
                  ! V4      R\        P
                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR;p;reR# )
z	data/mlp/z, .csvr   py4assert %(py6)spy6Nr   )z%(py1)s == %(py4)s)r   r   r   r   r   r   r    r!   )	r"   tfperiodr	   @py_assert0@py_assert3r#   @py_format5@py_format7s	   &&&      r-   /test_path_embeds_the_requested_asset_and_period9TestTfMap.test_path_embeds_the_requested_asset_and_period9   so    ]+zFyr&FFFFFFFFzFFFzFFFFFFFFFFFFr0   c                   \         P                  ! R 4      p\         P                  ! \        4      p\         P                   F  pW,          qBV,          qTV8g  qf'       gy   \        P
                  ! RV3RWE34      R\        P                  ! V4      R\        P                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR;p;reK  	  R# )COINBASE_BTCUSDr   r3   r4   r5   N)!=)z%(py1)s != %(py4)s)	r   r   r   r   r   r   r   r    r!   )	r"   btcethr6   r8   r9   r#   r:   r;   s	   &        r-   #test_different_assets_never_collide-TestTfMap.test_different_assets_never_collide>   s}    kk+,kk-(//B7%"g%g%%%%%7%%%7%%%g%%%%%%%% "r0    N)__name__
__module____qualname____firstlineno____doc__r.   pytestmarkparametrizelistr   r   itemsr<   rC   __static_attributes____classdictcell____classdict__s   @r-   r   r   2   sR     NA [[[$s/D/D/F*GHG IG& &r0   r   c                   r   a  ] tR t^Et o Rt]P                  P                  R. RO4      R 4       tR t	Rt
V tR# )TestWinnerPathzE`winner_path(tf, asset)` must resolve to the real on-disk winner CSV.r6   c                   \         P                  ! V\        4      p\         P                  pR \         RV R2qCV,          qRV8H  qf'       Eg   \        P
                  ! RV3RW%34      RR\        P                  ! 4       9   g   \        P                  ! V4      '       d   \        P                  ! V4      MRRR\        P                  ! 4       9   g!   \        P                  ! \         4      '       d   \        P                  ! \         4      MRR\        P                  ! V4      R\        P                  ! V4      /,          pR	R
V/,          p\        \        P                  ! V4      4      hR;p;p;rE\        P                  P                  \        \!        V4      4      p	\        P                  qfP"                  q3! V	4      q'       Eg-   \        P$                  ! RV	 24      R,           RR\        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MRR\        P                  ! V4      R\        P                  ! V4      RR\        P                  ! 4       9   g   \        P                  ! V	4      '       d   \        P                  ! V	4      MRR\        P                  ! V
4      /,          p\        \        P                  ! V4      4      hR;p;r:R# )(optimization_winner_strategy_mlp_scores__r2   r   wppy2r   r3   r5   zassert %(py9)sr   Nzexpected real fixture at zd
>assert %(py7)s
{%(py7)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.path
}.exists
}(%(py5)s)
}osr   abs_wpr   r   )z>%(py0)s == (%(py4)s
{%(py4)s = %(py2)s.WINNER_DIR
} / %(py6)s))r   winner_pathr   
WINNER_DIRr   r   r   r   r   r   r    r!   r[   pathjoin	REPO_ROOTstrexists_format_assertmsg)r"   r6   rY   r9   @py_assert5@py_assert7@py_assert1@py_format8@py_format10r\   r%   s   &&         r-   :test_explicit_non_btc_asset_resolves_to_a_file_that_existsITestWinnerPath.test_explicit_non_btc_asset_resolves_to_a_file_that_existsH   s   __R/^^i(PQ^P__`ac`ddh&ii&iiiiiiiiiriiiiiiriiiiriiiiiiiSiiiiSiii^iii&iiiiiiiiiiR1wwK~~K~f%K%KK)B6('KKKKKKKKrKKKKrKKKwKKK~KKKKKKfKKKKfKKK%KKKKKKKr0   c                   VP                  \        R \        4       \        P                  pRq2! V4      p\        P                  pRqe! V\        4      qtV8H  q'       Eg   \        P
                  ! RV3RWG34      RR\        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MRR\        P                  ! V4      R\        P                  ! V4      R\        P                  ! V4      RR\        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MRR\        P                  ! V4      R	\        P                  ! V4      R
R\        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MRR\        P                  ! V4      /	,          p	RRV	/,          p
\        \        P                  ! V
4      4      hR;p;p;p;p;p;rgR# )ASSET4Hr   r   rZ   r3   r5   py8r   r   py13r   py15zassert %(py17)spy17Nr   )z%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.winner_path
}(%(py4)s)
} == %(py15)s
{%(py15)s = %(py10)s
{%(py10)s = %(py8)s.winner_path
}(%(py12)s, %(py13)s)
})setattrr   r   r]   r   r   r   r   r   r   r    r!   )r"   monkeypatchrg   r9   re   @py_assert9r&   @py_assert14rf   @py_format16@py_format18s   &&         r-   .test_default_asset_falls_back_to_module_global=TestWinnerPath.test_default_asset_falls_back_to_module_globalO   s!   C-8LtLt$LLLm(LL(LLLLLL$LLLLLLsLLLLsLLLLLLtLLL$LLLLLLLLLLLLLLLLLLLLLLmLLLLmLLL(LLLLLLLLLLr0   rE   N)rn   6H8H12H1D)rF   rG   rH   rI   rJ   rK   rL   rM   rj   ry   rP   rQ   rR   s   @r-   rU   rU   E   s;     O[[T#BCL DLM Mr0   rU   c                   6   a  ] tR t^Tt o RtR tR tR tRtV t	R# )TestGlobalPairingHazardz
The real hazard: ASSET and TF_MAP are independent mutable globals.
main() pairs them correctly; a direct caller of evaluate_tf() need not.
c                   VP                  \        R \        4       VP                  \        R\        P                  ! \        4      4       \        P                   EF  p\        P
                  V,          p\        V9   qD'       g   \        P                  ! RV3R\        V34      RR\        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MRR\        P                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR;rC\        P                  qw! V4      p\        V4      p	\        V	9   qD'       Eg   \        P                  ! RV3R\        V	34      RR\        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MRRR	\        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MR	RR
\        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MR
R\        P                  ! V4      RR\        P                  ! 4       9   g   \        P                  ! V4      '       d   \        P                  ! V4      MRR\        P                  ! V4      R\        P                  ! V	4      /,          p
RRV
/,          p\        \        P                  ! V4      4      hR;p;p;rEK  	  R# )rm   TF_MAPr   r   r
   assert %(py5)sr   NrZ   rb   r   r5   r6   ro   r   zassert %(py12)sr   in)z%(py0)s in %(py3)s)zq%(py0)s in %(py10)s
{%(py10)s = %(py2)s(%(py8)s
{%(py8)s = %(py5)s
{%(py5)s = %(py3)s.winner_path
}(%(py6)s)
})
})rs   r   r   r   r   r   r   r   r   r   r   r   r    r!   r]   rb   )r"   rt   r6   r#   rg   @py_format4@py_format6r$   rf   ru   @py_format11@py_format13s   &&          r-   =test_mains_paired_reassignment_keeps_asset_and_tf_map_in_syncUTestGlobalPairingHazard.test_mains_paired_reassignment_keeps_asset_and_tf_map_in_syncZ   s    	C-8C3;;}+EF //B$'JJrN2=N22222=N222222=2222=222N22222222(+<(;<C(;$<<=$<<<<<<=$<<<<<<<=<<<<=<<<<<<<C<<<<C<<<<<<<<<<<<<<<<<<<<<<<<<<<(;<<<$<<<<<<<<< "r0   c                ,   VP                  \        R \        4       Rp\        P                  R,          q2V9   qD'       gy   \        P
                  ! RV3RW#34      R\        P                  ! V4      R\        P                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR;p;rC\        P                  P                  \        \        P                  R,          4      p\        P                  P                  \        \        \        P                  ! R4      4      4      p\        P                  qP                  q3! V4      q'       Eg   RR	R
\         P"                  ! 4       9   g!   \        P$                  ! \        4      '       d   \        P                  ! \        4      MR
R\        P                  ! V	4      R\        P                  ! V4      RR\         P"                  ! 4       9   g   \        P$                  ! V4      '       d   \        P                  ! V4      MRR\        P                  ! V
4      /,          p\        \        P                  ! V4      4      hR;p	;r:\        P                  qP                  q3! V4      q'       Eg   RR	R
\         P"                  ! 4       9   g!   \        P$                  ! \        4      '       d   \        P                  ! \        4      MR
R\        P                  ! V	4      R\        P                  ! V4      RR\         P"                  ! 4       9   g   \        P$                  ! V4      '       d   \        P                  ! V4      MRR\        P                  ! V
4      /,          p\        \        P                  ! V4      4      hR;p	;r:\        V9  q'       g   \        P
                  ! RV	3R\        V34      R	R\         P"                  ! 4       9   g!   \        P$                  ! \        4      '       d   \        P                  ! \        4      MRRR\         P"                  ! 4       9   g   \        P$                  ! V4      '       d   \        P                  ! V4      MR/,          pRRV/,          p\        \        P                  ! V4      4      hRp	\        V9   q'       g   \        P
                  ! RV	3R\        V34      R	R\         P"                  ! 4       9   g!   \        P$                  ! \        4      '       d   \        P                  ! \        4      MRRR\         P"                  ! 4       9   g   \        P$                  ! V4      '       d   \        P                  ! V4      MR/,          pRRV/,          p\        \        P                  ! V4      4      hRp	\        P&                  ! R4      pRqMVJ q'       g   \        P
                  ! RV	3RW34      R	R\         P"                  ! 4       9   g   \        P$                  ! V4      '       d   \        P                  ! V4      MRR\        P                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR;rR# )rm   r?   rn   r   r3   r4   r5   Nzbassert %(py7)s
{%(py7)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.path
}.exists
}(%(py5)s)
}r   r[   rZ   r   stale_data_filer   mismatched_winnerr   zassert %(py4)sresultr
   r   r   )z%(py1)s in %(py4)s)not in)z%(py0)s not in %(py2)s)z%(py0)s in %(py2)sisz%(py0)s is %(py3)s)rs   r   r   r   r   r   r   r    r!   r[   r_   r`   ra   rb   r]   rc   r   r   r   evaluate_tf)r"   rt   r8   r9   r#   r:   r;   r   r   rg   r%   rh   @py_format3r   r   r   s   &&              r-   Atest_evaluate_tf_never_pairs_one_assets_data_with_anothers_winnerYTestGlobalPairingHazard.test_evaluate_tf_never_pairs_one_assets_data_with_anothers_winnere   s?   
 	C-8 4CJJt$44$444444 444 444$444444444
 '',,y#**T2BCGGLLC8M4NOww.~~.~o.........r....r...w...~......o....o..........ww0~~0~/000000000r0000r000w000~000000/0000/0000000000O33333}O333333}3333}3333333O3333O33333333 111111} 1111111}1111}1111111 11111 111111111 &~vvvr0   c                   VP                  \        R RR/4       \        P                  ! R\        R7      pRq2VJ qD'       g   \        P
                  ! R
V3RW#34      RR\        P                  ! 4       9   g   \        P                  ! V4      '       d   \        P                  ! V4      MRR\        P                  ! V4      /,          pRR	V/,          p\        \        P                  ! V4      4      hR;rCR# )r   rn   zdoes/not/exist.csv)assetNr   r   r
   r   r   r   r   )rs   r   r   r   r   r   r   r   r   r   r    r!   )r"   rt   r   r#   rg   r   r   s   &&     r-   >test_evaluate_tf_ignores_tf_map_entirely_for_an_explicit_assetVTestGlobalPairingHazard.test_evaluate_tf_ignores_tf_map_entirely_for_an_explicit_asset   s    CD2F+GH
 ];~vvvr0   rE   N)
rF   rG   rH   rI   rJ   r   r   r   rP   rQ   rR   s   @r-   r   r   T   s     
	=4 r0   r   )rJ   builtinsr   _pytest.assertion.rewrite	assertionrewriter   r[   rK   tools.mlp_results_tablemlp_results_tabler   r_   abspathr`   dirname__file__ra   r   r   rU   r   rE   r0   r-   <module>r      sm   %L  	  %GGOOBGGLL)BDIJ	!& &&M M3 3r0   