Files
CodeForge c4bb8632ca feat: 彩票技能统一输出格式 - 双色球/大乐透4块结构化输出标准对齐
- 新增 model_full_report_dlt.py: 大乐透专用全量报告脚本
- 统一4块结构: 回滚迭代→数据采集→推理分析→机选号码
- 统一术语: 前区/后区(大乐透) 对齐 红球/蓝球(双色球)
- 统一评分: TOP10前区+TOP5后区 归一化概率输出
- 更新 SKILL.md: 双色球/大乐透统一模板+文件结构
2026-07-30 06:04:12 +00:00

301 lines
12 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 开奖后把实际号码发我,帮你回滚迭代校正精度 🍀")