feat: 彩票智能分析技能 v1.0 - 双色球/大乐透集成学习模型

This commit is contained in:
CodeForge committed 2026-07-15 02:56:14 +00:00
commit 56b02238ea
18 files changed
+8230

No files matched your search

+758
View File
@@ -0,0 +1,758 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
增强版彩票智能分析系统 v2.0
===============================
核心升级:
1. 采集近200期数据(原100期)
2. AI逐期回滚推演:从第200期开始->模拟分析机选->比对实开->回滚优化
3. 方法论自优化:每轮回滚后总结方法论并迭代升级
4. 目标:胜出率(概率占比) >= 51%
用法:
python enhanced_lottery.py --action full_report --lottery ssq --count 5
python enhanced_lottery.py --action rollback --lottery ssq
python enhanced_lottery.py --action self_evolve --lottery ssq --iterations 10
"""
import json, os, sys, math, random, copy, datetime
from collections import Counter
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(BASE_DIR, "data")
os.makedirs(DATA_DIR, exist_ok=True)
LOTTERY_RULES = {
"ssq": {
"name": "双色球",
"red_count": 6, "red_max": 33, "blue_count": 1, "blue_max": 16,
"draw_days": [2, 4, 7], "draw_time": "21:15",
},
"dlt": {
"name": "大乐透",
"red_count": 5, "red_max": 35, "blue_count": 2, "blue_max": 12,
"draw_days": [1, 3, 6], "draw_time": "20:25",
}
}
DEFAULT_WEIGHTS = {
"frequency": 0.25,
"hot_number": 0.20,
"missing": 0.15,
"tail": 0.10,
"zone": 0.08,
"odd_even": 0.06,
"big_small": 0.05,
"sum_value": 0.04,
"probability": 0.04,
"consecutive": 0.03,
}
# ============================================================
# 增强版分析引擎(200期 + 10维度深度分析)
# ============================================================
def _normalize_rec(rec):
"""标准化记录,兼容新旧格式(blue vs blues)"""
if "blues" not in rec or not rec["blues"]:
if "blue" in rec:
rec["blues"] = rec["blue"] if isinstance(rec["blue"], list) else [rec["blue"]]
return rec
def _get_blues(rec):
"""获取blue值,兼容新旧格式"""
if "blues" in rec and rec["blues"]:
raw = rec["blues"]
elif "blue" in rec:
raw = rec["blue"]
else:
raw = []
return raw if isinstance(raw, list) else [raw]
class EnhancedAnalyzer:
"""使用近200期数据,10维度权重可调,输出结构化分析结果"""
def __init__(self, data, lt, weights=None):
self.lt = lt
self.rule = LOTTERY_RULES[lt]
# 标准化并取近200期
normed = [_normalize_rec(d) for d in data]
self.data = sorted(normed, key=lambda x: int(x["issue"]), reverse=True)[:200]
self.weights = weights if weights else copy.deepcopy(DEFAULT_WEIGHTS)
self.rmax = self.rule["red_max"]
self.bmax = self.rule["blue_max"]
self.rcnt = self.rule["red_count"]
self.bcnt = self.rule["blue_count"]
self.mid = self.rmax / 2
def analyze(self):
"""完整分析,返回结构化分析结果"""
if not self.data:
return None
# 1. 频率分析
all_r, all_b = [], []
for rec in self.data:
all_r.extend(int(x) for x in rec["reds"])
bl = _get_blues(rec)
all_b.extend(int(x) for x in bl)
rf = Counter(all_r)
bf = Counter(all_b)
max_rf = max(rf.values()) or 1
max_bf = max(bf.values()) or 1
rf_score = {i: rf.get(i, 0) / max_rf for i in range(1, self.rmax + 1)}
bf_score = {i: bf.get(i, 0) / max_bf for i in range(1, self.bmax + 1)}
# 2. 热号分析(最近20期)
hot = self.data[:20]
hot_r = [int(x) for r in hot for x in r["reds"]]
hot_rf = Counter(hot_r)
max_hr = max(hot_rf.values()) or 1
hot_score = {i: hot_rf.get(i, 0) / max_hr for i in range(1, self.rmax + 1)}
# 3. 遗漏值分析
r_miss = {}
for n in range(1, self.rmax + 1):
cnt = 0
for r in self.data:
if n in [int(x) for x in r["reds"]]:
break
cnt += 1
r_miss[n] = cnt
max_rm = max(r_miss.values()) or 1
rm_score = {n: math.sin(m / max_rm * math.pi) * 0.8 + 0.2 for n, m in r_miss.items()}
b_miss = {}
for n in range(1, self.bmax + 1):
cnt = 0
for r in self.data:
ns = [int(x) for x in _get_blues(r)]
if n in ns:
break
cnt += 1
b_miss[n] = cnt
max_bm = max(b_miss.values()) or 1
bm_score = {n: math.sin(m / max_bm * math.pi) * 0.8 + 0.2 for n, m in b_miss.items()}
# 4. 奇偶模式
oe_counter = Counter()
for rec in self.data:
ns = [int(x) for x in rec["reds"]]
odd_count = sum(1 for n in ns if n % 2 == 1)
oe_counter[f"{odd_count}:{self.rcnt - odd_count}"] += 1
most_oe = oe_counter.most_common(1)[0][0] if oe_counter else "3:3"
# 5. 大小模式
bs_counter = Counter()
for rec in self.data:
ns = [int(x) for x in rec["reds"]]
big_count = sum(1 for n in ns if n > self.mid)
bs_counter[f"{big_count}:{self.rcnt - big_count}"] += 1
most_bs = bs_counter.most_common(1)[0][0] if bs_counter else "3:3"
# 6. 和值分析
sums = [sum(int(x) for x in r["reds"]) for r in self.data]
avg_sum = sum(sums) / len(sums) if sums else 0
std_sum = math.sqrt(sum((s - avg_sum) ** 2 for s in sums) / len(sums)) if sums else 0
# 7. 尾数分布
tail_counter = Counter()
for rec in self.data:
for ns in rec["reds"]:
tail_counter[int(ns) % 10] += 1
max_tf = max(tail_counter.values()) or 1
tail_score = {t: tail_counter.get(t, 0) / max_tf for t in range(10)}
# 8. 区间分布
zones = [(1, 11), (12, 22), (23, self.rmax)] if self.lt == "ssq" else [(1, 12), (13, 24), (25, self.rmax)]
zone_balance = []
for zs, ze in zones:
count = sum(1 for r in self.data for n in [int(x) for x in r["reds"]] if zs <= n <= ze)
expected = len(self.data) * self.rcnt / len(zones)
zone_balance.append(count / expected if expected else 1.0)
# 9. 连号分析
consec_counter = Counter()
for rec in self.data:
ns = sorted(int(x) for x in rec["reds"])
consec = sum(1 for i in range(len(ns) - 1) if ns[i + 1] - ns[i] == 1)
consec_counter[consec] += 1
most_consec = consec_counter.most_common(1)[0][0] if consec_counter else 0
# 10. 综合评分
r_comp = {}
for n in range(1, self.rmax + 1):
s = rf_score.get(n, 0) * self.weights["frequency"]
s += hot_score.get(n, 0) * self.weights["hot_number"]
s += rm_score.get(n, 0.5) * self.weights["missing"]
s += tail_score.get(n % 10, 0.5) * self.weights["tail"]
for i, (zs, ze) in enumerate(zones):
if zs <= n <= ze and zone_balance[i] < 0.85:
s += 0.10
break
r_comp[n] = round(s, 4)
# 蓝球复合评分
recent_blue = []
for r in self.data[:20]:
recent_blue.extend(int(x) for x in (r["blues"] if isinstance(r["blues"], list) else [r["blues"]]))
rbf = Counter(recent_blue)
max_rbf = max(rbf.values()) or 1
b_comp = {}
for n in range(1, self.bmax + 1):
s = bf_score.get(n, 0) * 0.35 + bm_score.get(n, 0.5) * 0.40 + (rbf.get(n, 0) / max_rbf) * 0.25
b_comp[n] = round(s, 4)
result = {
"data_range": {
"total": len(self.data),
"start": self.data[-1]["issue"],
"end": self.data[0]["issue"]
},
"red_composite": r_comp,
"blue_composite": b_comp,
"patterns": {
"most_oe": most_oe,
"most_bs": most_bs,
"avg_sum": round(avg_sum, 1),
"std_sum": round(std_sum, 1),
"sum_range": [round(avg_sum - std_sum, 1), round(avg_sum + std_sum, 1)],
"zone_balance": {f"Z{i+1}": round(zb, 3) for i, zb in enumerate(zone_balance)},
"most_consec": most_consec,
},
"weights_used": copy.deepcopy(self.weights),
}
return result
def recommend(self, analysis, count=5):
"""基于分析结果生成推荐号码"""
if not analysis:
return []
r_comp = analysis["red_composite"]
b_comp = analysis["blue_composite"]
pat = analysis["patterns"]
sorted_r = sorted(r_comp.keys(), key=lambda n: r_comp[n], reverse=True)
sorted_b = sorted(b_comp.keys(), key=lambda n: b_comp[n], reverse=True)
target_oe = [int(x) for x in pat["most_oe"].split(":")]
target_bs = [int(x) for x in pat["most_bs"].split(":")]
sum_min, sum_max = pat["sum_range"]
seed = int(datetime.datetime.now().timestamp() * 1000) % 1000000
rng = random.Random(seed)
results = []
for _ in range(count * 3):
top_r = sorted_r[:20]
weights_r = [max(r_comp[n], 0) for n in top_r]
total_w = sum(weights_r)
if total_w <= 0:
weights_r = [1] * len(top_r)
total_w = len(top_r)
probs_r = [w / total_w for w in weights_r]
reds = set()
attempts = 0
while len(reds) < self.rcnt and attempts < 100:
n = rng.choices(top_r, weights=probs_r, k=1)[0]
reds.add(n)
attempts += 1
if len(reds) < self.rcnt:
remaining = [n for n in range(1, self.rmax + 1) if n not in reds]
rng.shuffle(remaining)
reds.update(remaining[:self.rcnt - len(reds)])
reds = sorted(reds)
top_b = sorted_b[:8]
weights_b = [max(b_comp[n], 0) for n in top_b]
total_bw = sum(weights_b) or 1
probs_b = [w / total_bw for w in weights_b]
if self.bcnt > 1:
blues = list(rng.choices(top_b, weights=probs_b, k=self.bcnt))
# 确保后区号码不重复
while len(set(blues)) < len(blues):
for j in range(len(blues)):
if blues.count(blues[j]) > 1:
remaining = [n for n in range(1, self.bmax + 1) if n not in blues[:j] + blues[j+1:]]
blues[j] = rng.choice(remaining)
else:
blues = list(rng.choices(top_b, weights=probs_b, k=self.bcnt))
score = sum(r_comp.get(n, 0) for n in reds) / self.rcnt
score += sum(b_comp.get(n, 0) for n in blues) / self.bcnt
score /= 2
oe = sum(1 for n in reds if n % 2 == 1)
bs = sum(1 for n in reds if n > self.mid)
total_sum = sum(reds)
bonus = 0
if oe == target_oe[0]:
bonus += 0.05
if bs == target_bs[0]:
bonus += 0.05
if sum_min <= total_sum <= sum_max:
bonus += 0.05
results.append({
"reds": reds, "blues": blues,
"score": round(score + bonus, 4),
"oe": f"{oe}:{self.rcnt - oe}",
"bs": f"{bs}:{self.rcnt - bs}",
"sum": total_sum,
})
seen = set()
unique = []
for r in sorted(results, key=lambda x: x["score"], reverse=True):
key = tuple(r["reds"]) + tuple(r["blues"])
if key not in seen:
seen.add(key)
unique.append(r)
return unique[:count]
# ============================================================
# AI 逐期回滚推演引擎
# ============================================================
class AIRollbackEngine:
"""
AI逐期回滚推演:
从第200期开始 -> 使用当时可用的历史数据进行分析 -> 生成推荐
-> 与实开号码比对 -> 记录命中率 -> 自动调整权重
-> 进入下一期... 直至最新一期
"""
def __init__(self, lt, data, initial_weights=None):
self.lt = lt
self.rule = LOTTERY_RULES[lt]
# 标准化所有记录(兼容 blue/blues 混用)
normed = [_normalize_rec(d) for d in data]
self.all_data = sorted(normed, key=lambda x: int(x["issue"])) # 从旧到新
self.weights = initial_weights if initial_weights else copy.deepcopy(DEFAULT_WEIGHTS)
self.rollback_history = []
self.methodology_log = []
def run(self):
"""执行完整回滚推演:从第200期开始逐期推演至最新一期"""
total_periods = len(self.all_data)
if total_periods < 200:
return {"error": f"数据不足200期,当前仅{total_periods}期", "available": total_periods}
start_idx = 199 # 第200期(0-based索引)
total_simulations = 0
total_red_hits = 0
total_blue_hits = 0
possible_red = 0
possible_blue = 0
methodology_snapshots = []
print(f"{'='*60}")
print(f" AI逐期回滚推演引擎 - {self.rule['name']}")
print(f" 数据总量: {total_periods}期 | 推演范围: 第200期 ~ 第{total_periods}期")
print(f" 推演总轮次: {total_periods - start_idx} 期")
print(f"{'='*60}")
for i in range(start_idx, total_periods):
current_issue = self.all_data[i]["issue"]
historical = self.all_data[:i]
actual = self.all_data[i]
actual_reds = [int(x) for x in actual["reds"]]
actual_blues = [int(x) for x in _get_blues(actual)]
analyzer = EnhancedAnalyzer(historical, self.lt, self.weights)
analysis = analyzer.analyze()
if not analysis:
continue
recommendations = analyzer.recommend(analysis, count=5)
if not recommendations:
continue
best_pick = recommendations[0]
pred_reds = best_pick["reds"]
pred_blues = best_pick["blues"]
red_hit = len(set(pred_reds) & set(actual_reds))
blue_hit = len(set(pred_blues) & set(actual_blues))
total_red_hits += red_hit
total_blue_hits += blue_hit
possible_red += self.rule["red_count"]
possible_blue += self.rule["blue_count"]
total_simulations += 1
self.rollback_history.append({
"issue": current_issue,
"iteration": total_simulations,
"pred_reds": pred_reds,
"pred_blues": pred_blues,
"actual_reds": actual_reds,
"actual_blues": actual_blues,
"red_hit": red_hit,
"blue_hit": blue_hit,
"score": best_pick["score"],
"weights_at_time": copy.deepcopy(self.weights),
})
self._optimize_weights(red_hit, blue_hit, pred_reds, actual_reds)
if total_simulations % 5 == 0:
red_acc = total_red_hits / possible_red * 100 if possible_red else 0
blue_acc = total_blue_hits / possible_blue * 100 if possible_blue else 0
methodology_snapshots.append({
"iteration": total_simulations,
"issue": current_issue,
"weights": copy.deepcopy(self.weights),
"red_accuracy": round(red_acc, 2),
"blue_accuracy": round(blue_acc, 2),
})
if total_simulations % 10 == 0 or total_simulations == 1:
red_acc = total_red_hits / possible_red * 100 if possible_red else 0
blue_acc = total_blue_hits / possible_blue * 100 if possible_blue else 0
overall_acc = (total_red_hits + total_blue_hits) / (possible_red + possible_blue) * 100
print(f" [推演 {total_simulations:3d}] 期{current_issue} "
f"红{red_hit}/{self.rule['red_count']} 蓝{blue_hit}/{self.rule['blue_count']} "
f"| 累计 红{red_acc:.1f}% 蓝{blue_acc:.1f}% 综合{overall_acc:.1f}%")
# 最终统计
avg_red = total_red_hits / possible_red * 100 if possible_red else 0
avg_blue = total_blue_hits / possible_blue * 100 if possible_blue else 0
overall_hits = total_red_hits + total_blue_hits
overall_possible = possible_red + possible_blue
overall_acc = overall_hits / overall_possible * 100 if overall_possible else 0
win_probability = overall_acc
hit_dist = {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0}
for entry in self.rollback_history:
total_hit = entry["red_hit"] + entry["blue_hit"]
if total_hit in hit_dist:
hit_dist[total_hit] += 1
result = {
"lottery": self.lt,
"total_simulations": total_simulations,
"start_issue": self.all_data[start_idx]["issue"],
"end_issue": self.all_data[-1]["issue"],
"final_weights": self.weights,
"accuracy": {
"red_accuracy": round(avg_red, 2),
"blue_accuracy": round(avg_blue, 2),
"overall_accuracy": round(overall_acc, 2),
"win_probability": round(win_probability, 2),
},
"hits": {
"total_red_hits": total_red_hits,
"total_blue_hits": total_blue_hits,
"possible_red": possible_red,
"possible_blue": possible_blue,
},
"hit_distribution": hit_dist,
"methodology_snapshots": methodology_snapshots,
"weight_evolution": self._get_weight_evolution(),
}
return result
def _optimize_weights(self, red_hit, blue_hit, pred_reds, actual_reds):
"""根据推演结果动态调整10维度权重"""
iteration = len(self.rollback_history) + 1
lr = max(0.003, 0.01 - iteration * 0.0001)
hit_ratio = (red_hit + blue_hit) / (self.rule["red_count"] + self.rule["blue_count"])
if hit_ratio >= 0.5:
self.weights["frequency"] = min(0.35, self.weights["frequency"] * (1 + lr))
self.weights["hot_number"] = min(0.30, self.weights["hot_number"] * (1 + lr * 0.8))
else:
self.weights["missing"] = min(0.30, self.weights["missing"] * (1 + lr))
self.weights["probability"] = min(0.15, self.weights["probability"] * (1 + lr * 1.2))
self.weights["frequency"] = max(0.15, self.weights["frequency"] * (1 - lr * 0.5))
pred_oe = sum(1 for n in pred_reds if n % 2 == 1)
actual_oe = sum(1 for n in actual_reds if n % 2 == 1)
if pred_oe == actual_oe:
self.weights["odd_even"] = min(0.12, self.weights["odd_even"] * (1 + lr))
pred_sum = sum(pred_reds)
actual_sum = sum(actual_reds)
if abs(pred_sum - actual_sum) <= 15:
self.weights["sum_value"] = min(0.10, self.weights["sum_value"] * (1 + lr))
pred_consec = sum(1 for i in range(len(pred_reds) - 1) if pred_reds[i + 1] - pred_reds[i] == 1)
actual_consec = sum(1 for i in range(len(actual_reds) - 1) if actual_reds[i + 1] - actual_reds[i] == 1)
if pred_consec == actual_consec:
self.weights["consecutive"] = min(0.08, self.weights["consecutive"] * (1 + lr))
total = sum(self.weights.values())
if total > 0:
for k in self.weights:
self.weights[k] /= total
def _get_weight_evolution(self):
if not self.rollback_history:
return []
interval = max(1, len(self.rollback_history) // 20)
evolution = []
for i, entry in enumerate(self.rollback_history):
if i % interval == 0 or i == len(self.rollback_history) - 1:
evolution.append({
"iteration": entry["iteration"],
"issue": entry["issue"],
"weights": entry["weights_at_time"],
})
return evolution
# ============================================================
# 自进化系统(多轮迭代 + 方法论总结升级)
# ============================================================
class SelfEvolvingSystem:
"""多轮迭代运行,每轮完成后总结方法论并升级,目标胜出率 >= 51%"""
def __init__(self, lt, data):
self.lt = lt
self.data = data
self.rule = LOTTERY_RULES[lt]
self.best_weights = copy.deepcopy(DEFAULT_WEIGHTS)
self.best_accuracy = 0
self.iteration_results = []
self.methodology_log = []
def run_iterations(self, max_iterations=20):
print(f"\n{'='*60}")
print(f" 🔬 自进化系统启动 - {self.rule['name']}")
print(f" 目标:胜出率(概率占比) >= 51%")
print(f" 最大迭代轮次: {max_iterations}")
print(f"{'='*60}")
for iteration in range(1, max_iterations + 1):
print(f"\n{'─'*60}")
print(f" 第 {iteration}/{max_iterations} 轮迭代")
print(f"{'─'*60}")
if iteration == 1:
current_weights = copy.deepcopy(DEFAULT_WEIGHTS)
else:
current_weights = self._mutate_weights(self.best_weights, iteration)
engine = AIRollbackEngine(self.lt, self.data, current_weights)
result = engine.run()
if "error" in result:
print(f" ❌ 错误: {result['error']}")
break
accuracy = result["accuracy"]["win_probability"]
self.iteration_results.append({
"iteration": iteration,
"accuracy": accuracy,
"weights": result["final_weights"],
"simulations": result["total_simulations"],
})
self._summarize_methodology(iteration, result)
if accuracy > self.best_accuracy:
self.best_accuracy = accuracy
self.best_weights = result["final_weights"]
print(f" 🏆 新最佳胜出率: {accuracy:.2f}%")
else:
print(f" 本轮胜出率: {accuracy:.2f}% (最佳: {self.best_accuracy:.2f}%)")
if self.best_accuracy >= 51.0:
print(f"\n{'='*60}")
print(f" 🎯 目标达成!胜出率 {self.best_accuracy:.2f}% >= 51%")
print(f"{'='*60}")
break
return self._final_report()
def _mutate_weights(self, base_weights, iteration):
mutated = copy.deepcopy(base_weights)
mutation_rate = max(0.005, 0.03 - iteration * 0.001)
for k in mutated:
delta = random.uniform(-mutation_rate, mutation_rate)
mutated[k] = max(0.01, mutated[k] + delta)
total = sum(mutated.values())
for k in mutated:
mutated[k] /= total
return mutated
def _summarize_methodology(self, iteration, result):
acc = result["accuracy"]
weights = result["final_weights"]
dist = result.get("hit_distribution", {})
sorted_w = sorted(weights.items(), key=lambda x: x[1], reverse=True)
top_dims = sorted_w[:3]
weak_dims = sorted_w[-2:]
summary_lines = [
f"\n === 方法论总结 - 第{iteration}轮 ===",
f" 胜出率: {acc['win_probability']:.2f}% (红球{acc['red_accuracy']:.1f}% 蓝球{acc['blue_accuracy']:.1f}%)",
f" 最优三维度:",
]
for dim, w in top_dims:
summary_lines.append(f" - {dim}: {w:.4f}")
summary_lines.append(f" 最弱二维度:")
for dim, w in weak_dims:
summary_lines.append(f" - {dim}: {w:.4f}")
summary_lines.append(f" 命中分布:")
for level in sorted(dist.keys()):
if dist.get(level, 0) > 0:
pct = dist[level] / result["total_simulations"] * 100
summary_lines.append(f" - {level}个命中: {dist[level]}次 ({pct:.1f}%)")
summary = "\n".join(summary_lines)
print(summary)
self.methodology_log.append(summary)
mpath = os.path.join(DATA_DIR, f"methodology_{self.lt}_iter{iteration}.json")
with open(mpath, "w", encoding="utf-8") as f:
json.dump({
"iteration": iteration,
"accuracy": acc,
"weights": weights,
"hit_distribution": dist,
"snapshots": result.get("methodology_snapshots", []),
}, f, ensure_ascii=False, indent=2)
print(f" [方法论已保存] {mpath}")
def _final_report(self):
report = {
"lottery": self.lt,
"total_iterations": len(self.iteration_results),
"best_accuracy": self.best_accuracy,
"best_weights": self.best_weights,
"iteration_summary": self.iteration_results,
}
rpath = os.path.join(DATA_DIR, f"self_evolve_{self.lt}_final.json")
with open(rpath, "w", encoding="utf-8") as f:
json.dump(report, f, ensure_ascii=False, indent=2)
return report
# ============================================================
# CLI 主入口
# ============================================================
def load_history(lt):
path = os.path.join(DATA_DIR, f"{lt}_history.json")
if os.path.exists(path):
try:
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
except:
pass
return []
def print_header():
print("\n" + "*" * 60)
print(" 双色球 & 大乐透 * 增强智能分析系统 v2.0")
print(" AI回滚推演 | 方法论自优化 | 200期深度分析")
print(" " + datetime.datetime.now().strftime("%Y-%m-%d %H:%M"))
print("*" * 60)
def show_full_report(lt, count=5):
rule = LOTTERY_RULES[lt]
data = load_history(lt)
if not data:
print(f"\n ⚠️ {rule['name']}暂无数据,请先采集")
print(f" python3 lottery_tool.py --action fetch --lottery {lt}")
return
analyzer = EnhancedAnalyzer(data, lt)
analysis = analyzer.analyze()
if not analysis:
print(f"\n ⚠️ {rule['name']}分析失败")
return
print(f"\n{'─'*60}")
print(f" {rule['name']} - 增强分析报告 (200期)")
print(f"{'─'*60}")
dr = analysis["data_range"]
print(f" 数据范围: {dr['total']}期 ({dr['start']} ~ {dr['end']})")
w = analyzer.weights
print(f" 权重体系: freq={w['frequency']:.3f} hot={w['hot_number']:.3f} miss={w['missing']:.3f}")
pat = analysis["patterns"]
print(f"\n 模式分析:")
print(f" 奇偶比: {pat['most_oe']} | 大小比: {pat['most_bs']}")
print(f" 和值范围: {pat['sum_range'][0]} ~ {pat['sum_range'][1]} (均{pat['avg_sum']})")
print(f" 区间分布: {pat['zone_balance']}")
recs = analyzer.recommend(analysis, count=count)
print(f"\n 🎯 AI推荐号码 ({count}组):")
for i, rec in enumerate(recs, 1):
rs = " ".join(f"{n:02d}" for n in rec["reds"])
bs = " ".join(f"{n:02d}" for n in rec["blues"])
print(f" [{i}] 红球: {rs} 蓝球: {bs} (评分:{rec['score']:.3f} OE:{rec['oe']} BS:{rec['bs']})")
def main():
import argparse
parser = argparse.ArgumentParser(description="增强版彩票智能分析系统 v2.0")
parser.add_argument("--action",
choices=["report", "rollback", "self_evolve"],
default="report",
help="report: 200期分析推荐 | rollback: 逐期回滚推演 | self_evolve: 自进化")
parser.add_argument("--lottery", choices=["ssq", "dlt", "all"], default="ssq")
parser.add_argument("--count", type=int, default=5, help="推荐组数")
parser.add_argument("--iterations", type=int, default=10, help="自进化迭代轮次")
args = parser.parse_args()
print_header()
lotteries = ["ssq", "dlt"] if args.lottery == "all" else [args.lottery]
if args.action == "report":
for lt in lotteries:
show_full_report(lt, args.count)
return
if args.action == "rollback":
for lt in lotteries:
data = load_history(lt)
if len(data) < 200:
print(f"\n ⚠️ {LOTTERY_RULES[lt]['name']}数据不足200期 (当前{len(data)}期)")
print(f" 请先采集: python3 lottery_tool.py --action fetch --lottery {lt}")
continue
engine = AIRollbackEngine(lt, data)
result = engine.run()
if "error" not in result:
acc = result["accuracy"]
print(f"\n === 回滚推演完成 ===")
print(f" 综合胜出率: {acc['win_probability']:.2f}%")
print(f" 红球准确率: {acc['red_accuracy']:.1f}% | 蓝球: {acc['blue_accuracy']:.1f}%")
if args.action == "self_evolve":
for lt in lotteries:
data = load_history(lt)
if len(data) < 200:
print(f"\n ⚠️ {LOTTERY_RULES[lt]['name']}数据不足200期 (当前{len(data)}期)")
continue
system = SelfEvolvingSystem(lt, data)
final = system.run_iterations(max_iterations=args.iterations)
print(f"\n === 自进化最终结果 ===")
print(f" 最佳胜出率: {final['best_accuracy']:.2f}%")
print(f" 迭代总轮次: {final['total_iterations']}")
print(f" 最优权重:")
for k, v in sorted(final['best_weights'].items(), key=lambda x: x[1], reverse=True):
print(f" {k}: {v:.4f}")
if __name__ == "__main__":
main()