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

@@ -0,0 +1,259 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
大乐透全量报告:与双色球 model_full_report.py 统一4块结构化输出
使用集成学习模型(5模型融合),输出格式与双色球完全对齐
"""
import json, math, os, datetime, hashlib, random, sys, io
from collections import Counter
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")
DLT_FILE = os.path.join(DATA_DIR, "dlt_history.json")
FEEDBACK_FILE = os.path.join(DATA_DIR, "feedback.json")
CONFIG_FILE = os.path.join(DATA_DIR, "config.json")
# ================================================================
# 加载数据
# ================================================================
data = json.load(open(DLT_FILE, "r", encoding="utf-8"))
records = []
historical_combos = set()
for r in data:
fronts = sorted([int(x) for x in r["reds"]])
backs = sorted([int(x) for x in r["blue"]]) if isinstance(r["blue"], list) else [int(r["blue"])]
if len(fronts) == 5 and all(1 <= n <= 35 for n in fronts) and len(backs) == 2 and all(1 <= n <= 12 for n in backs):
records.append({"issue": r["issue"], "fronts": fronts, "backs": backs, "date": r.get("date", "")})
historical_combos.add(tuple(fronts))
records.sort(key=lambda x: int(x["issue"]))
N = len(records)
latest = records[-1]
# ================================================================
# 加载回滚统计
# ================================================================
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},
"dlt": {"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_fronts = latest["fronts"]
prev_backs = latest["backs"]
next_issue = str(int(prev_issue) + 1)
today = datetime.datetime.now()
draw_days = [1, 3, 6] # 周一、三、六
draw_time = "20:25"
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(), "")
# ================================================================
# 基础统计分析(与双色球贝叶斯后验对齐)
# ================================================================
# 前区频率统计
all_fronts = []
for r in records:
all_fronts.extend(r["fronts"])
front_freq = Counter(all_fronts)
total_fronts = len(all_fronts)
front_probs = {n: front_freq.get(n, 0) / total_fronts for n in range(1, 36)}
# 后区频率统计
all_backs = []
for r in records:
all_backs.extend(r["backs"])
back_freq = Counter(all_backs)
total_backs = len(all_backs)
back_probs = {n: back_freq.get(n, 0) / total_backs for n in range(1, 13)}
# 前区遗漏统计
front_last_seen = {n: 0 for n in range(1, 36)}
for i, r in enumerate(reversed(records)):
for n in r["fronts"]:
if front_last_seen[n] == 0:
front_last_seen[n] = i
# 后区遗漏统计
back_last_seen = {n: 0 for n in range(1, 13)}
for i, r in enumerate(reversed(records)):
for n in r["backs"]:
if back_last_seen[n] == 0:
back_last_seen[n] = i
# 综合评分 = 频率权重 × 0.4 + 遗漏回补 × 0.3 + 近期热度 × 0.3
front_scores = {}
for n in range(1, 36):
freq_score = front_probs.get(n, 0)
miss_score = min(1.0, front_last_seen[n] / 20) # 遗漏越大,回补概率越高
# 近期热度:最近10期出现次数
recent_count = sum(1 for r in records[-10:] if n in r["fronts"])
hot_score = recent_count / 10
front_scores[n] = 0.4 * freq_score + 0.3 * miss_score + 0.3 * hot_score
back_scores = {}
for n in range(1, 13):
freq_score = back_probs.get(n, 0)
miss_score = min(1.0, back_last_seen[n] / 15)
recent_count = sum(1 for r in records[-10:] if n in r["backs"])
hot_score = recent_count / 10
back_scores[n] = 0.4 * freq_score + 0.3 * miss_score + 0.3 * hot_score
# 归一化
total_front_score = sum(front_scores.values())
front_probs_norm = {n: s / total_front_score for n, s in front_scores.items()}
total_back_score = sum(back_scores.values())
back_probs_norm = {n: s / total_back_score for n, s in back_scores.items()}
# ================================================================
# 加载集成学习模块(抑制中间输出)
# ================================================================
sys.path.insert(0, BASE_DIR)
HAS_ENSEMBLE = False
ensemble_result = None
try:
# 临时重定向stdout以抑制集成学习的中间输出
old_stdout = sys.stdout
sys.stdout = io.StringIO()
from ensemble_learning import ensemble_recommendation
rule = {"name": "大乐透", "red_max": 35, "red_count": 5, "blue_max": 12, "blue_count": 2,
"draw_days": [1, 3, 6], "draw_time": "20:25", "source": "中国体育彩票"}
sorted_hist = sorted(records, key=lambda x: int(x["issue"]), reverse=True)[:100]
hist_for_ensemble = [{"issue": r["issue"], "reds": r["fronts"], "blue": r["backs"], "date": r.get("date", "")} for r in sorted_hist]
ensemble_result = ensemble_recommendation("dlt", hist_for_ensemble, rule, count=5)
sys.stdout = old_stdout
if ensemble_result and ensemble_result.get("recommendations"):
HAS_ENSEMBLE = True
except Exception as e:
sys.stdout = old_stdout
pass
# ================================================================
# 4块输出(与双色球统一格式)
# ================================================================
print("\n" + "=" * 60)
print(" [1/4] 回滚迭代")
print("=" * 60)
ver = config.get("iteration_count", 0)
stats = feedback.get("dlt", {})
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(" 当前版本号: v%d (集成学习模型)" % ver)
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)
f_str = " ".join("%02d" % n for n in prev_fronts)
b_str = " ".join("%02d" % n for n in prev_backs)
print(" 开奖号码: 前区 %s 后区 %s" % (f_str, b_str))
# ==================== 第3块:推理分析 ====================
print("\n" + "=" * 60)
print(" [3/4] 推理分析(集成学习模型 | 数据源: 中国体育彩票)")
print("=" * 60)
# 步骤1: 前区频率分析 TOP10(与双色球"贝叶斯后验概率 TOP10红球"对齐)
top10_front = sorted(front_probs_norm.items(), key=lambda x: -x[1])[:10]
print(" >> 步骤1 - 频率分析(前区TOP10)")
print(" %s" % " ".join("%02d(%.4f)" % (n, s) for n, s in top10_front))
# 步骤2: 后区分析 TOP5
top5_back = sorted(back_probs_norm.items(), key=lambda x: -x[1])[:5]
print(" >> 步骤2 - 后区分析(TOP5)")
print(" %s" % " ".join("%02d(%.4f)" % (n, s) for n, s in top5_back))
# 步骤3: 模式识别
print(" >> 步骤3 - 模式识别")
# 统计历史奇偶比和大小比
oe_counter = Counter()
bs_counter = Counter()
for r in records[-30:]:
odd = sum(1 for n in r["fronts"] if n % 2 == 1)
even = 5 - odd
oe_counter[f"{odd}:{even}"] += 1
big = sum(1 for n in r["fronts"] if n > 17)
small = 5 - big
bs_counter[f"{big}:{small}"] += 1
most_oe = oe_counter.most_common(1)[0][0] if oe_counter else "3:2"
most_bs = bs_counter.most_common(1)[0][0] if bs_counter else "3:2"
sum_min = min(r["fronts"][0] + r["fronts"][1] for r in records[-30:])
sum_max = max(sum(r["fronts"]) for r in records[-30:])
print(" 奇偶比: %s | 大小比: %s | 和值区间: [%d, %d]" % (most_oe, most_bs, sum_min, sum_max))
# 步骤4: 权重体系
print(" >> 步骤4 - 权重体系(集成学习模型)")
if HAS_ENSEMBLE and ensemble_result.get("weights"):
weights = ensemble_result["weights"]
name_map = {'freq': '频率加权', 'bayes': '贝叶斯平滑', 'markov': '马尔可夫链',
'kmeans': 'K-Means聚类', 'residual': '残差回归'}
weight_parts = []
for m, w in sorted(weights.items(), key=lambda x: -x[1]):
weight_parts.append("%s%.2f%%" % (name_map.get(m, m), w * 100))
print(" %s" % " + ".join(weight_parts))
else:
print(" 频率40% + 遗漏30% + 热号30%")
# ==================== 第4块:机选号码 ====================
print("\n" + "=" * 60)
print(" [4/4] 机选号码(第%s期 | %s %s)" % (next_issue, next_draw_str, next_wd))
print("=" * 60)
if HAS_ENSEMBLE and ensemble_result.get("recommendations"):
recommendations = ensemble_result["recommendations"]
for i, r in enumerate(recommendations):
f_str = " ".join("%02d" % n for n in r["reds"])
b_str = " ".join("%02d" % n for n in r["blues"])
marker = " ⭐" if i == 0 else ""
print("\n 第%d组: 前区 %s 后区 %s%s" % (i + 1, f_str, b_str, marker))
print(" 得分:%.4f | 奇偶:%s | 大小:%s | 和:%d" % (
r["score"], r["odd_even"], r["big_small"], r["sum"]))
# 保存推荐
analysis_file = os.path.join(DATA_DIR, "analysis_dlt.json")
analysis = json.load(open(analysis_file, "r")) if os.path.exists(analysis_file) else {}
analysis["last_recommendation"] = {
"fronts": recommendations[0]["reds"],
"backs": recommendations[0]["blues"],
"generated_at": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"model_version": "ensemble_v7"
}
json.dump(analysis, open(analysis_file, "w"), ensure_ascii=False, indent=2)
else:
print(" [⚠️ 无法生成推荐,请检查数据]")
print("\n" + "=" * 60)
print(" ⚠️ 免责声明: 本推荐仅基于历史统计建模的相对概率评分,")
print(" 不预测下期开奖,不保证中奖。彩票是独立随机事件。")
print("=" * 60)
print("\n 开奖后把实际号码发我,帮你回滚迭代校正精度 🍀")