
    gj"                        d Z ddlZddlmc mZ ddlZddlZddl	m
Z ej                  j                  ej                  j                  ej                  j                  e      d            ZdZ G d d      Z G d d      Z G d	 d
      Zy)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                       e Zd ZdZd Zej                  j                  d ee	j                  j                                     d        Zd Zy)	TestTfMapzD`_tf_map(asset)` must build asset-specific paths, not just BTC ones.c                    t        j                  t              }|j                  } |       }t	        |      }t         j
                  }|j                  } |       }t	        |      }||k(  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            d x}x}x}x}	x}x}x}}y )	N==)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
}()
})
}settf_mapmrt)py0py1py3py5py7py9py10py12py14py16py18zassert %(py20)spy20)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_timeframez6TestTfMap.test_returns_a_path_per_configured_timeframe5   sP   ]+;;@;=@s=!@@)=)=@)=)?@S)?%@@!%@@@@@!%@@@@@@@s@@@s@@@@@@6@@@6@@@;@@@=@@@!@@@@@@S@@@S@@@@@@@@@@@@@@@)=@@@)?@@@%@@@@@@@@@    z	tf,periodc                 L   t        j                  t              }||   }dt         d| d}||k(  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )	Nz	data/mlp/z, .csvr   )z%(py1)s == %(py4)sr   py4assert %(py6)spy6)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_periodz9TestTfMap.test_path_embeds_the_requested_asset_and_period9   sp    ]+bzFyr&FFzFFFFFzFFFFzFFFFFFFFFFFr1   c                    t        j                  d      }t        j                  t              }t         j                  D ]  }||   }||   }||k7  }|slt	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d x}x}} y )NCOINBASE_BTCUSD)!=)z%(py1)s != %(py4)sr4   r6   r7   )	r   r   r   r   r   r   r!   r"   r#   )	r$   btcethr8   r:   r;   r%   r<   r=   s	            r/   #test_different_assets_never_collidez-TestTfMap.test_different_assets_never_collide>   s    kk+,kk-(//Br7%c"g%7g%%%%7g%%%7%%%g%%%%%%% "r1   N)__name__
__module____qualname____doc__r0   pytestmarkparametrizelistr   r   itemsr>   rD    r1   r/   r   r   2   sJ    NA [[[$s/D/D/F*GHG IG&r1   r   c                   ^    e Zd ZdZej
                  j                  dg d      d        Zd Zy)TestWinnerPathzE`winner_path(tf, asset)` must resolve to the real on-disk winner CSV.r8   )4H6H8H12H1Dc                 @   t        j                  |t              }t         j                  }dt         d| d}||z  }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  t               rt	        j                  t               ndt	        j                  |      t	        j                  |      dz  }d	d
|iz  }t        t	        j                  |            d x}x}x}}t        j                  j                  t        t!        |            }	t        j                  }|j"                  } ||	      }
|
st	        j$                  d|	       dz   dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      dt        j                         v st	        j                  |	      rt	        j                  |	      ndt	        j                  |
      dz  }t        t	        j                  |            d x}x}}
y )N(optimization_winner_strategy_mlp_scores__r3   r   )z>%(py0)s == (%(py4)s
{%(py4)s = %(py2)s.WINNER_DIR
} / %(py6)s)wpr   )r   py2r5   r7   zassert %(py9)sr   zexpected real fixture at zd
>assert %(py7)s
{%(py7)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.path
}.exists
}(%(py5)s)
}osabs_wpr   rZ   r5   r   r   )r   winner_pathr   
WINNER_DIRr   r   r   r   r    r!   r"   r#   r[   pathjoin	REPO_ROOTstrexists_format_assertmsg)r$   r8   rY   r;   @py_assert5@py_assert7@py_assert1@py_format8@py_format10r\   r'   s              r/   :test_explicit_non_btc_asset_resolves_to_a_file_that_existszITestWinnerPath.test_explicit_non_btc_asset_resolves_to_a_file_that_existsH   s|   __R/^^i(PQ^P__`ac`ddh&ii^&iiiriiiiiriiiiiiiriiiriiiiiiSiiiSiii^iii&iiiiiiiiiR1wwKw~~K~f%K%KK)B6('KKKKKKKrKKKrKKKwKKK~KKKKKKfKKKfKKK%KKKKKKr1   c                    |j                  t        dt               t        j                  }d} ||      }t        j                  }d} ||t              }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      d	z  }	dd	|	iz  }
t        t	        j                  |
            d x}x}x}x}x}x}}y )
NASSETrQ   r   )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)
}r   r   )	r   rZ   r5   r7   py8r   r   py13py15zassert %(py17)spy17)setattrr   r   r^   r   r   r   r   r    r!   r"   r#   )r$   monkeypatchrh   r;   rf   @py_assert9r(   @py_assert14rg   @py_format16@py_format18s              r/   .test_default_asset_falls_back_to_module_globalz=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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LmLLLmLLL(LLLLLLLLLr1   N)	rE   rF   rG   rH   rI   rJ   rK   rk   rx   rN   r1   r/   rP   rP   E   s2    O[[T#BCL DLMr1   rP   c                   "    e Zd ZdZd Zd Zd Zy)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                    |j                  t        dt               |j                  t        dt        j                  t                     t        j                  D ]  }t        j
                  |   }t        |v }|st        j                  d|fdt        |f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}t        j                  } ||      }t        |      }	t        |	v }|st        j                  d|fd	t        |	f      dt        j                         v st        j                  t              rt        j                  t              ndd
