refactor: apply portfolio cap and align project docs

Keep the fixed 11-number set intact while adding a second-stage portfolio selection that caps final recommendations to the 70,000 KRW budget, and update docs/data/scripts to match the current project structure and runtime flow.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-08 10:37:03 +09:00
parent bd9eea2aee
commit 919f2e19bb
11 changed files with 492 additions and 343 deletions

View File

@@ -1,10 +1,10 @@
import json
from collections import Counter
import socket
import numpy as np
import pandas as pd
from final_filter_params import TRAIN_ALLOW
socket.getaddrinfo(socket.gethostname(), None)
class BallFilter:
history_ball_dict = None
@@ -16,39 +16,15 @@ class BallFilter:
compositeNumber = None
def __init__(self, lottoHistoryFileName=None):
if lottoHistoryFileName is None:
return
self.history_ball_list = []
self.history_ball_no_ymd = {}
self.history_ball_no_dict = {}
self.history_ball_date_dict = {}
self.history_ball_dict = {}
path = str(lottoHistoryFileName)
if path.endswith('.txt'):
rows = []
with open(path, 'r', encoding='utf-8') as in_fp:
for line in in_fp:
line = line.strip()
if not line:
continue
parts = line.split(',')
drw_no = int(parts[0])
balls = [int(parts[i]) for i in range(1, 7)]
rows.append((drw_no, balls))
rows.sort(key=lambda x: x[0])
for drw_no, balls in rows:
sb = sorted(balls)
self.history_ball_list.append(sb)
self.history_ball_no_dict[str(sb)] = drw_no
ymd_key = f'{drw_no:08d}'
self.history_ball_date_dict[ymd_key] = drw_no
self.history_ball_dict[drw_no] = {'date': '', 'ball': list(sb)}
self.history_ball_no_ymd[drw_no] = ymd_key
else:
in_fp = open(path, 'r', encoding='utf-8')
if lottoHistoryFileName is not None:
inFp = open(lottoHistoryFileName, 'r', encoding='utf-8')
self.history_ball_list = []
self.history_ball_no_ymd = {}
self.history_ball_no_dict = {}
self.history_ball_date_dict = {}
self.history_ball_dict = {}
while True:
line = in_fp.readline()
line = inFp.readline()
if not line or line == '\n':
break
data = json.loads(line)
@@ -56,27 +32,28 @@ class BallFilter:
self.history_ball_no_dict[str(self.history_ball_list[len(self.history_ball_list) - 1])] = data['drwNo']
self.history_ball_date_dict[data['drwNoDate'].replace('-', '')] = data['drwNo']
self.history_ball_dict[data['drwNo']] = {'date': data['drwNoDate'], 'ball': [data['drwtNo1'], data['drwtNo2'], data['drwtNo3'], data['drwtNo4'], data['drwtNo5'], data['drwtNo6']]}
self.history_ball_no_ymd[data['drwNo']] = data['drwNoDate'].replace('-', '')
in_fp.close()
self.history_ball_no_ymd[data['drwNo']] = data['drwNoDate'].replace('-','')
inFp.close()
ball_avg = {}
ball_sum = {}
for i in range(len(self.history_ball_list)):
win_ball = list(self.history_ball_list[-i])
avg = sum(win_ball) / 6
if avg not in ball_avg:
ball_avg[avg] = 1
else:
ball_avg[avg] += 1
# ball 평균과 합 구하기
ball_avg = {}
ball_sum = {}
for i in range(len(self.history_ball_list)):
WIN_BALL = list(self.history_ball_list[-i])
avg = sum(WIN_BALL) / 6
if avg not in ball_avg:
ball_avg[avg] = 1
else:
ball_avg[avg] += 1
s = sum(self.history_ball_list[-i])
if s in ball_sum:
ball_sum[s] += 1
else:
ball_sum[s] = 1
if sum(self.history_ball_list[-i]) in ball_sum:
ball_sum[sum(self.history_ball_list[-i])] += 1
else:
ball_sum[sum(self.history_ball_list[-i])] = 1
self.primeNumber = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43]
self.compositeNumber = [4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, 36, 38, 39, 40, 42, 44, 45]
self.primeNumber = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43]
self.compositeNumber = [4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, 36, 38, 39, 40, 42, 44, 45]
return
def getBall(self, no):
@@ -808,6 +785,7 @@ class BallFilter:
return len(low), len(high)
def filterOneDigitPattern(self, ball):
ball = [8, 18, 22, 31, 40, 44]
digit = set()
for b in ball:
if b % 10 not in digit:
@@ -3839,7 +3817,6 @@ class BallFilter:
p_ball = p_ball[1:7]
filter_set = set()
A = TRAIN_ALLOW
### S: 이전 당첨 번호
if no is not None:
@@ -3852,7 +3829,7 @@ class BallFilter:
### S: 당첨번호 6개 합
acc = sum(ball)
if acc not in A.sum6:
if acc not in {112,114,121,123,126,127,131,132,138,146,148,156,154,163,165,167,172,174,183}:
filter_set.add('6개 합: {}'.format(acc))
if not until_end:
return filter_set
@@ -3860,7 +3837,8 @@ class BallFilter:
### E: 당첨번호 6개 합
### S: 당첨번호 6개 합에 대한 전주와 차이
if abs(acc - p_acc) not in A.abs_sum_diff:
if abs(acc - p_acc) not in {2,3,4,6,7,8,9,10,11,12,13,14,15,17,18,24,25,26,27,28,29,30,31,32,33,34,39,40,51}:
# 첫수와 끝수의 합에 대해서 전주 금주의 차이
filter_set.add('6개 합 전주차: {}'.format(abs(acc - p_acc)))
if not until_end:
return filter_set
@@ -4331,6 +4309,7 @@ class BallFilter:
if not until_end:
return filter_set
### E: 홀짝 개수에 대한 전주와 차이
### S: 용지에 안나올 것 같은 마킹 위치 (filterPatternInPaper1~filterPatternInPaper6)
v1 = self.filterPatternInPaper1(ball)
v2 = self.filterPatternInPaper2(ball)