feat(lotto): 티켓 생성 3전략 (engine_w/random_null/coverage)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,17 @@ from app import backtest as bt
|
|||||||
from app.analyzer import build_analysis_cache, score_combination
|
from app.analyzer import build_analysis_cache, score_combination
|
||||||
|
|
||||||
|
|
||||||
|
def _toy_draws(n=120):
|
||||||
|
# 결정적 가짜 회차: 분석 캐시 구성용 (오름차순 (drw_no, [6 nums]))
|
||||||
|
import random as _r
|
||||||
|
_r.seed(1)
|
||||||
|
out = []
|
||||||
|
for i in range(1, n + 1):
|
||||||
|
nums = sorted(_r.sample(range(1, 46), 6))
|
||||||
|
out.append((i, nums))
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
def test_grade_tickets_histogram_and_prizes():
|
def test_grade_tickets_histogram_and_prizes():
|
||||||
winning6 = [1, 2, 3, 4, 5, 6]
|
winning6 = [1, 2, 3, 4, 5, 6]
|
||||||
bonus = 7
|
bonus = 7
|
||||||
@@ -23,3 +34,26 @@ def test_grade_tickets_histogram_and_prizes():
|
|||||||
# 등수 매핑 헬퍼
|
# 등수 매핑 헬퍼
|
||||||
prizes = bt.prize_counts(r)
|
prizes = bt.prize_counts(r)
|
||||||
assert prizes == {"1st": 1, "2nd": 1, "3rd": 1, "4th": 1, "5th": 1}
|
assert prizes == {"1st": 1, "2nd": 1, "3rd": 1, "4th": 1, "5th": 1}
|
||||||
|
|
||||||
|
|
||||||
|
def test_purchase_tickets_distinct_and_count():
|
||||||
|
draws = _toy_draws()
|
||||||
|
cache = bt.build_analysis_cache(draws)
|
||||||
|
nw = bt.build_number_weights(cache)
|
||||||
|
pool = bt.generate_pool(cache, nw, n=2000, seed=7)
|
||||||
|
W = [0.25, 0.30, 0.20, 0.15, 0.10]
|
||||||
|
bought = bt.purchase_tickets(pool, cache, W, k=50)
|
||||||
|
assert len(bought) == 50
|
||||||
|
assert len({tuple(t) for t in bought}) == 50 # distinct
|
||||||
|
# W로 랭킹된 상위 → 평균 분석치가 풀 평균보다 높아야
|
||||||
|
avg_bought = sum(score_combination(t, cache, W)["score_total"] for t in bought) / 50
|
||||||
|
assert avg_bought > 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_random_null_and_coverage_distinct():
|
||||||
|
rnd = bt.random_null_tickets(k=50, seed=3)
|
||||||
|
assert len(rnd) == 50 and len({tuple(t) for t in rnd}) == 50
|
||||||
|
cov = bt.coverage_tickets(k=9, seed=3) # 9장 = 54슬롯 ≥ 45번호 전수 커버 가능
|
||||||
|
flat = {n for t in cov for n in t}
|
||||||
|
assert len(cov) == 9 and len({tuple(t) for t in cov}) == 9
|
||||||
|
assert len(flat) >= 40 # 커버리지 전략은 번호를 넓게 퍼뜨림
|
||||||
|
|||||||
Reference in New Issue
Block a user