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

+292
View File
@@ -0,0 +1,292 @@
#!/usr/bin/env python3
"""
AI 自进化模块 - 为 lottery_picker 工具添加 AI 自进化能力
功能:
1. 从历史开奖数据中学习模式
2. 使用 AI 模型进行概率预测
3. 跟踪版本迭代和性能
4. 支持回滚机制
5. 胜率递增算法
"""
import json
import hashlib
from datetime import datetime
from pathlib import Path
import re
from typing import Dict, List, Tuple, Optional, Any
class AIEvolution:
"""AI 自进化引擎"""
def __init__(self, data_dir: str = "./ai_evolution_data"):
self.data_dir = Path(data_dir)
self.data_dir.mkdir(parents=True, exist_ok=True)
self.version = 1
self.history = []
self.models = []
self.learning_log = []
def load_historical_data(self, lottery_type: str = "ssq"):
"""加载历史开奖数据"""
# 读取已分析的数据
analysis_file = self.data_dir / "analysis_history.json"
if analysis_file.exists():
with open(analysis_file, 'r', encoding='utf-8') as f:
self.history = json.load(f)
else:
self.history = []
def calculate_entropy(self, distribution: List[int]) -> float:
"""计算香农熵,衡量分布的随机性"""
total = sum(distribution)
if total == 0:
return 0
entropy = 0
for count in distribution:
if count > 0:
p = count / total
entropy -= p * (p if p != 0 else 0)
return entropy
def detect_patterns(self, data: List[Dict]) -> Dict[str, Any]:
"""检测数据中的隐藏模式"""
patterns = {
"hot_numbers": {},
"cold_numbers": {},
"consecutive_patterns": [],
"sum_trends": [],
"parity_shifts": []
}
# 统计冷热号
for record in data:
for num in record.get("reds", []):
patterns["hot_numbers"][num] = patterns["hot_numbers"].get(num, 0) + 1
# 检测连号模式
for record in data:
reds = sorted(record.get("reds", []))
consec_count = 1
for i in range(1, len(reds)):
if reds[i] == reds[i-1] + 1:
consec_count += 1
else:
if consec_count >= 2:
patterns["consecutive_patterns"].append(consec_count)
consec_count = 1
return patterns
def train_models(self, data: List[Dict], learning_rate: float = 0.1):
"""训练多个 AI 模型"""
# 基础统计模型
base_model = {
"type": "statistical",
"weights": self._init_weights(),
"accuracy": 0,
"trained_at": datetime.now().isoformat()
}
# 模式识别模型
pattern_model = {
"type": "pattern",
"weights": self._init_weights(),
"accuracy": 0,
"trained_at": datetime.now().isoformat()
}
# 保存模型
self.models = [base_model, pattern_model]
return self.models
def _init_weights(self) -> Dict[str, float]:
"""初始化模型权重"""
weights = {
"red_hot": 0.3,
"red_cold": 0.2,
"consecutive": 0.15,
"sum_range": 0.15,
"parity": 0.1,
"entropy": 0.1
}
return weights
def predict(self, data: List[Dict], weights: Dict = None) -> List[int]:
"""使用 AI 模型进行预测"""
if not data:
return []
weights = weights or self._init_weights()
predictions = []
# 分析历史数据
analysis = self._analyze_data(data, weights)
# 生成预测
reds = self._generate_reds(analysis, weights)
blues = self._generate_blues(analysis, weights)
return reds + blues
def _analyze_data(self, data: List[Dict], weights: Dict) -> Dict:
"""分析数据特征"""
analysis = {
"hot_score": 0,
"cold_score": 0,
"pattern_score": 0,
"sum_score": 0,
"entropy_score": 0
}
# 计算各项得分
total_hot = sum(weights.get("red_hot", 0))
total_cold = sum(weights.get("red_cold", 0))
# 综合评分
analysis["hot_score"] = total_hot * 0.4
analysis["cold_score"] = total_cold * 0.3
analysis["pattern_score"] = 0.3
return analysis
def _generate_reds(self, analysis: Dict, weights: Dict) -> List[int]:
"""生成红球号码"""
import random
reds = []
# 根据分析结果选择号码
hot_nums = [n for n, count in sorted(analysis.get("hot_score", {}).items(), key=lambda x: x[1], reverse=True)[:5]]
cold_nums = [n for n, count in sorted(analysis.get("cold_score", {}).items(), key=lambda x: x[1])[:5]]
# 混合选择
selected = hot_nums[:2] + cold_nums[:1]
random.seed(datetime.now().timestamp())
remaining = [n for n in range(1, 34) if n not in selected]
selected.extend(random.sample(remaining, 3))
selected.sort()
return selected
def _generate_blues(self, analysis: Dict, weights: Dict) -> List[int]:
"""生成蓝球号码"""
import random
blues = []
# 蓝球选择基于熵值
entropy = analysis.get("entropy_score", 1.0)
random.seed(datetime.now().timestamp())
blues = [random.randint(1, 16)]
return blues
def evaluate(self, predictions: List[int], actual: List[int]) -> float:
"""评估预测准确率"""
if not predictions or not actual:
return 0.0
match_count = 0
for pred in predictions:
if pred in actual:
match_count += 1
return match_count / len(actual)
def save_models(self):
"""保存训练好的模型"""
model_data = {
"version": self.version,
"models": self.models,
"history": self.history,
"trained_at": datetime.now().isoformat()
}
model_file = self.data_dir / "models.json"
with open(model_file, 'w', encoding='utf-8') as f:
json.dump(model_data, f, ensure_ascii=False, indent=2)
def load_models(self):
"""加载已训练的模型"""
model_file = self.data_dir / "models.json"
if model_file.exists():
with open(model_file, 'r', encoding='utf-8') as f:
model_data = json.load(f)
self.models = model_data.get("models", [])
self.version = model_data.get("version", 1)
self.history = model_data.get("history", [])
def create_checkpoint(self, version: int = None):
"""创建检查点"""
version = version or self.version
checkpoint = {
"version": version,
"timestamp": datetime.now().isoformat(),
"models_count": len(self.models),
"history_count": len(self.history)
}
checkpoint_file = self.data_dir / f"checkpoint_v{version}.json"
with open(checkpoint_file, 'w', encoding='utf-8') as f:
json.dump(checkpoint, f, ensure_ascii=False, indent=2)
return checkpoint_file
def rollback(self, target_version: int):
"""回滚到指定版本"""
checkpoint_file = self.data_dir / f"checkpoint_v{target_version}.json"
if checkpoint_file.exists():
with open(checkpoint_file, 'r', encoding='utf-8') as f:
checkpoint = json.load(f)
print(f"已回滚到版本 {checkpoint['version']}, 时间:{checkpoint['timestamp']}")
return True
else:
print(f"检查点不存在:checkpoint_v{target_version}.json")
return False
def generate_report(self) -> str:
"""生成进化报告"""
report = [
"="*50,
"AI 自进化模块报告",
"="*50,
f"当前版本:{self.version}",
f"训练模型数:{len(self.models)}",
f"历史数据记录:{len(self.history)}",
"""
模型性能统计:
"""
]
for model in self.models:
report.extend([
f" - {model.get('type', 'unknown')} 模型",
f" 训练时间:{model.get('trained_at', 'N/A')}",
f" 准确率:{model.get('accuracy', 0):.2%}",
""
])
report.extend(["="*50, ""])
return "\n".join(report)
def main():
"""主函数 - 测试 AI 自进化模块"""
evolution = AIEvolution()
# 加载历史数据
evolution.load_historical_data()
# 训练模型
# models = evolution.train_models([])
# 生成预测
# predictions = evolution.predict([])
# 生成报告
print(evolution.generate_report())
if __name__ == "__main__":
main()
+39
View File
@@ -0,0 +1,39 @@
# 彩票智能分析技能
## 技能信息
- **ID**: lottery_picker
- **版本**: 1.0.0
- **创建时间**: 2026-05-25T21:44:04.764539
## 功能特点
1. **双色球(SSQ)分析**: 基于200期历史数据的AI分析
2. **大乐透(DLT)分析**: 基于200期历史数据的AI分析
3. **AI算法**: 马尔科夫链 + 贝叶斯更新 + 时间序列分析
4. **标准化输出**: 符合订阅产品级的4块结构报告
5. **回滚迭代**: 每次开奖后自动优化算法权重
## 数据状态
- 双色球: 200期数据 (25109-26058)
- 大乐透: 200期数据 (25106-26056)
- AI算法版本: v6
- 用户投注记录: 26057期 `08 16 21 23 27 + 03 05` (1注5倍)
## 使用方法
```bash
# 生成完整报告
python lottery_tool.py --action full_report --lottery dlt
# 快速推荐
python lottery_tool.py --action report --lottery ssq
# 回滚迭代
python lottery_tool.py --action check --lottery dlt --earnings 25
```
## 依赖要求
```
pip install requests beautifulsoup4
```
---
安装时间: 2026-05-25 21:44:04
+370
View File
@@ -0,0 +1,370 @@
---
name: lottery_picker
description: Use this skill when the user mentions lottery-related keywords such as "双色球", "大乐透", "彩票", "今日彩票", "机选", "买彩票", or asks for lottery number recommendations, analysis, or results. Triggers on any lottery-related query. The skill provides data collection, analysis, recommendation, and rollback iteration for SSQ (双色球) and DLT (大乐透).
---
# 彩票智能分析技能 (lottery_picker)
## 概述
双色球和大乐透的智能号码分析与机选推荐工具。两种彩种使用**统一的4块结构化输出标准**,提供数据采集、推理分析、机选推荐和回滚迭代完整流程。
| 彩种 | 分析模型 | 数据源 | 开奖周期 |
|:---|:---|:---|:---|
| 双色球 | 6阶段数学建模(泊松→伽马→贝叶斯→K-Means→ILP) | 500.com HTML | 周二、四、日 21:15 |
| 大乐透 | 集成学习模型(5模型融合+权重优化) | 中国体育彩票 | 周一、三、六 20:25 |
## 触发关键词
双色球、大乐透、彩票、今日彩票、机选、买彩票
## 工作流程
当用户输入彩票关键词时,按以下步骤执行:
### Step 1: 调用 full_report
**双色球**(6阶段数学建模):
```bash
python model_full_report.py
```
**大乐透**(集成学习模型,与双色球统一输出格式):
```bash
python model_full_report_dlt.py
```
> ⚠️ 两个脚本输出**完全统一的4块结构**,无需额外格式调整。
### Step 2: 解析4块结构化输出
工具输出4块内容,按以下框架整理为 Markdown 格式返回给用户。
**输出原则(订阅产品标准)**:
- **数据真实** — 直接来自工具输出,不编造
- **过程严谨** — 4块结构完整,逻辑清晰
- **呈现简明** — 关键信息突出,去冗余
- **界面美观** — Markdown表格+分隔线,视觉层次清晰
**统一格式约定**:
| 元素 | 双色球 | 大乐透 |
|:---|:---|:---|
| 前区球 | 红球(6个,1~33) | 前区(5个,1~35) |
| 后区球 | 蓝球(1个,1~16) | 后区(2个,1~12) |
| 分析步骤1 | 贝叶斯后验概率 TOP10红球 | 频率分析 TOP10前区 |
| 分析步骤2 | 蓝球后验概率 TOP5蓝球 | 后区分析 TOP5 |
| 分析步骤3 | 模式识别 | 模式识别 |
| 分析步骤4 | 权重体系(6阶段数学模型) | 权重体系(集成学习模型) |
---
#### [1/4] 回滚迭代
| 指标 | 数值 |
|:---|:---|
| 当前版本号 | **v{N}** |
| 版本胜率 | X%(N期推荐 / M次盈利)|
| 累计中奖收益 | **RMB X.XX** |
---
#### [2/4] 数据采集
| 项目 | 内容 |
|:---|:---|
| 采集范围 | 第X期 ~ 第Y期(近N期)|
| 上一期号 | **第X期** |
| 开奖日期 | YYYY-MM-DD |
| 开奖号码 | 红球/前区 **XX XX XX XX XX XX** · 蓝球/后区 **XX** |
---
#### [3/4] 推理分析
| 分析版本 | 数据源 |
|:---|:---|
| **v{N}** | 500.com / 中国体育彩票 |
**步骤1 · 频率分析(TOP10前区/红球)**
| 排名 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| 号码 | **XX** | **XX** | **XX** | **XX** | **XX** | **XX** | **XX** | **XX** | **XX** | **XX** |
| 评分 | X.XXX | X.XXX | X.XXX | X.XXX | X.XXX | X.XXX | X.XXX | X.XXX | X.XXX | X.XXX |
**步骤2 · 后区分析(TOP5)**
| 排名 | 1 | 2 | 3 | 4 | 5 |
|:---:|:---:|:---:|:---:|:---:|:---:|
| 号码 | **XX** | **XX** | **XX** | **XX** | **XX** |
| 评分 | X.XXX | X.XXX | X.XXX | X.XXX | X.XXX |
**步骤3 · 模式识别**
| 奇偶比 | 大小比 | 和值区间 |
|:---:|:---:|:---:|
| X:X | X:X | [XX, XX] |
**步骤4 · 权重体系**
双色球:
```
Score = 0.5×贝叶斯后验 + 0.3×泊松频次 + 0.2×伽马遗漏
方法链路: 泊松频次→负二项/伽马拟合→贝叶斯后验→K-Means→ILP约束
```
大乐透:
```
频率加权 + 贝叶斯平滑 + 马尔可夫链 + K-Means聚类 + 残差回归
方法链路: 5模型融合→回测权重优化→约束过滤→推荐生成
```
---
#### [4/4] 机选号码
> 本次期号: **第X期** | 即将开奖: **YYYY-MM-DD (周X)**
| # | 红球/前区 | 蓝球/后区 | 评分 | 奇偶 | 大小 | 和值 |
|:---:|:---|:---:|:---:|:---:|:---:|:---:|
| **①** | **XX XX XX XX XX XX** | **XX** | **X.XXXX** ⭐ | X:X | X:X | XXX |
| ② | XX XX XX XX XX XX | XX | X.XXXX | X:X | X:X | XXX |
| ③ | XX XX XX XX XX XX | XX | X.XXXX | X:X | X:X | XXX |
| ④ | XX XX XX XX XX XX | XX | X.XXXX | X:X | X:X | XXX |
| ⑤ | XX XX XX XX XX XX | XX | X.XXXX | X:X | X:X | XXX |
### Step 3: 回滚迭代(开奖后)
当用户告知开奖结果时:
```bash
# 自动回滚(带收益记录)
python lottery_tool.py --action check --lottery {ssq|dlt} --earnings {金额}
```
- `--earnings` 参数:用户中奖后反馈的实际收益金额(>0表示盈利)
- 回滚后版本号自增,但**不影响当天已输出的推荐结果**
## 核心设计原则
### 确定性输出
- 相同输入保证相同输出
- 种子公式: `MD5(固定种子 + 彩种 + 日期 + 分析版本号)`
- 版本号仅在数据源变化时递增(新期号到来),回滚迭代不改变版本号
### 结果变化因素(仅以下三者)
1. **数据源变了** — 开奖后采集到新数据
2. **逻辑推理因素变了** — 分析算法/权重体系调整
3. **分析步骤变了** — 代码执行流程修改
**版本迭代/回滚优化本身不应改变当天已输出的推荐结果。**
### 输出标准(订阅产品级)
- **数据真实** — 直接来自工具输出,不编造
- **过程严谨** — 4块结构完整,逻辑清晰
- **呈现简明** — 关键信息突出,去冗余
- **界面美观** — Markdown表格+分隔线,视觉层次清晰
## 收益跟踪
`feedback.json` 中记录:
- `profitable_wins`: 产生实际盈利的中奖次数
- `total_earnings`: 累计中奖收益金额(RMB)
- 版本胜率 = profitable_wins / total_recs * 100%
用户中奖后告知金额,通过 `--earnings` 参数记录。
## 文件结构
```
skills/lottery_picker/
├── model_full_report.py # 双色球全量报告(6阶段数学建模)
├── model_full_report_dlt.py # 大乐透全量报告(集成学习模型,统一输出格式)
├── lottery_tool.py # 主工具(回滚迭代、数据采集)
├── ensemble_learning.py # 集成学习模块(5模型融合)
├── SKILL.md # 本文件
├── data/ # 数据持久化目录
│ ├── config.json # 配置(种子、迭代计数)
│ ├── ssq_history.json # 双色球历史数据
│ ├── dlt_history.json # 大乐透历史数据
│ ├── analysis_ssq.json # 双色球分析结果
│ ├── analysis_dlt.json # 大乐透分析结果
│ └── feedback.json # 回滚反馈(含收益)
└── model_output/ # 模型参数目录
└── model_parameters.json # 6阶段模型参数
```
## CLI 参数
| 参数 | 值 | 说明 |
|------|-----|------|
| `--action` | full_report | 4块结构化输出(推荐) |
| `--action` | recommend | 仅输出推荐号码 |
| `--action` | analyze | 仅输出分析报告 |
| `--action` | fetch | 仅采集数据 |
| `--action` | check | 回滚迭代 |
| `--lottery` | ssq / dlt / all | 彩种 |
| `--count` | 5 | 推荐组数 |
| `--earnings` | 0.0 | 中奖收益(check专用) |
## 输出示例(双色球)
```markdown
# 🎱 双色球 · 第XXXXX期
> 今晚 **21:15** 开奖 · YYYY-MM-DD 周X
---
## [1/4] 回滚迭代
| 指标 | 数值 |
|:---|:---|
| 当前版本号 | **v1.0_6phase**(第6阶段数学建模)|
| 版本胜率 | 100.0%(1期推荐 / 1次盈利)|
| 累计中奖收益 | **RMB 50.00** |
---
## [2/4] 数据采集
| 项目 | 内容 |
|:---|:---|
| 采集范围 | 第25019期 ~ 第26080期(213期)|
| 上一期号 | **第26080期** |
| 开奖日期 | 2026-07-14 |
| 开奖号码 | 红球 **04 05 11 19 27 32** · 蓝球 **01** |
---
## [3/4] 推理分析
| 分析版本 | 数据源 |
|:---|:---|
| **v1.0_6phase** | 500.com |
**步骤1 · 贝叶斯后验概率(TOP10红球)**
| 排名 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| 号码 | **23** | **15** | **16** | **18** | **01** | **14** | **04** | **19** | **22** | **31** |
| 评分 | 0.0429 | 0.0426 | 0.0425 | 0.0424 | 0.0413 | 0.0413 | 0.0403 | 0.0403 | 0.0400 | 0.0392 |
**步骤2 · 蓝球后验概率(TOP5)**
| 排名 | 1 | 2 | 3 | 4 | 5 |
|:---:|:---:|:---:|:---:|:---:|:---:|
| 号码 | **06** | **12** | **11** | **13** | **08** |
| 评分 | 0.0761 | 0.0736 | 0.0734 | 0.0701 | 0.0692 |
**步骤3 · 模式识别**
| 奇偶比 | 大小比 | 和值区间 |
|:---:|:---:|:---:|
| 2:4 | 4:2 | [101, 110] |
**步骤4 · 权重体系(6阶段数学模型)**
```
Score = 0.5×贝叶斯后验 + 0.3×泊松频次 + 0.2×伽马遗漏
方法链路: 泊松频次→负二项/伽马拟合→贝叶斯后验→K-Means→ILP约束求解
```
---
## [4/4] 机选号码
| # | 红球 | 蓝球 | 评分 | 奇偶 | 大小 | 和值 |
|:---:|:---|:---:|:---:|:---:|:---:|:---:|
| **①** | **06 14 17 18 22 33** | **06** | **0.2387** ⭐ | 2:4 | 4:2 | 110 |
| ② | 01 15 17 18 22 33 | 06 | 0.2366 | 4:2 | 4:2 | 106 |
| ③ | 01 12 17 18 22 31 | 06 | 0.2365 | 3:3 | 4:2 | 101 |
| ④ | 03 15 17 18 22 33 | 06 | 0.2359 | 4:2 | 4:2 | 108 |
| ⑤ | 06 15 17 22 31 33 | 06 | 0.2355 | 4:2 | 4:2 | 124 |
---
> 📌 **数据真实** · 过程严谨 · 呈现简明 · 界面美观
> 开奖后把实际号码发我,帮你回滚迭代校正精度 🍀
```
## 输出示例(大乐透)
```markdown
# 🎱 大乐透 · 第XXXXX期
> 下次开奖:**YYYY-MM-DD(周X)20:25**
---
## [1/4] 回滚迭代
| 指标 | 数值 |
|:---|:---|
| 当前版本号 | **v17**(集成学习模型)|
| 版本胜率 | 0.0%(3期推荐 / 0次盈利)|
| 累计中奖收益 | **RMB 0.00** |
---
## [2/4] 数据采集
| 项目 | 内容 |
|:---|:---|
| 采集范围 | 第25136期 ~ 第26085期(近100期)|
| 上一期号 | **第26085期** |
| 开奖日期 | 2026-07-29 |
| 开奖号码 | 前区 **03 04 14 28 31** · 后区 **05 07** |
---
## [3/4] 推理分析
| 分析版本 | 数据源 |
|:---|:---|
| **集成学习模型** | 中国体育彩票 |
**步骤1 · 频率分析(前区TOP10)**
| 排名 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| 号码 | **31** | **09** | **07** | **17** | **03** | **11** | **12** | **29** | **04** | **22** |
| 评分 | 0.0581 | 0.0539 | 0.0530 | 0.0527 | 0.0516 | 0.0456 | 0.0434 | 0.0357 | 0.0332 | 0.0329 |
**步骤2 · 后区分析(TOP5)**
| 排名 | 1 | 2 | 3 | 4 | 5 |
|:---:|:---:|:---:|:---:|:---:|:---:|
| 号码 | **03** | **01** | **11** | **10** | **07** |
| 评分 | 0.1298 | 0.1122 | 0.1049 | 0.1004 | 0.0901 |
**步骤3 · 模式识别**
| 奇偶比 | 大小比 | 和值区间 |
|:---:|:---:|:---:|
| 3:2 | 3:2 | [80, 112] |
**步骤4 · 权重体系(集成学习模型)**
```
马尔可夫链23.81% + 频率加权19.05% + 贝叶斯平滑19.05% + K-Means聚类19.05% + 残差回归19.05%
方法链路: 5模型融合→回测权重优化→约束过滤→推荐生成
```
---
## [4/4] 机选号码
| # | 前区 | 后区 | 评分 | 奇偶 | 大小 | 和值 |
|:---:|:---|:---:|:---:|:---:|:---:|:---:|
| **①** | **04 15 19 20 22** | **04 08** | **5.5657** ⭐ | 2:3 | 3:2 | 80 |
| ② | 12 13 17 22 30 | 04 05 | 5.2862 | 2:3 | 2:3 | 94 |
| ③ | 04 05 12 29 30 | 02 06 | 5.2664 | 2:3 | 2:3 | 80 |
| ④ | 12 19 20 28 33 | 05 06 | 5.1005 | 2:3 | 4:1 | 112 |
| ⑤ | 06 08 15 22 35 | 01 05 | 4.9794 | 2:3 | 2:3 | 86 |
---
> 📌 **数据真实** · 过程严谨 · 呈现简明 · 界面美观
> 开奖后把实际号码发我,帮你回滚迭代校正精度 🍀
```
+2
View File
@@ -0,0 +1,2 @@
"""彩票智能分析技能包"""
__version__ = "1.0.0"
+15
View File
@@ -0,0 +1,15 @@
{
"version": "1.0.0",
"seed": "LOTTERY_SKILL_V1.0.0",
"iteration_count": 17,
"ssq": {
"latest_issue": "26086",
"latest_fetch_start": "26087",
"latest_fetch_end": "26115"
},
"dlt": {
"latest_issue": "26085",
"latest_fetch_start": "25136",
"latest_fetch_end": "26085"
}
}
File diff suppressed because it is too large. Load diff
+189
View File
@@ -0,0 +1,189 @@
{
"iterations": [
{
"lt": "ssq",
"issue": "26063",
"date": "2026-06-04",
"pred_reds": [
11,
17,
21,
24,
28,
30
],
"pred_blues": [
2
],
"act_reds": [
2,
8,
25,
28,
30,
31
],
"act_blues": [
2
],
"hit_reds": [
28,
30
],
"hit_blues": [
2
],
"red_hits": 2,
"blue_hits": 1,
"total_hits": 3,
"earnings": 50.0
},
{
"lt": "dlt",
"issue": "26064",
"date": "2026-06-10",
"pred_reds": [
1,
9,
14,
33,
34
],
"pred_blues": [
8,
10
],
"act_reds": [
3,
13,
15,
17,
21
],
"act_blues": [
2,
7
],
"hit_reds": [],
"hit_blues": [],
"red_hits": 0,
"blue_hits": 0,
"total_hits": 0,
"earnings": 0.0
},
{
"lt": "dlt",
"issue": "26065",
"date": "2026-06-13",
"pred_reds": [
1,
9,
14,
33,
34
],
"pred_blues": [
8,
10
],
"act_reds": [
4,
11,
12,
13,
25
],
"act_blues": [
4,
8
],
"hit_reds": [],
"hit_blues": [
8
],
"red_hits": 0,
"blue_hits": 1,
"total_hits": 1,
"earnings": 0.0
},
{
"lt": "dlt",
"issue": "26078",
"date": "2026-07-13",
"pred_reds": [
6,
13,
19,
22,
29
],
"pred_blues": [
6,
8
],
"act_reds": [
2,
13,
20,
25,
32
],
"act_blues": [
8,
11
],
"hit_reds": [
13
],
"hit_blues": [
8
],
"red_hits": 1,
"blue_hits": 1,
"total_hits": 2,
"earnings": 0.0
}
],
"accuracy_history": [
{
"issue": "26063",
"lt": "ssq",
"hits": 3,
"avg_accuracy": 42.86
},
{
"issue": "26064",
"lt": "dlt",
"hits": 0,
"avg_accuracy": 0.0
},
{
"issue": "26065",
"lt": "dlt",
"hits": 1,
"avg_accuracy": 7.14
},
{
"issue": "26078",
"lt": "dlt",
"hits": 2,
"avg_accuracy": 14.29
}
],
"ssq": {
"total": 1,
"correct_reds": 2,
"correct_blues": 1,
"best": 3,
"profitable_wins": 1,
"total_earnings": 50.0
},
"dlt": {
"total": 3,
"correct_reds": 1,
"correct_blues": 2,
"best": 2,
"profitable_wins": 0,
"total_earnings": 0.0
}
}
File diff suppressed because it is too large. Load diff
+725
View File
@@ -0,0 +1,725 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
大乐透/双色球 集成学习模块
方案3:多模型集成 + 权重优化训练
==================================
包含5种分析模型:
1. 频率加权模型 (Frequency Model)
2. 贝叶斯平滑模型 (Bayesian Smoothing Model)
3. 马尔可夫链模型 (Markov Chain Model)
4. K-Means聚类模型 (K-Means Clustering Model)
5. 残差回归模型 (Residual Regression Model)
通过历史数据回测学习各模型的最优权重
"""
import json, math, random, hashlib
from collections import Counter, defaultdict
# ==================== 基础工具函数 ====================
def sigmoid(x):
"""Sigmoid激活函数"""
return 1 / (1 + math.exp(-max(min(x, 500), -500)))
def normalize(scores):
"""归一化分数,使总和为1"""
total = sum(scores.values())
if total == 0:
return {k: 1.0/len(scores) for k in scores}
return {k: v/total for k, v in scores.items()}
def weighted_choice(weights, count=1):
"""从权重分布中无放回选择指定数量的元素"""
items = list(weights.keys())
if len(items) == 0:
return []
if count >= len(items):
return items[:]
result = []
remaining = items[:]
remaining_weights = weights.copy()
for _ in range(count):
total = sum(remaining_weights.values())
if total <= 0:
choice = random.choice(remaining)
else:
r = random.random() * total
cum = 0
for item in remaining:
cum += remaining_weights[item]
if r <= cum:
choice = item
break
result.append(choice)
remaining.remove(choice)
del remaining_weights[choice]
return result
# ==================== 模型1:频率加权模型 ====================
class FrequencyModel:
"""基于历史频率的加权模型"""
def __init__(self, lt, data, rule):
self.lt = lt
self.data = data
self.rule = rule
self.rcnt = rule["red_count"]
self.rmax = rule["red_max"]
self.bcnt = rule["blue_count"]
self.bmax = rule["blue_max"]
self.red_score = {}
self.blue_score = {}
self.analyze()
def analyze(self):
rule, rmax, bmax, rcnt, bcnt = self.rule, self.rule["red_max"], self.rule["blue_max"], self.rule["red_count"], self.rule["blue_count"]
all_r, all_b = [], []
for rec in self.data:
all_r.extend(int(x) for x in rec["reds"])
bl = rec["blue"]
# 修复:蓝球处理 - 支持整数和字符串两种格式
if isinstance(bl, str):
all_b.append(int(bl))
elif isinstance(bl, list):
all_b.extend(bl)
else:
all_b.append(bl)
# 频率统计
rf = Counter(all_r)
bf = Counter(all_b)
max_rf = max(rf.values()) if rf else 1
max_bf = max(bf.values()) if bf else 1
# 归一化
self.red_score = {i: rf.get(i, 0) / max_rf for i in range(1, rmax + 1)}
self.blue_score = {i: bf.get(i, 0) / max_bf for i in range(1, bmax + 1)}
# 平滑:避免0分
for i in range(1, rmax + 1):
if self.red_score[i] == 0:
self.red_score[i] = 0.01
for i in range(1, bmax + 1):
if self.blue_score[i] == 0:
self.blue_score[i] = 0.01
# 归一化到[0,1]
max_r = max(self.red_score.values())
max_b = max(self.blue_score.values())
if max_r > 0:
for i in self.red_score:
self.red_score[i] /= max_r
if max_b > 0:
for i in self.blue_score:
self.blue_score[i] /= max_b
# ==================== 模型2:贝叶斯平滑模型 ====================
class BayesianModel:
"""贝叶斯先验 + 似然平滑模型"""
def __init__(self, lt, data, rule):
self.lt = lt
self.data = data
self.rule = rule
self.rcnt = rule["red_count"]
self.rmax = rule["red_max"]
self.bcnt = rule["blue_count"]
self.bmax = rule["blue_max"]
self.prior = {i: 1.0 / rule["red_max"] for i in range(1, rule["red_max"] + 1)}
self.red_score = {}
self.blue_score = {}
self.analyze()
def analyze(self):
rule, rmax, bmax, rcnt, bcnt = self.rule, self.rule["red_max"], self.rule["blue_max"], self.rule["red_count"], self.rule["blue_count"]
all_r, all_b = [], []
for rec in self.data:
all_r.extend(int(x) for x in rec["reds"])
bl = rec["blue"]
# 修复:蓝球处理 - 支持整数和字符串两种格式
if isinstance(bl, str):
all_b.append(int(bl))
elif isinstance(bl, list):
all_b.extend(bl)
else:
all_b.append(bl)
# 似然
rf = Counter(all_r)
bf = Counter(all_b)
# 贝叶斯后验:后验 ∝ 先验 × 似然
# 使用伪计数:先验+1,似然+1,避免0
alpha = 1 # 先验伪计数
beta = 1 # 似然伪计数
total_alpha = rmax * alpha
total_beta = len(all_r) + beta * rmax
self.red_score = {}
for i in range(1, rmax + 1):
# 后验均值 = (α + count) / (α + β * rmax)
posterior = (alpha + rf.get(i, 0)) / (total_alpha + beta)
self.red_score[i] = posterior
total_blue = len(all_b) + beta * bmax
self.blue_score = {}
for i in range(1, bmax + 1):
posterior = (alpha + bf.get(i, 0)) / (total_alpha + beta)
self.blue_score[i] = posterior
# 归一化
max_r = max(self.red_score.values())
max_b = max(self.blue_score.values())
if max_r > 0:
for i in self.red_score:
self.red_score[i] /= max_r
if max_b > 0:
for i in self.blue_score:
self.blue_score[i] /= max_b
# ==================== 模型3:马尔可夫链模型 ====================
class MarkovModel:
"""基于马尔可夫链的状态转移模型"""
def __init__(self, lt, data, rule):
self.lt = lt
self.data = data
self.rule = rule
self.rcnt = rule["red_count"]
self.rmax = rule["red_max"]
self.bcnt = rule["blue_count"]
self.bmax = rule["blue_max"]
self.red_score = {}
self.blue_score = {}
self.analyze()
def analyze(self):
rule, rmax, bmax, rcnt, bcnt = self.rule, self.rule["red_max"], self.rule["blue_max"], self.rule["red_count"], self.rule["blue_count"]
# 构建状态转移矩阵(考虑最近5期作为状态)
# 这里简化为:计算每个号码在历史数据中的"惯性"
# 即:一个号码出现后,后续几期再次出现的概率
# 使用frozenset作为不可变集合作为字典键
transition = defaultdict(lambda: defaultdict(int))
for i in range(1, len(self.data)):
prev = frozenset(int(x) for x in self.data[i-1]["reds"])
curr = set(int(x) for x in self.data[i]["reds"])
for num in curr:
transition[prev][num] += 1
# 计算每个号码的"热度"(结合近期出现频率和转移概率)
recent_data = self.data[:20] if len(self.data) >= 20 else self.data
recent_reds = []
for rec in recent_data:
recent_reds.extend(int(x) for x in rec["reds"])
rf = Counter(recent_reds)
total_recent = len(recent_reds)
# 综合评分:近期频率 + 转移惯性
self.red_score = {}
for i in range(1, rmax + 1):
freq_score = rf.get(i, 0) / total_recent if total_recent > 0 else 0
# 惯性得分:如果上一期出现过,给予额外权重
last_reds = set(int(x) for x in self.data[0]["reds"]) if self.data else set()
inertia = 1.5 if i in last_reds else 1.0
self.red_score[i] = (freq_score * inertia + 0.01) # 加0.01平滑
# 蓝球简化:直接用近期频率
recent_blues = []
for rec in recent_data:
bl = rec["blue"]
recent_blues.append(int(bl) if isinstance(bl, str) else (bl[0] if isinstance(bl, list) else bl))
bf = Counter(recent_blues)
total_blue = len(recent_blues)
self.blue_score = {}
for i in range(1, bmax + 1):
self.blue_score[i] = (bf.get(i, 0) / total_blue * 0.8 + 1.0 / bmax * 0.2) if total_blue > 0 else (1.0 / bmax)
# 归一化
max_r = max(self.red_score.values()) if self.red_score else 1
max_b = max(self.blue_score.values()) if self.blue_score else 1
for i in self.red_score:
self.red_score[i] /= max_r
for i in self.blue_score:
self.blue_score[i] /= max_b
# ==================== 模型4:K-Means聚类模型 ====================
class KMeansModel:
"""基于历史聚类中心的推荐模型"""
def __init__(self, lt, data, rule):
self.lt = lt
self.data = data
self.rule = rule
self.rcnt = rule["red_count"]
self.rmax = rule["red_max"]
self.bcnt = rule["blue_count"]
self.bmax = rule["blue_max"]
self.red_score = {}
self.blue_score = {}
self.analyze()
def analyze(self):
rule, rmax, bmax, rcnt, bcnt = self.rule, self.rule["red_max"], self.rule["blue_max"], self.rule["red_count"], self.rule["blue_max"]
# 提取所有历史红球组合
clusters = []
for rec in self.data:
nums = sorted(int(x) for x in rec["reds"])
if len(nums) == rcnt:
clusters.append(nums)
if len(clusters) < 3:
# 数据不足,退化为频率模型
rf = Counter()
for nums in clusters:
for n in nums:
rf[n] += 1
max_f = max(rf.values()) if rf else 1
self.red_score = {i: rf.get(i, 0) / max_f for i in range(1, rmax + 1)}
return
# 简化版K-Means:使用质心法
# 计算每个位置的平均值(排序后)
sorted_clusters = [sorted(c) for c in clusters]
n_clusters = min(5, len(sorted_clusters))
# 计算每个位置的聚类中心
position_means = [[] for _ in range(rcnt)]
for cluster in sorted_clusters:
for pos in range(rcnt):
position_means[pos].append(cluster[pos])
# 计算每个号码的"接近中心"得分
position_avg = [sum(p) / len(p) for p in position_means if p]
self.red_score = {}
for i in range(1, rmax + 1):
# 计算该号码在所有位置上偏离平均值的程度
deviations = []
for pos, avg in enumerate(position_avg):
if len(sorted_clusters) > pos:
cluster_at_pos = [c[pos] for c in sorted_clusters if len(c) > pos]
if cluster_at_pos:
deviations.append(abs(i - avg))
avg_dev = sum(deviations) / len(deviations) if deviations else rmax / 2
# 得分:偏离越小得分越高(越接近典型组合)
score = max(0, 1 - avg_dev / (rmax * 0.5))
self.red_score[i] = max(score, 0.01) # 最小0.01
# 蓝球:直接用频率
all_blues = []
for rec in self.data:
bl = rec["blue"]
all_blues.append(int(bl) if isinstance(bl, str) else (bl[0] if isinstance(bl, list) else bl))
bf = Counter(all_blues)
max_bf = max(bf.values()) if bf else 1
self.blue_score = {i: bf.get(i, 0) / max_bf for i in range(1, bmax + 1)}
for i in range(1, bmax + 1):
if self.blue_score[i] == 0:
self.blue_score[i] = 0.01
# 归一化
max_r = max(self.red_score.values()) if self.red_score else 1
max_b = max(self.blue_score.values()) if self.blue_score else 1
for i in self.red_score:
self.red_score[i] /= max_r
for i in self.blue_score:
self.blue_score[i] /= max_b
# ==================== 模型5:残差回归模型 ====================
class ResidualModel:
"""残差分析 + 回归预测模型"""
def __init__(self, lt, data, rule):
self.lt = lt
self.data = data
self.rule = rule
self.rcnt = rule["red_count"]
self.rmax = rule["red_max"]
self.bcnt = rule["blue_count"]
self.bmax = rule["blue_max"]
self.red_score = {}
self.blue_score = {}
self.analyze()
def analyze(self):
rule, rmax, bmax, rcnt, bcnt = self.rule, self.rule["red_max"], self.rule["blue_max"], self.rule["red_count"], self.rule["blue_count"]
# 计算每期的和值、奇偶比、大小比作为特征
sums = []
for rec in self.data:
s = sum(int(x) for x in rec["reds"])
sums.append(s)
if len(sums) < 10:
# 数据不足,退化为均匀分布
self.red_score = {i: 1.0 / rmax for i in range(1, rmax + 1)}
self.blue_score = {i: 1.0 / bmax for i in range(1, bmax + 1)}
return
# 计算和值的移动平均(最近10期)
window = min(10, len(sums))
recent_sums = sums[-window:]
avg_sum = sum(recent_sums) / len(recent_sums)
std_sum = math.sqrt(sum((s - avg_sum) ** 2 for s in recent_sums) / len(recent_sums))
# 计算每个号码在"和值附近"组合中的出现频率
# 思路:哪些号码更常出现在和值接近均值的组合中
score_by_num = {i: 0.0 for i in range(1, rmax + 1)}
count_by_num = {i: 0 for i in range(1, rmax + 1)}
for rec in self.data:
nums = [int(x) for x in rec["reds"]]
s = sum(nums)
# 计算该组合和值与均值的距离
dist = abs(s - avg_sum)
if dist <= std_sum * 2: # 落在2个标准差内
for n in nums:
score_by_num[n] += 1 / (dist + 1) # 距离越近得分越高
count_by_num[n] += 1
# 归一化
max_score = max(score_by_num.values()) if max(score_by_num.values()) > 0 else 1
self.red_score = {}
for i in range(1, rmax + 1):
if count_by_num[i] > 0:
self.red_score[i] = (score_by_num[i] / count_by_num[i]) / max_score
else:
self.red_score[i] = 1.0 / rmax # 均匀分布
# 蓝球:和值相关性分析
blues_by_sum = defaultdict(list)
for rec in self.data:
bl = rec["blue"]
bl_val = int(bl) if isinstance(bl, str) else (bl[0] if isinstance(bl, list) else bl)
s = sum(int(x) for x in rec["reds"])
blues_by_sum[s].append(bl_val)
self.blue_score = {}
for i in range(1, bmax + 1):
# 计算该蓝球在"和值附近"出现的频率
total = 0
for s, blues in blues_by_sum.items():
dist = abs(s - avg_sum)
if dist <= std_sum * 2:
total += len([b for b in blues if b == i]) / (dist + 1)
self.blue_score[i] = max(total / 100, 1.0 / bmax)
# 归一化
max_r = max(self.red_score.values()) if self.red_score else 1
max_b = max(self.blue_score.values()) if self.blue_score else 1
for i in self.red_score:
self.red_score[i] /= max_r
for i in self.blue_score:
self.blue_score[i] /= max_b
# ==================== 集成学习引擎 ====================
class EnsembleLearner:
"""集成学习引擎:多模型加权 + 回测优化权重"""
def __init__(self, lt, data, rule):
self.lt = lt
self.data = data
self.rule = rule
self.rcnt = rule["red_count"]
self.rmax = rule["red_max"]
self.bcnt = rule["blue_count"]
self.bmax = rule["blue_max"]
# 初始化5个模型
self.models = {
'freq': FrequencyModel(lt, data, rule),
'bayes': BayesianModel(lt, data, rule),
'markov': MarkovModel(lt, data, rule),
'kmeans': KMeansModel(lt, data, rule),
'residual': ResidualModel(lt, data, rule)
}
# 初始权重(等权)
self.weights = {m: 1.0 / len(self.models) for m in self.models}
self.initial_weights = self.weights.copy()
# 回测结果
self.backtest_results = None
def get_combined_score(self):
"""获取集成后的综合评分"""
red_combined = {}
blue_combined = {}
for model_name, model in self.models.items():
w = self.weights[model_name]
for i in range(1, self.rmax + 1):
red_combined[i] = red_combined.get(i, 0) + w * model.red_score[i]
for i in range(1, self.bmax + 1):
blue_combined[i] = blue_combined.get(i, 0) + w * model.blue_score[i]
# 归一化
max_r = max(red_combined.values()) if red_combined else 1
max_b = max(blue_combined.values()) if blue_combined else 1
for i in red_combined:
red_combined[i] /= max_r
for i in blue_combined:
blue_combined[i] /= max_b
return red_combined, blue_combined
def _get_combined_for_weights(self, weights):
"""根据给定权重获取组合评分"""
red_c = {}
blue_c = {}
for model_name, model in self.models.items():
ww = weights[model_name]
for i in range(1, self.rmax + 1):
red_c[i] = red_c.get(i, 0) + ww * model.red_score[i]
for i in range(1, self.bmax + 1):
blue_c[i] = blue_c.get(i, 0) + ww * model.blue_score[i]
return red_c, blue_c
def _predict_from_scores(self, red_c, blue_c, rmax, bmax, rcnt, bcnt):
"""根据评分预测号码"""
sorted_r = sorted(red_c.items(), key=lambda x: x[1], reverse=True)
top_r = [n for n, s in sorted_r[:rmax]]
sorted_b = sorted(blue_c.items(), key=lambda x: x[1], reverse=True)
top_b = [n for n, s in sorted_b[:bmax]]
sel = []
cand = top_r[:]
weights_r = [red_c.get(n, 0.5) for n in cand]
while len(sel) < rcnt and cand:
tw = sum(weights_r)
if tw <= 0: pk = random.choice(cand)
else:
rv = random.random() * tw
cum = 0
for i, ww in enumerate(weights_r):
cum += ww
if rv <= cum:
pk = cand[i]
break
if pk not in sel: sel.append(pk)
idx = cand.index(pk); cand.pop(idx); weights_r.pop(idx)
sel.sort()
bls = []
cand_b = top_b[:]
weights_b = [blue_c.get(n, 0.5) for n in cand_b]
while len(bls) < bcnt and cand_b:
tw = sum(weights_b)
if tw <= 0: pk = random.choice(cand_b)
else:
rv = random.random() * tw
cum = 0
for i, ww in enumerate(weights_b):
cum += ww
if rv <= cum:
pk = cand_b[i]
break
if pk not in bls: bls.append(pk)
idx = cand_b.index(pk); cand_b.pop(idx); weights_b.pop(idx)
bls.sort()
return sel, bls
def backtest_optimize(self, test_periods=30):
"""
通过回测优化各模型权重
使用简单网格搜索 + 梯度上升混合方法
"""
rule = self.rule
rmax, bmax = self.rule["red_max"], self.rule["blue_max"]
print(f"\n{'='*60}")
print(f"🧠 集成学习权重优化 | 彩种: {rule['name']} | 数据期数: {len(self.data)}")
print(f"{'='*60}")
# 准备回测数据(按时间顺序)
sorted_data = sorted(self.data, key=lambda x: int(x["issue"]))
if len(sorted_data) < test_periods + 10:
test_periods = max(10, len(sorted_data) - 10)
# 评分函数:计算推荐与实际匹配的分数
def evaluate(weights, data_slice):
red_comp, blue_comp = self._get_combined_for_weights(weights)
pred_r, pred_b = self._predict_from_scores(red_comp, blue_comp, rmax, bmax, rule["red_count"], rule["blue_count"])
actual = data_slice
act_r = [int(x) for x in actual["reds"]]
act_b = actual["blue"] if isinstance(actual["blue"], list) else [int(actual["blue"])]
# 评分:命中红球数*2 + 命中蓝球数
hit_r = sum(1 for n in pred_r if n in act_r)
hit_b = sum(1 for n in pred_b if n in act_b if (isinstance(act_b, list) and n in act_b) or (isinstance(act_b, int) and n == act_b))
return hit_r * 2 + hit_b
# 简单网格搜索优化权重
best_weights = self.weights.copy()
best_score = float('-inf')
# 初始评估
current_score = 0
for i in range(test_periods):
if i + 10 < len(sorted_data):
slice_data = sorted_data[i + 10:i + 11] # 下一期作为测试
current_score += evaluate(self.weights, slice_data[0])
print(f" 初始等权总分: {current_score:.1f}")
# 简单梯度上升(每个模型权重微调)
improved = True
iterations = 0
max_iterations = 20
while improved and iterations < max_iterations:
improved = False
iterations += 1
for model_name in self.weights:
for delta in [-0.05, 0.05]: # 微调权重
test_w = self.weights.copy()
test_w[model_name] = max(0.01, min(0.9, test_w[model_name] + delta))
# 归一化
total = sum(test_w.values())
test_w = {k: v/total for k, v in test_w.items()}
score = 0
for i in range(test_periods):
if i + 10 < len(sorted_data):
slice_data = sorted_data[i + 10:i + 11]
score += evaluate(test_w, slice_data[0])
if score > best_score:
best_score = score
best_weights = test_w.copy()
improved = True
self.weights = best_weights
self.backtest_results = {
'iterations': iterations,
'best_score': best_score,
'test_periods': test_periods,
'model_weights': best_weights
}
# 输出各模型权重
print(f" 优化后权重:")
for m, w in sorted(self.weights.items(), key=lambda x: -x[1]):
model_names = {
'freq': '频率加权',
'bayes': '贝叶斯平滑',
'markov': '马尔可夫链',
'kmeans': 'K-Means聚类',
'residual': '残差回归'
}
print(f" {model_names.get(m, m):<12s}: {w:.4f}")
print(f" 最终集成总分: {best_score:.1f} (测试{test_periods}期)")
# 返回综合评分
return self.get_combined_score()
def get_recommendations(self, count=5):
"""基于集成评分生成推荐"""
red_comp, blue_comp = self.get_combined_score()
rmax, bmax = self.rule["red_max"], self.rule["blue_max"]
rcnt, bcnt = self.rule["red_count"], self.rule["blue_count"]
sorted_r = sorted(red_comp.items(), key=lambda x: x[1], reverse=True)
top_r = [n for n, s in sorted_r[:rmax]]
sorted_b = sorted(blue_comp.items(), key=lambda x: x[1], reverse=True)
top_b = [n for n, s in sorted_b[:bmax]]
seed = hashlib.md5(f"{self.lt}_ensemble".encode()).hexdigest()
res = []
for ci in range(count):
cs = hashlib.md5(f"ensemble_c{ci}_{seed}".encode()).hexdigest()
cr = random.Random(cs)
sel = []
cand = top_r[:]
w = [red_comp.get(n, 0.5) for n in cand]
while len(sel) < rcnt and cand:
tw = sum(w)
if tw <= 0: pk = cr.choice(cand)
else:
rv = cr.random() * tw
cum = 0
for i, ww in enumerate(w):
cum += ww
if rv <= cum:
pk = cand[i]
break
if pk not in sel: sel.append(pk)
idx = cand.index(pk); cand.pop(idx); w.pop(idx)
sel.sort()
bls = []
cand_b = top_b[:]
wb = [blue_comp.get(n, 0.5) for n in cand_b]
while len(bls) < bcnt and cand_b:
tw = sum(wb)
if tw <= 0: pk = cr.choice(cand_b)
else:
rv = cr.random() * tw
cum = 0
for i, ww in enumerate(wb):
cum += ww
if rv <= cum:
pk = cand_b[i]
break
if pk not in bls: bls.append(pk)
idx = cand_b.index(pk); cand_b.pop(idx); wb.pop(idx)
bls.sort()
score = round(sum(red_comp.get(n, 0) for n in sel) + sum(blue_comp.get(n, 0) for n in bls), 4)
mid = rmax / 2
res.append({
"reds": sel,
"blues": bls,
"score": score,
"odd_even": f"{sum(1 for n in sel if n % 2 == 1)}:{rcnt - sum(1 for n in sel if n % 2 == 1)}",
"big_small": f"{sum(1 for n in sel if n > mid)}:{rcnt - sum(1 for n in sel if n > mid)}",
"sum": sum(sel)
})
res.sort(key=lambda x: x["score"], reverse=True)
return res
# ==================== 主函数 ====================
def ensemble_recommendation(lt, data, rule, count=5):
"""集成学习推荐主接口"""
learner = EnsembleLearner(lt, data, rule)
red_comp, blue_comp = learner.backtest_optimize(test_periods=30)
recommendations = learner.get_recommendations(count=count)
return {
'weights': learner.weights,
'backtest': learner.backtest_results,
'recommendations': recommendations,
'combined_scores': {
'red': red_comp,
'blue': blue_comp
}
}
if __name__ == "__main__":
# 简单测试
print("集成学习模块加载成功!")
print("可用模型:频率加权、贝叶斯平滑、马尔可夫链、K-Means聚类、残差回归")
+285
View File
@@ -0,0 +1,285 @@
#!/usr/bin/env python3
"""
回滚迭代跟踪工具 - 管理 AI 进化版本和回滚机制
"""
import json
import os
from datetime import datetime
from typing import Dict, List, Optional, Any
from pathlib import Path
class EvolutionTracker:
"""回滚迭代跟踪器"""
def __init__(self, data_dir: str = "./evolution_tracking"):
self.data_dir = Path(data_dir)
self.data_dir.mkdir(parents=True, exist_ok=True)
self.version_file = self.data_dir / "versions.json"
self.performance_log = self.data_dir / "performance.json"
self.rollback_log = self.data_dir / "rollbacks.json"
def initialize(self):
"""初始化跟踪器"""
# 初始化版本记录
if not self.version_file.exists():
initial_version = {
"version": 0,
"created_at": datetime.now().isoformat(),
"performance": {
"win_rate": 0.0,
"total_bets": 0,
"total_winnings": 0.0
}
}
self.save_version(initial_version)
# 初始化性能日志
if not self.performance_log.exists():
self.save_performance({
"history": [],
"current": {
"total_bets": 0,
"win_rate": 0.0,
"earnings": 0.0,
"total_winnings": 0.0
}
})
# 初始化回滚日志
if not self.rollback_log.exists():
self.save_rollbacks({
"history": [],
"current_version": 0
})
def save_version(self, version_data: Dict):
"""保存版本信息"""
with open(self.version_file, 'w', encoding='utf-8') as f:
json.dump(version_data, f, ensure_ascii=False, indent=2)
def load_version(self) -> Dict:
"""加载当前版本"""
if self.version_file.exists():
with open(self.version_file, 'r', encoding='utf-8') as f:
return json.load(f)
return {}
def record_performance(self, version: int, win_rate: float, earnings: float):
"""记录性能数据"""
performance = self.load_performance()
entry = {
"version": version,
"recorded_at": datetime.now().isoformat(),
"win_rate": win_rate,
"earnings": earnings,
"total_bets": performance["current"].get("total_bets", 0),
"total_winnings": performance["current"].get("total_winnings", 0.0)
}
performance["history"].append(entry)
# 更新当前性能
current = performance["current"]
current["total_bets"] += 1
current["win_rate"] = win_rate
current["earnings"] = earnings
current["total_winnings"] = current.get("total_winnings", 0.0) + earnings
self.save_performance(performance)
def load_performance(self) -> Dict:
"""加载性能日志"""
if self.performance_log.exists():
with open(self.performance_log, 'r', encoding='utf-8') as f:
return json.load(f)
return {"history": [], "current": {}}
def save_performance(self, performance: Dict):
"""保存性能日志"""
with open(self.performance_log, 'w', encoding='utf-8') as f:
json.dump(performance, f, ensure_ascii=False, indent=2)
def record_rollback(self, from_version: int, to_version: int, reason: str):
"""记录回滚操作"""
rollbacks = self.load_rollbacks()
entry = {
"from_version": from_version,
"to_version": to_version,
"reason": reason,
"timestamp": datetime.now().isoformat()
}
rollbacks["history"].append(entry)
rollbacks["current_version"] = to_version
self.save_rollbacks(rollbacks)
def load_rollbacks(self) -> Dict:
"""加载回滚日志"""
if self.rollback_log.exists():
with open(self.rollback_log, 'r', encoding='utf-8') as f:
return json.load(f)
return {"history": [], "current_version": 0}
def save_rollbacks(self, rollbacks: Dict):
"""保存回滚日志"""
with open(self.rollback_log, 'w', encoding='utf-8') as f:
json.dump(rollbacks, f, ensure_ascii=False, indent=2)
def get_version_history(self) -> List[Dict]:
"""获取版本历史"""
performance = self.load_performance()
return performance.get("history", [])
def get_best_version(self) -> Optional[Dict]:
"""获取性能最好的版本"""
history = self.get_version_history()
if not history:
return None
best = max(history, key=lambda x: x.get("win_rate", 0))
return best
def compare_versions(self, version1: int, version2: int) -> Dict:
"""比较两个版本的性能"""
history = self.get_version_history()
v1_data = next((h for h in history if h["version"] == version1), None)
v2_data = next((h for h in history if h["version"] == version2), None)
if not v1_data or not v2_data:
return {"error": "版本不存在"}
comparison = {
"version1": version1,
"version2": version2,
"v1_win_rate": v1_data.get("win_rate", 0),
"v2_win_rate": v2_data.get("win_rate", 0),
"v1_earnings": v1_data.get("earnings", 0.0),
"v2_earnings": v2_data.get("earnings", 0.0),
"better_version": version1 if v1_data.get("win_rate", 0) > v2_data.get("win_rate", 0) else version2
}
return comparison
def generate_report(self) -> str:
"""生成进化报告"""
performance = self.load_performance()
rollbacks = self.load_rollbacks()
report = [
"="*60,
"AI 进化跟踪报告",
"="*60,
f"当前版本:{rollbacks.get('current_version', 0)}",
f"回滚历史数:{len(rollbacks.get('history', []))}",
"\n当前性能数据:",
f" 胜率:{performance['current'].get('win_rate', 0):.2%}",
f" 累计投注:{performance['current'].get('total_bets', 0)}",
f" 累计收益:¥{performance['current'].get('total_winnings', 0.0):.2f}",
"\n版本历史:",
]
history = performance.get("history", [])
if history:
for i, entry in enumerate(history[-10:], 1): # 显示最后 10 个
report.extend([
f" [v{entry['version']}] 胜率:{entry['win_rate']:.2%}, "
f"收益:¥{entry['earnings']:.2f}, "
f"记录时间:{entry['recorded_at']}",
""
])
else:
report.append(" 暂无历史数据")
report.extend(["\n回滚历史:", ""])
if rollbacks.get("history"):
for i, entry in enumerate(rollbacks["history"]):
report.extend([
f" 回滚 #{i+1}: v{entry['from_version']} → v{entry['to_version']}, "
f"原因:{entry['reason']}, "
f"时间:{entry['timestamp']}",
""
])
else:
report.append(" 暂无回滚记录")
report.extend(["="*60, ""])
return "\n".join(report)
def optimize_weights(self, learning_rate: float = 0.1, epochs: int = 100) -> Dict:
"""优化模型权重 - 模拟进化过程"""
import random
# 初始化权重
weights = {
"red_hot": 0.3,
"red_cold": 0.2,
"consecutive": 0.15,
"sum_range": 0.15,
"parity": 0.1,
"entropy": 0.1
}
# 模拟进化过程
for epoch in range(epochs):
# 模拟数据输入
sample_data = [random.randint(1, 33) for _ in range(10)]
# 计算损失
loss = sum((w - random.random())**2 for w in weights.values())
# 梯度下降
for key in weights:
gradient = sum(random.random() for _ in range(10)) / len(sample_data)
weights[key] -= learning_rate * gradient
# 归一化权重
total = sum(weights.values())
weights = {k: round(v/total, 4) for k, v in weights.items()}
return {
"optimized_weights": weights,
"epochs_completed": epochs,
"final_loss": round(loss, 4)
}
def main():
"""主函数 - 测试回滚跟踪工具"""
tracker = EvolutionTracker()
tracker.initialize()
# 模拟一些版本记录
versions = [
(1, 0.05, 100.0),
(2, 0.12, 150.0),
(3, 0.08, 120.0),
(4, 0.15, 200.0),
(5, 0.18, 250.0)
]
for version, win_rate, earnings in versions:
tracker.record_performance(version, win_rate, earnings)
# 模拟回滚
tracker.record_rollback(5, 4, "性能下降")
# 生成报告
print(tracker.generate_report())
# 优化权重
optimized = tracker.optimize_weights()
print("\n优化结果:")
print(f" 完成轮数:{optimized['epochs_completed']}")
print(f" 最终损失:{optimized['final_loss']}")
print(f" 优化权重:{optimized['optimized_weights']}")
if __name__ == "__main__":
main()
File diff suppressed because it is too large. Load diff
+300
View File
@@ -0,0 +1,300 @@
#!/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 开奖后把实际号码发我,帮你回滚迭代校正精度 🍀")
@@ -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 开奖后把实际号码发我,帮你回滚迭代校正精度 🍀")
File diff suppressed because it is too large. Load diff
+38
View File
@@ -0,0 +1,38 @@
{
"id": "lottery_picker",
"name": "彩票智能分析",
"description": "双色球(SSQ)和大乐透(DLT)的智能号码分析与机选推荐工具,基于多维度数学模型 + AI概率分析,提供数据采集、推理分析、机选推荐和回滚迭代完整流程。",
"version": "1.0.0",
"author": "QwenPaw彩票分析系统",
"keywords": [
"双色球",
"大乐透",
"彩票",
"机选",
"AI分析"
],
"enabled": true,
"main": "lottery_tool.py",
"triggers": [
{
"type": "keyword",
"keywords": [
"双色球",
"大乐透",
"彩票",
"今日彩票",
"机选",
"买彩票"
]
}
],
"requirements": [
"requests",
"beautifulsoup4",
"markdown"
],
"entrypoint": "lottery_tool.py",
"documentation": "SKILL.md",
"created_at": "2026-05-25T21:44:04.764539",
"updated_at": "2026-05-25T21:44:04.764539"
}