import json import numpy as np import pandas as pd from scripts.run_ml_method_ladder import ( _date_group_sizes, _ranking_metrics, _ranker_relevance, _split_panel, build_sequence_features, render_html_report, ) def test_build_sequence_features_uses_current_and_prior_rows_only(): df = pd.DataFrame( { "close": [10, 11, 12, 11, 13, 14, 15, 15, 16, 18, 19, 20], "high": [11, 12, 13, 12, 14, 15, 16, 16, 17, 19, 20, 21], "low": [9, 10, 11, 10, 12, 13, 14, 14, 15, 17, 18, 19], "volume": [100, 110, 120, 130, 140, 160, 180, 190, 200, 220, 240, 260], } ) seq = build_sequence_features(df) assert "seq_ret_5_sum" in seq assert "seq_sax_up_ratio_10" in seq assert len(seq) == len(df) assert np.isfinite(seq.to_numpy()).all() def test_split_panel_embargoes_label_horizon_between_train_and_validation(): rows = [] for stock in ["2330", "2454"]: for idx in range(180): rows.append( { "stock": stock, "date": f"2026-01-{(idx % 28) + 1:02d}", "row_idx": idx, "label": 1 if idx % 3 == 0 else 0, "f": float(idx), } ) panel = pd.DataFrame(rows) train, valid, split = _split_panel(panel, train_ratio=0.7) assert not train.empty assert not valid.empty for stock, info in split["stocks"].items(): assert info["validation_start_idx"] - info["train_end_idx"] > 1 assert train[train["stock"] == stock]["row_idx"].max() < valid[valid["stock"] == stock]["row_idx"].min() def test_ranking_metrics_scores_top_k_hits_by_date(): frame = pd.DataFrame( { "date": ["2026-01-01"] * 4 + ["2026-01-02"] * 4, "stock": list("ABCDEFGH"), "label": [1, 0, -1, 1, 0, 1, -1, 1], "p_buy": [0.9, 0.8, 0.1, 0.2, 0.2, 0.95, 0.1, 0.8], "pred": [1, 1, -1, 0, 0, 1, -1, 1], } ) metrics = _ranking_metrics(frame, top_k=2) assert metrics["dates"] == 2 assert metrics["hit_rate"] == 75.0 def test_ranker_helpers_build_date_groups_and_non_negative_relevance(): frame = pd.DataFrame( { "date": ["2026-01-01", "2026-01-01", "2026-01-02"], "label": [-1, 0, 1], } ) assert _date_group_sizes(frame) == [2, 1] assert _ranker_relevance(frame["label"]).to_list() == [0, 1, 2] def test_render_html_report_contains_method_rows(): payload = { "generated_at": "2026-05-21T00:00:00+00:00", "stocks": ["2330"], "split": {"validation_date_range": ["2026-01-01", "2026-02-01"]}, "methods": { "panel_global_model": { "baseline": {"accuracy": 40, "up_precision": 50}, "candidate": {"accuracy": 44, "up_precision": 51, "n_signals": 10}, "deltas": {"accuracy_delta_pp": 4, "up_precision_delta_pp": 1}, "gate": {"passed": True}, }, "ranking_from_panel": {"ranking": {"baseline": {}, "candidate": {}, "deltas": {}}}, }, } html = render_html_report(payload) assert "ML Method Ladder Validation" in html assert "panel_global_model" in html assert "PASS" in html