#!/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 开奖后把实际号码发我,帮你回滚迭代校正精度 🍀")