feat: 彩票技能统一输出格式 - 双色球/大乐透4块结构化输出标准对齐

- 新增 model_full_report_dlt.py: 大乐透专用全量报告脚本
- 统一4块结构: 回滚迭代→数据采集→推理分析→机选号码
- 统一术语: 前区/后区(大乐透) 对齐 红球/蓝球(双色球)
- 统一评分: TOP10前区+TOP5后区 归一化概率输出
- 更新 SKILL.md: 双色球/大乐透统一模板+文件结构
This commit is contained in:
CodeForge committed 2026-07-30 06:04:12 +00:00
1 parent f45881dc88
commit c4bb8632ca
15 files changed
+9932

No files matched your search

+300
View File
@@ -0,0 +1,300 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
新模型集成入口:替代 lottery_tool.py 的 full_report
保持4块结构化输出,推理分析和机选号码使用6阶段数学模型
"""
import json, math, os, datetime, hashlib, random, re, sys
from collections import Counter
import numpy as np
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(BASE_DIR, "data")
OUTPUT_DIR = os.path.join(BASE_DIR, "model_output")
SSQ_FILE = os.path.join(DATA_DIR, "ssq_history.json")
FEEDBACK_FILE = os.path.join(DATA_DIR, "feedback.json")
CONFIG_FILE = os.path.join(DATA_DIR, "config.json")
# ================================================================
# 加载数据和模型参数
# ================================================================
data = json.load(open(SSQ_FILE, "r", encoding="utf-8"))
records = []
historical_combos = set()
for r in data:
reds = sorted([int(x) for x in r["reds"]])
blue = int(r["blue"])
if len(reds) == 6 and all(1 <= n <= 33 for n in reds) and 1 <= blue <= 16:
records.append({"issue": r["issue"], "reds": reds, "blue": blue, "date": r.get("date", "")})
historical_combos.add(tuple(reds))
records.sort(key=lambda x: int(x["issue"]))
N = len(records)
latest = records[-1]
# 加载模型参数
mp_file = os.path.join(OUTPUT_DIR, "model_parameters.json")
if os.path.exists(mp_file):
mp = json.load(open(mp_file, "r"))
MODEL_VERSION = "v1.0_6phase"
else:
mp = None
MODEL_VERSION = "v1.0_legacy"
# ================================================================
# 加载回滚统计
# ================================================================
config = json.load(open(CONFIG_FILE, "r")) if os.path.exists(CONFIG_FILE) else {"iteration_count": 0}
feedback = json.load(open(FEEDBACK_FILE, "r")) if os.path.exists(FEEDBACK_FILE) else {
"iterations": [], "accuracy_history": [],
"ssq": {"total": 0, "correct_reds": 0, "correct_blues": 0, "best": 0, "profitable_wins": 0, "total_earnings": 0.0}
}
# ================================================================
# 计算下期信息
# ================================================================
prev_issue = latest["issue"]
prev_date = latest.get("date", "")
prev_reds = latest["reds"]
prev_blue = latest["blue"]
next_issue = str(int(prev_issue) + 1)
today = datetime.datetime.now()
draw_days = [2, 4, 7] # 周二、四、日
draw_time = "21:15"
draw_hour, draw_min = map(int, draw_time.split(":"))
now_hour, now_min = today.hour, today.minute
today_draw = today.isoweekday() in draw_days
time_past = (now_hour > draw_hour) or (now_hour == draw_hour and now_min >= draw_min)
if today_draw and not time_past:
delta = 0
else:
delta = 1
while (today + datetime.timedelta(days=delta)).isoweekday() not in draw_days:
delta += 1
next_draw = today + datetime.timedelta(days=delta)
next_draw_str = next_draw.strftime("%Y-%m-%d")
wd_map = {1:"周一",2:"周二",3:"周三",4:"周四",5:"周五",6:"周六",7:"周日"}
next_wd = wd_map.get(next_draw.isoweekday(), "")
# ================================================================
# 4块输出
# ================================================================
print("\n" + "=" * 60)
print(" [1/4] 回滚迭代")
print("=" * 60)
ver = config.get("iteration_count", 0)
stats = feedback.get("ssq", {})
total_recs = stats.get("total", 0)
profitable = stats.get("profitable_wins", 0)
win_rate = "%.1f%%" % (profitable / total_recs * 100) if total_recs > 0 else "0.0%"
earnings = stats.get("total_earnings", 0.0)
print(" 当前版本号: %s (第6阶段数学建模)" % MODEL_VERSION)
print(" 版本胜率: %s (%d期推荐 / %d次盈利)" % (win_rate, total_recs, profitable))
print(" 累计中奖收益金额: RMB %.2f" % earnings)
# ==================== 第2块:数据采集 ====================
print("\n" + "=" * 60)
print(" [2/4] 数据采集")
print("=" * 60)
print(" 采集期数范围: 第%s期 ~ 第%s期(%d期)" % (records[0]["issue"], prev_issue, N))
print(" 上一期号: 第%s期" % prev_issue)
print(" 开奖日期: %s" % prev_date)
r_str = " ".join("%02d" % n for n in prev_reds)
print(" 开奖号码: 红球 %s 蓝球 %02d" % (r_str, prev_blue))
# ==================== 第3块:推理分析 ====================
print("\n" + "=" * 60)
print(" [3/4] 推理分析(%s | 数据源: 500.com)" % MODEL_VERSION)
print("=" * 60)
if mp:
# --- 6阶段模型输出 ---
p3 = mp["phase3_params"]
p4 = mp["phase4_params"]
p5 = mp["phase5_params"]
# 步骤1: 贝叶斯后验概率 TOP10
red_post = {int(k): float(v) for k, v in p3["red_posterior"].items()}
top10 = sorted(red_post.items(), key=lambda x: -x[1])[:10]
print(" >> 步骤1 - 贝叶斯后验概率: TOP10红球")
print(" %s" % " ".join("%02d(%.4f)" % (n, s) for n, s in top10))
# 步骤2: 蓝球后验 TOP5
blue_post = {int(k): float(v) for k, v in p3["blue_posterior"].items()}
top5b = sorted(blue_post.items(), key=lambda x: -x[1])[:5]
print(" >> 步骤2 - 蓝球后验概率: TOP5蓝球")
print(" %s" % " ".join("%02d(%.4f)" % (n, s) for n, s in top5b))
# 步骤3: 聚类分组
candidate = p4["candidate_pool"]
eliminated = p4["eliminated"]
print(" >> 步骤3 - K-Means聚类降维")
print(" K=%d | 轮廓系数=%.4f" % (p4["red_k"], p4["red_silhouette"]))
print(" 核心候选池(%d个): %s" % (len(candidate), " ".join("%02d" % n for n in candidate[:15]) + ("..." if len(candidate) > 15 else "")))
# 步骤4: 权重体系
sw = p5["objective_weights"]
print(" >> 步骤4 - 综合得分权重体系(6阶段数学模型)")
print(" Score = %.1f×后验 + %.1f×泊松 + %.1f×伽马遗漏" % (sw["w1_posterior"], sw["w2_poisson"], sw["w3_gamma"]))
print(" 方法链路: 泊松频次→负二项/伽马拟合→贝叶斯后验→K-Means→ILP约束求解")
else:
print(" [⚠️ 新模型参数未加载,使用基础统计]")
# ==================== 第4块:机选号码 ====================
print("\n" + "=" * 60)
print(" [4/4] 机选号码(第%s期 | %s %s)" % (next_issue, next_draw_str, next_wd))
print("=" * 60)
if mp:
# --- 6阶段模型推荐 ---
w1 = p3["score_weights"]["alpha1_posterior"]
w2 = p3["score_weights"]["alpha2_poisson"]
w3 = p3["score_weights"]["alpha3_miss"]
red_freq = {int(k): v["freq"] for k, v in mp["phase1_params"]["red_freq"].items()}
lam = mp["phase1_params"]["poisson_lambda_red"]
# 泊松权重
red_poisson = {}
for n in range(1, 34):
k = red_freq.get(n, 0)
log_p = k * math.log(lam) - lam
for i in range(1, k + 1):
log_p -= math.log(i)
red_poisson[n] = math.exp(log_p)
total_pois = sum(red_poisson.values())
red_poisson = {n: v / total_pois for n, v in red_poisson.items()}
# 遗漏权重
red_miss = mp["phase1_params"]["red_miss"]
red_gamma = {}
for n in range(1, 34):
miss = red_miss.get(str(n), {"avg_miss": 5, "last_miss": 0})
avg = miss["avg_miss"]
last = miss["last_miss"]
red_gamma[n] = min(1.0, last / (avg * 2)) if avg > 0 else 0.5
total_gam = sum(red_gamma.values())
red_gamma = {n: v / total_gam for n, v in red_gamma.items()}
# 综合得分
red_score = {}
for n in range(1, 34):
red_score[n] = w1 * red_post[n] + w2 * red_poisson[n] + w3 * red_gamma[n]
# 蓝球得分
blue_freq = {int(k): v["freq"] for k, v in mp["phase1_params"]["blue_freq"].items()}
lam_b = mp["phase1_params"]["poisson_lambda_blue"]
blue_poisson = {}
for n in range(1, 17):
k = blue_freq.get(n, 0)
log_p = k * math.log(lam_b) - lam_b
for i in range(1, k + 1):
log_p -= math.log(i)
blue_poisson[n] = math.exp(log_p)
total_pois_b = sum(blue_poisson.values())
blue_poisson = {n: v / total_pois_b for n, v in blue_poisson.items()}
blue_score = {}
for n in range(1, 17):
blue_score[n] = w1 * blue_post[n] + w2 * blue_poisson[n] + w3 * 0.5
# 约束检查
constraints = p5["constraints"]
def check_constraints(combo):
odd = sum(1 for n in combo if n % 2 == 1)
if not (constraints["odd_even"]["min_odd"] <= odd <= constraints["odd_even"]["max_odd"]):
return False
big = sum(1 for n in combo if n > 16)
if not (constraints["big_small"]["min_big"] <= big <= constraints["big_small"]["max_big"]):
return False
consec = sum(1 for i in range(len(combo) - 1) if combo[i + 1] - combo[i] == 1)
if not (constraints["consecutive"]["min_consec"] <= consec <= constraints["consecutive"]["max_consec"]):
return False
s = sum(combo)
if not (constraints["sum_range"]["min_sum"] <= s <= constraints["sum_range"]["max_sum"]):
return False
hot = sum(1 for n in combo if red_score[n] > 0.03)
if not (constraints["hot_cold"]["min_hot"] <= hot <= constraints["hot_cold"]["max_hot"]):
return False
z1 = sum(1 for n in combo if 1 <= n <= 11)
z2 = sum(1 for n in combo if 12 <= n <= 22)
z3 = sum(1 for n in combo if 23 <= n <= 33)
if not all(constraints["zone_balance"]["min_zone"] <= z <= constraints["zone_balance"]["max_zone"] for z in [z1, z2, z3]):
return False
if tuple(combo) in historical_combos:
return False
return True
# 生成推荐
import itertools
sorted_nums = sorted(range(1, 34), key=lambda n: -red_score[n])
best_combos = []
seed = hashlib.md5(("6phase_ssq_%s" % prev_issue).encode()).hexdigest()
rng = random.Random(seed)
for _ in range(30000):
weights = np.array([red_score[n] for n in range(1, 34)])
weights = weights / weights.sum()
selected = np.random.choice(range(1, 34), size=6, replace=False, p=weights)
combo = sorted(selected.tolist())
if check_constraints(combo):
score = sum(red_score[n] for n in combo)
if len(best_combos) < 10 or score > best_combos[-1][0]:
best_combos.append((score, combo))
best_combos.sort(key=lambda x: -x[0])
if len(best_combos) > 10:
best_combos = best_combos[:10]
for combo in itertools.combinations(sorted_nums[:15], 6):
combo_list = sorted(list(combo))
if check_constraints(combo_list):
score = sum(red_score[n] for n in combo_list)
if len(best_combos) < 10 or score > best_combos[-1][0]:
best_combos.append((score, combo_list))
best_combos.sort(key=lambda x: -x[0])
if len(best_combos) > 10:
best_combos = best_combos[:10]
seen = set()
unique = []
for s, c in best_combos:
if tuple(c) not in seen:
seen.add(tuple(c))
unique.append((s, c))
results = unique[:5]
blue_ranked = sorted(blue_score.items(), key=lambda x: -x[1])[:3]
primary_blue = blue_ranked[0][0]
for i, (score, combo) in enumerate(results):
r_str = " ".join("%02d" % n for n in combo)
odd = sum(1 for n in combo if n % 2 == 1)
big = sum(1 for n in combo if n > 16)
s = sum(combo)
marker = " ⭐" if i == 0 else ""
print("\n 第%d组: 红球 %s 蓝球 %02d%s" % (i + 1, r_str, primary_blue, marker))
print(" 得分:%.4f | 奇偶:%d:%d | 大小:%d:%d | 和:%d" % (
score, odd, 6 - odd, big, 6 - big, s))
# 保存推荐
analysis = json.load(open(os.path.join(DATA_DIR, "analysis_ssq.json"), "r")) if os.path.exists(os.path.join(DATA_DIR, "analysis_ssq.json")) else {}
analysis["last_recommendation"] = {
"reds": results[0][1],
"blues": [primary_blue],
"generated_at": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"model_version": MODEL_VERSION
}
json.dump(analysis, open(os.path.join(DATA_DIR, "analysis_ssq.json"), "w"), ensure_ascii=False, indent=2)
else:
print(" [⚠️ 新模型未加载,请先运行 model_phase1~6.py 训练模型]")
print("\n" + "=" * 60)
print(" ⚠️ 免责声明: 本推荐仅基于历史统计建模的相对概率评分,")
print(" 不预测下期开奖,不保证中奖。彩票是独立随机事件。")
print("=" * 60)
print("\n 开奖后把实际号码发我,帮你回滚迭代校正精度 🍀")