diff --git a/lotto/app/backtest.py b/lotto/app/backtest.py index b0c838b..0b73392 100644 --- a/lotto/app/backtest.py +++ b/lotto/app/backtest.py @@ -91,6 +91,20 @@ def point_in_time_draws(draws: List[Tuple[int, List[int]]], return [(d, nums) for d, nums in draws if d < target_draw_no] +def calibrate_winner_compute(draws, target_draw_no, winning6, + sample_m: int = 2000, seed: Optional[int] = None) -> Dict[str, Any]: + """순수 연산: point-in-time 캐시로 당첨조합 채점 + 무작위 M표본 percentile.""" + pit = point_in_time_draws(draws, target_draw_no) + cache = build_analysis_cache(pit) + scores = score_combination(sorted(winning6), cache) + win_total = scores["score_total"] + samples = random_null_tickets(sample_m, seed=seed) + le = sum(1 for t in samples + if score_combination(t, cache)["score_total"] <= win_total) + percentile = le / max(len(samples), 1) + return {"scores": scores, "percentile": percentile, "cache_draws": len(pit)} + + def coverage_tickets(k: int, seed: Optional[int] = None) -> List[List[int]]: """greedy 커버리지 — 아직 덜 쓰인 번호를 우선 배치해 번호를 넓게 분산. (휠링/보장설계는 향후. 현재는 distinct + 번호 사용 균등화)""" diff --git a/lotto/tests/test_backtest.py b/lotto/tests/test_backtest.py index 0972492..517aa3f 100644 --- a/lotto/tests/test_backtest.py +++ b/lotto/tests/test_backtest.py @@ -68,6 +68,17 @@ def test_point_in_time_excludes_target_draw(): assert len(pit) == 29 +def test_calibrate_winner_scores_and_percentile(): + draws = _toy_draws(60) + winning6 = [3, 11, 19, 27, 35, 44] + res = bt.calibrate_winner_compute(draws, target_draw_no=60, + winning6=winning6, sample_m=500, seed=9) + assert set(res["scores"].keys()) >= {"score_total", "score_frequency", + "score_fingerprint", "score_gap", "score_cooccur", "score_diversity"} + assert 0.0 <= res["percentile"] <= 1.0 + assert res["cache_draws"] == 59 # 1..59 + + def test_generate_pool_partial_fill(monkeypatch): """weighted_sample_6이 항상 같은 조합만 반환하도록 패치 → cap에 먼저 걸려 len < n — 예외 없이 반환.""" import random as _r