t        j                         v st        j                  t              rt        j                  t              nd
dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |	      dz  }
dd|
iz  }t        t        j                  |            d x}x}x}}	 y )Nrm   TF_MAPin)z%(py0)s in %(py3)sr   r   r   assert %(py5)sr   )zq%(py0)s in %(py10)s
{%(py10)s = %(py2)s(%(py8)s
{%(py8)s = %(py5)s
{%(py5)s = %(py3)s.winner_path
}(%(py6)s)
})
}rc   r   r8   )r   rZ   r   r   r7   rn   r   zassert %(py12)sr   )rr   r   r   r   r   r|   r   r   r   r   r    r!   r"   r#   r^   rc   )r$   rs   r8   r%   rh   @py_format4@py_format6r&   rg   rt   @py_format11@py_format13s               r/   =test_mains_paired_reassignment_keeps_asset_and_tf_map_in_synczUTestGlobalPairingHazard.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=N222222=222=222N2222222(+<(;<C(;$<<=$<<<<<=$<<<<<<<=<<<=<<<<<<C<<<C<<<<<<<<<<<<<<<<<<<<<<<<(;<<<$<<<<<<<< "r1   c                    |j                  t        dt               d}t        j                  d   }||v }|slt	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d x}x}}t        j                  j                  t        t        j                  d         }t        j                  j                  t        t        t        j                  d                  }t        j                  }	|	j                  } ||      }
|
sd	d
t!        j"                         v st	        j$                  t              rt	        j                  t              nd
t	        j                  |	      t	        j                  |      dt!        j"                         v st	        j$                  |      rt	        j                  |      ndt	        j                  |
      dz  }t        t	        j                  |            d x}	x}}
t        j                  }	|	j                  } ||      }
|
sd	d
t!        j"                         v st	        j$                  t              rt	        j                  t              nd
t	        j                  |	      t	        j                  |      dt!        j"                         v st	        j$                  |      rt	        j                  |      ndt	        j                  |
      dz  }t        t	        j                  |            d x}	x}}
t        |v}	|	st	        j
                  d|	fdt        |f      dt!        j"                         v st	        j$                  t              rt	        j                  t              nddt!        j"                         v st	        j$                  |      rt	        j                  |      nddz  }dd|iz  }t        t	        j                  |            d }	t        |v }	|	st	        j
                  d|	fdt        |f      dt!        j"                         v st	        j$                  t              rt	        j                  t              nddt!        j"                         v st	        j$                  |      rt	        j                  |      nddz  }dd|iz  }t        t	        j                  |            d }	t        j&                  d      }d }||u }	|	st	        j
                  d|	fd||f      dt!        j"                         v st	        j$                  |      rt	        j                  |      ndt	        j                  |      dz  }dd|iz  }t        t	        j                  |            d x}	}y )Nrm   r@   rQ   r}   )z%(py1)s in %(py4)sr4   r6   r7   zbassert %(py7)s
{%(py7)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.path
}.exists
}(%(py5)s)
}r[   stale_data_filer]   mismatched_winner)not in)z%(py0)s not in %(py2)sr   )r   rZ   zassert %(py4)sr5   )z%(py0)s in %(py2)sisz%(py0)s is %(py3)sresultr   r   r   )rr   r   r   r|   r   r   r!   r"   r#   r[   r`   ra   rb   rc   r^   rd   r   r   r    evaluate_tf)r$   rs   r:   r;   r%   r<   r=   r   r   rh   r'   ri   @py_format3r   r   r   s                   r/   Atest_evaluate_tf_never_pairs_one_assets_data_with_anothers_winnerzYTestGlobalPairingHazard.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
 '',,y#**T2BCGGLLC8M4NOww.w~~.~o........r...r...w...~......o...o..........ww0w~~0~/00000000r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O3333}O333333}333}333333O333O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 &v~vvvr1   c                    |j                  t        dddi       t        j                  dt              }d }||u }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }d	d
|iz  }t        t	        j                  |            d x}}y )Nr|   rQ   zdoes/not/exist.csv)assetr   r   r   r   r   r   )rr   r   r   r   r   r   r   r   r    r!   r"   r#   )r$   rs   r   r%   rh   r   r   s          r/   >test_evaluate_tf_ignores_tf_map_entirely_for_an_explicit_assetzVTestGlobalPairingHazard.test_evaluate_tf_ignores_tf_map_entirely_for_an_explicit_asset   s    CD2F+GH
 ];v~vvvr1   N)rE   rF   rG   rH   r   r   r   rN   r1   r/   rz   rz   T   s    
	=4r1   rz   )rH   builtinsr   _pytest.assertion.rewrite	assertionrewriter   r[   rI   tools.mlp_results_tablemlp_results_tabler   r`   abspathra   dirname__file__rb   r   r   rP   rz   rN   r1   r/   <module>r      sm   %L  	  %GGOOBGGLL)BDIJ	!& &&M M3 3r1   