Files
lottery-picker/lottery_picker/data/enhanced_lottery.py
T

758 lines
29 KiB
Python
Raw 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 -*-
"""
增强版彩票智能分析系统 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()