import pandas as pd from scripts.search_factor_weight_grid import _grid_from_name, candidate_passes, search_weight_grid def _events(rows): return pd.DataFrame(rows) def test_candidate_passes_requires_accuracy_precision_signal_and_buy_cap(): baseline = {"accuracy": 50.0, "buy_precision": 60.0, "signal_count": 10, "buy_count": 5} candidate = {"accuracy": 53.0, "buy_precision": 61.0, "signal_count": 9, "buy_count": 6} deltas = { "accuracy_delta_pp": 3.0, "buy_precision_delta_pp": 1.0, "direction_accuracy_delta_pp": 0.0, } passed, gate = candidate_passes( baseline, candidate, deltas, min_accuracy_delta_pp=2.0, min_buy_precision_delta_pp=0.0, min_signal_ratio=0.7, max_buy_count_ratio=1.3, ) assert passed is True assert gate["buy_count_ratio"] == 1.2 def test_search_weight_grid_finds_passing_weight_combination(): rows = [] for i in range(12): rows.append( { "stock": "2330", "date": f"2025-04-{i + 1:02d}", "y_true": 1 if i in {0, 1, 2, 6, 7, 8} else 0, "base_pred": 1 if i in {0, 1, 6} else 0, "p_buy": 0.52 if i in {0, 1, 6} else 0.48, "p_hold": 0.51 if i not in {0, 1, 6} else 0.44, "p_sell": 0.01, "bull_score": 3.0 if i in {2, 7, 8} else 0.0, "bear_score": 0.0, } ) result = search_weight_grid( _events(rows), optimize_ratio=0.5, min_accuracy_delta_pp=20.0, min_buy_precision_delta_pp=0.0, min_signal_ratio=0.7, max_buy_count_ratio=3.0, top_n=5, grid={ "buy_bull_weight": [0.0, 0.02], "buy_bear_weight": [0.0], "sell_bear_weight": [0.0], "sell_bull_weight": [0.0], "buy_bear_gate": [None], "sell_bull_gate": [None], "hold_bias": [0.0], }, ) assert result["grid_size"] == 2 assert result["passing_count"] == 1 assert result["best_passing"]["config"]["buy_bull_weight"] == 0.02 assert result["best_passing"]["validation"]["deltas"]["accuracy_delta_pp"] > 0 def test_volume_fine_grid_is_available_for_volume_factor_search(): grid = _grid_from_name("volume_fine") assert 0.08 in grid["buy_bull_weight"] assert -0.005 in grid["buy_bear_weight"] assert 0.005 in grid["sell_bear_weight"]