# 预测逻辑记录
> 项目路径:`F:\opclab\predict`
> 适用彩种:七星彩、排列五
> 说明:彩票开奖结果本质上是随机事件,本项目只做历史开奖数据的统计推演、记录、展示与复盘,不承诺命中。
## 1. 数据范围
### 首次初始化
- 第一次运行时分别抓取:
- 七星彩最近 100 期;
- 排列五最近 100 期。
- 数据来源使用 `api/api文档.txt` 中提供的接口:
- 七星彩:`https://cn.apihz.cn/api/caipiao/qixingcai.php`
- 排列五:`https://cn.apihz.cn/api/caipiao/pailie5.php`
- 最新一期不带 `qh` 参数获取。
- 历史期号通过最新期号向前递减查询,抓满 100 条有效记录。
- 主接口异常时,自动切换到 `docs/API.txt` 中的备用接口。
### 持续更新
- 按开奖节奏定时调用接口获取最新一期。
- 若接口返回期号已存在,则不重复写入。
- 若出现新期号,则保存到本地 JSON 数据库。
## 2. 开奖与预测时间设置
### 排列五
- 预测时间:每天 17:00。
- 开奖数据拉取与复盘时间:每天 22:00。
### 七星彩
- 预测时间:每周二、周五、周日 17:01。
- 开奖数据拉取与复盘时间:每周二、周五、周日 22:01。
> 七星彩与排列五错峰 1 分钟(排列五保持 17:00 / 22:00)。原因:两彩种定时任务若在同一秒触发,
> 会并发"读-改-写"同一份 JSON,后写者覆盖先写者导致预测/复盘记录丢失;错峰 + 写入加锁双保险防丢。
> 17:00 做的是下一期预测;22:00 尝试获取最新开奖数据,并对上一期预测做复盘。开奖约在 21:30 进行,
> 复盘定在 22:00 是为开奖号落地留出时间,避免过早抓取到尚未更新的开奖数据。
## 3. 预测对象
### 七星彩
- 重点预测:前 4 位。
- 原始开奖数据仍完整保存 7 位,便于后续扩展。
### 排列五
- 预测完整 5 位。
## 4. 位置命名
| 数字第N位 | 名称 |
|---|---:|
| 第1位 | 个位 |
| 第2位 | 十位 |
| 第3位 | 百位 |
| 第4位 | 千位 |
| 第5位 | 万位 |
| 第6位 | 十万位 |
| 第7位 | 百万位 |
## 5. 分位统计逻辑
每个位置单独统计,不把号码整体混在一起。
对每一位每个数字计算以下 **13 个维度**的综合评分:
### 5.1 基础频率(已有)
1. **近 100 期出现次数** — 长期位置属性
2. **近 60 期出现次数** — 中期稳定性
3. **近 30 期出现次数** — 短期热度
4. **趋势修正** — 近30对近60的变化方向
### 5.2 号码遗漏(已有)
5. **当前遗漏期数** — 该数字多久没出现。分段评分:
- 遗漏 0:0.25(刚出过)
- 遗漏 1-8:0.35→0.70(逐步升温)
- 遗漏 9-25:0.85(最佳回补区间)
- 遗漏 26-35:0.75(开始回落)
- 遗漏 >35:0.55(不盲目追冷)
### 5.3 走势分析(新增)
6. **号码走势** — 该数字在最近15期的出现频率趋势(前一半 vs 后一半),升温加分、降温减分。
7. **大小走势** — 该位置最近15期的大号(5-9)比例趋势,匹配当前趋势加分。
8. **单双走势** — 该位置最近15期的奇数比例趋势。
9. **质合走势** — 该位置最近15期的质数(2,3,5,7)比例趋势。
### 5.4 遗漏分析扩展(新增)
10. **大小遗漏** — 该位置上次出现同大小属性的数字距今多少期。
11. **单双遗漏** — 该位置上次出现同奇偶属性的数字距今多少期。
12. **质合遗漏** — 该位置上次出现同质合属性的数字距今多少期。
### 5.5 整体结构走势(新增)
13. **和值走势** — 最近10期和值前半均值 vs 后半均值,判断上升/下降/平稳。
14. **和值遗漏** — 优先和值区间多久没出现。
15. **连号走势** — 最近20期相邻位置连续数字(如 2-3、5-6)的出现频率趋势。
## 6. 综合评分模型
每个位置的 0—9 都会得到一个综合分。
### 当前评分权重
| 指标 | 权重 | 含义 |
|---|---:|---|
| 近30期频率 | 28% | 近期热度 |
| 近60期频率 | 20% | 中期稳定度 |
| 近100期频率 | 12% | 长期位置属性 |
| 号码遗漏成熟度 | 15% | 长时间未出后的回补参考 |
| 趋势修正 | 4% | 近30相对近60是否升温 |
| 号码走势 | 3% | 该数字出现频率趋势 |
| 大小走势 | 3% | 大小属性趋势匹配 |
| 单双走势 | 3% | 奇偶属性趋势匹配 |
| 质合走势 | 2% | 质合属性趋势匹配 |
| 大小遗漏 | 3% | 大小属性遗漏回补 |
| 单双遗漏 | 3% | 奇偶属性遗漏回补 |
| 质合遗漏 | 2% | 质合属性遗漏回补 |
| 连号走势(结构) | 2% | 连号趋势(结构评分用) |
> 总权重 = 1.0(100%)
## 7. 结构过滤逻辑
分位候选号码生成后,再用整体结构筛选组合。
### 七星彩前4位
- 和值优先区间:14—23;
- 核心和值:16—21;
- 跨度优先:4—8;
- 奇偶优先:2奇2偶,其次 1奇3偶 / 3奇1偶;
- 大小优先:2大2小,其次 1大3小 / 3大1小;
- 质合优先:2质2合,其次 1质3合 / 3质1合;
- 连号加分:存在相邻连续数字 +0.4;
- 和值走势匹配 +0.25;
- 和值遗漏回补 +0.15。
### 排列五
- 和值优先区间:18—31;
- 核心和值:20—26;
- 跨度优先:5—9;
- 奇偶优先:2奇3偶 / 3奇2偶;
- 大小优先:2大3小 / 3大2小;
- 质合优先:2质3合 / 3质2合 / 1质4合;
- 其余同上。
## 8. 输出结果
每次预测输出:
1. 各位置核心候选号码(7号码模式:3个核心 + 2个次级 + 2个防守);
2. 各位置四号码候选(4号码模式:每位置前4名,由独立的 `four_weights` 反热权重打分排序生成,与7号码分层候选解耦,详见第 12 节);
3. 各位置八号码候选(8号码模式:3核心 + 2次级 + 3防守)——**2026-10-23 起改用完全独立的整期指标体系**(18 项技术指标 + 遗漏值尾/振幅遗漏值尾 + 位置锚点),不再复用 7号码 的分位评分排序,详见第 16 节;
4. 各位置五号码候选(5号码模式:3核心 + 2次级)——**2026-10-23 起改用独立的「全量技术指标」体系**(012路、两数和/和尾/差、余数和尾 3-7、区间分布、形态 + 常用 18 项),不再复用 7号码 的分位评分排序,详见第 17 节;
5. ~~推荐组合(7号码12条 + 4号码12条)~~ —— **2026-10-20 起停止生成**:推荐组合改由「推荐组合」页(`/combo`)统一按置信分层提供,预测记录不再包含 `combinations` / `compact_combinations` / `eight_combinations` / `five_combinations` 字段(历史记录中的旧字段保留但不展示);
6. 每个号码入选理由(含走势和遗漏维度解释);
7. 走势与遗漏分析摘要(各位置大小/单双/质合比例、和值走势、连号走势);
8. 使用的数据期数、最新历史期号、预测目标期号;
9. 结构指标:和值、跨度、奇偶、大小、质合、连号。
## 9. 复盘逻辑
最新开奖出来后,对上一期预测进行复盘:
1. 按位置判断是否命中候选池;
2. 区分命中层级:核心、次级、防守、未命中;
3. 统计本期位置命中率;
4. 四号码独立复盘:判断 4号码 位置命中率(**2026-10-20 起不再计算组合命中**);
5. ~~统计组合是否包含实际号码~~(推荐组合命中改由「推荐组合」页的复盘统计负责);
6. 记录未命中的位置与数字;
7. 根据复盘结果生成纠偏建议。
## 10. 纠偏改善逻辑
当前采用保守纠偏,不自动大幅改模型,避免因单期波动过拟合。
纠偏规则:
- 若连续多期某位置核心候选命中率偏低:提示需要降低近30期热度权重;
- 若未命中数字多为长遗漏号:提示适当提高遗漏成熟度权重;
- 若未命中数字多为近期热号:提示适当提高近30期权重;
- 若大小/单双/质合走势持续偏离:提示调整对应走势权重;
- 若组合结构偏离实际开奖:提示调整和值、跨度、奇偶大小过滤区间;
- 所有纠偏先记录在复盘报告中,通过滚动回测确定最优权重,不直接静默改动核心权重。
## 11. 文件保存
- 开奖数据:`data/draws.json`
- 预测记录:`data/predictions.json`
- 复盘记录:`data/reviews.json`
- 模型状态(含各位置动态权重):`data/model_state.json`
- 抓取状态:`data/update_status.json`
- 配置文件:`config.json`(含 `model.weights` 7号码权重 与 `model.four_weights` 4号码反热权重)
- 逻辑文档:`docs/prediction_logic.md`
- 备用API:`docs/API.txt`
## 12. 4号码独立权重(反热版,2026-09-03 加入)
### 12.1 背景
原实现中"4号码"(每位置 top4 候选)与"7号码"共用同一份按 `model_state.json` 调优的 13 维权重排序,只是截取前 4 名,并非独立逻辑。
对生产数据(截至 2026-09,七星彩 123 期 / 排列五 152 期)做**训练/评估分离回测**发现:
- 七星彩 4号码 单位置 top4 覆盖率约 30~33%,**低于"随机抽 4 个"的 40% 基线**(平均每期命中 1.32/4,随机参照 1.60/4);
- 排列五约 45%,仅略高于随机。
多策略对比(现行 / 出厂默认 / 纯近30热度 / 纯近60 / 纯遗漏 / 纯近100期 / 反热)与分半稳定性检查显示:
- **近 30 期热度权重过重(默认 0.28)是主要拖累**——该段行情热号持续不出("冷号回补"),追热踏空导致精挑细选反而不如瞎猜;
- 降低热度、提高遗漏成熟度的"反热"配置在两个彩种、评估段前后两半均稳定优于现状。
### 12.2 配置与改动
`config.json` 新增 `model.four_weights`(出厂反热版,各位置共用,和=1.0):
| 维度 | 7号码 `weights` | 4号码 `four_weights` |
|---|---:|---:|
| freq_30(近30期热度) | 0.28 | **0.08** |
| freq_60(近60期) | 0.20 | 0.20 |
| freq_100(近100期) | 0.12 | 0.12 |
| omission(遗漏成熟度) | 0.15 | **0.35** |
| 其余走势/遗漏修正维度 | 约 0.25 | 约 0.25 |
`lottery_core.predict()`:4号码候选 `compact_positions` 改用 `four_weights` **独立打分排序**后取每位置前 4 名,再生成 `compact_combinations`;7号码分层候选 `positions` 仍走 `model_state` 各位置权重,完全不受影响。
### 12.3 验证依据(评估段 = 未参与挑选权重的开奖)
| 彩种 | 评估期数 | 现行(追热) | 温和反热 | 纯遗漏(激进) | 随机参照 |
|---|---:|---:|---:|---:|---:|
| 七星彩 qxc | 44 | 1.32/期 | **1.75/期** | 1.89/期 | 1.60/期 |
| 排列五 pl5 | 54 | 2.26/期 | **2.22/期** | 2.30/期 | 2.00/期 |
分半稳定性(前半/后半,平均每期命中):七星彩 反热 1.55 → 1.95;排列五 反热 2.15 → 2.30,两半均高于随机基线。
采用温和反热(而非纯遗漏):保留维度多样性、不易走极端;纯遗漏更准但完全押注单一规律,行情切换时反噬风险最大。
### 12.4 生效范围与维护
- 只影响**之后新生成**预测记录中的 `compact_positions` / `compact_combinations` 及其复盘;已存在的历史预测保持原口径不变。
- `optimize_model`(滚动回测爬山)只调 7号码 的 `model_state` 各位置权重,**不**自动修改 `four_weights`;反热权重为固定配置,需人工在 `config.json` 调整。
- 离线验证/策略对比脚本保留在项目根目录作证据:`offline_four_backtest.py`、`explore_four_strategies.py`。
- 风险:本结论基于当前行情窗口(44~54 期评估),若行情切回"热号连出",反热权重会变钝,届时应重估并调整 `four_weights`。
## 13. 休市规则(2026-10-01 加入)
### 13.1 官方依据
财政部年度公告规定全国彩票市场统一休市(体彩/福彩一致),休市期间除即开型彩票外,停止销售、开奖与兑奖:
| 假期 | 天数 | 2026 年具体时间 |
|---|---:|---|
| 春节 | 10 天 | 2026-02-14 0:00 ~ 2026-02-23 24:00 |
| 国庆节 | 4 天 | 2026-10-01 0:00 ~ 2026-10-04 24:00 |
全年合计休市 14 天。国庆节日期固定;**春节日期每年由公告确定**(2026 年与 2025 年均为春节 10 天、国庆 4 天,但具体日期会变)。
### 13.2 配置方式(`config.json` → `market_closed`)
```json
"market_closed": {
"national_day": ["10-01", "10-04"],
"spring_festival": [
{"year": 2026, "start": "2026-02-14", "end": "2026-02-23"}
]
}
```
- `national_day`:国庆固定区间(`MM-DD`),写死一次,**每年自动生效**;
- `spring_festival`:春节年度表,每年公告发布后**新增一条**(`year` 仅作标记,判定按 `start`/`end`)。
### 13.3 休市期间的行为(`app.py` → `market_closed_reason`)
休市日以下入口全部跳过——**不预测、不抓开奖、不复盘**:
| 入口 | 行为 |
|---|---|
| `scheduled_predict` | 自动预测跳过 |
| `scheduled_update_and_review` | 自动抓取与复盘跳过 |
| `retry_update_and_review` | 取消延迟重试(不再每 30 分钟空转) |
| `action_predict` / `action_update` / `action_review` | 手动按钮拦截,页面提示「彩票市场休市中,已跳过预测、抓取与复盘。」 |
说明:
- **期号逻辑无需改动**——休市结束后首次抓取仍取到休市前最后一期,期号天然连续;
- 休市判定使用服务器本机日期(Asia/Shanghai),不依赖网络时间。
### 13.4 维护
- 每年财政部公告发布后:核对 `national_day` 是否仍为 `10-01~10-04`(近年未变),并在 `spring_festival` 中补当年春节区间;
- 若遇特殊情况临时调整休市安排,以公告为准更新配置,并重启服务(`systemctl restart predict.service`)后生效。
## 14. 一次性跳过预测(`skip_predict`,2026-10-05 加入)
### 14.1 背景
休市期间(10/1~10/4)系统不预测,但休市**之前**的最后一个预测日会"提前覆盖"到恢复后的第一期:
- 2026-10-01 19:00 排列五照常预测,目标期 **26264**(= 休市结束后 10-05 开奖的那一期)。
若 10-05 恢复日排列五再自动预测,目标期仍是 26264(当期要到当天 21:25 才开奖),会产生**同一期两条重复预测**。因此让排列五在 10-05 跳过自动预测,10-06 起恢复。
### 14.2 配置方式(`config.json` → `market_closed.skip_predict`)
```json
"skip_predict": {
"qxc": [],
"pl5": ["2026-10-05"]
}
```
- 键为彩种(`qxc` / `pl5`),值为**具体日期 `YYYY-MM-DD`** 列表(一次性,区别于休市 `national_day` 的 `MM-DD` 年度复用格式);
- 命中列表的当天,该彩种**不执行自动预测**;其余彩种、其余日期不受影响。
### 14.3 行为边界(`app.py` → `skip_predict_reason`)
| 入口 | 是否受影响 |
|---|---|
| `scheduled_predict`(定时自动预测) | ✅ 跳过(本需求目标) |
| `scheduled_update_and_review` / `retry_update_and_review`(抓取与复盘) | ❌ 不受影响——恢复日仍需正常抓开奖,并对已提前生成的预测做实盘复盘 |
| `action_predict`(手动预测按钮) | ❌ 不拦截(手动为显式操作,仍由使用者自行决定) |
### 14.4 说明与维护
- 该配置用于**一次性补偿期**,用完可保留(历史留痕)或清空;
- **七星彩无需配置**:其常规预测日为周二/五/日,2026-10-05(周一)本就不触发预测,10-06(周二)按原规律恢复;
- 同类情况(休市后恢复日已被提前预测覆盖)再次出现时,照此在该彩种下追加日期即可,重启服务生效。
## 15. 推荐组合(2026-10-20 加入)
### 15.1 定位与口径
在「七星彩 / 排列五」子菜单下新增 **推荐组合** 页面(`/combo?lottery=qxc|pl5`),把 **4、5、7、8 号码**四档各自的候选池,按**置信分层**推荐 100 组(高置信 50 / 中置信 30 / 覆盖 20,详见 15.2)。
- **统一前 4 位**:七星彩取千位~个位;排列五也只取前 4 位(第 5 位万位不参与),与现有页面的命中统计口径一致;
- **预测生成 5 分钟后才开始组合**:以预测记录的 `created_at` 为起点,`created_at + 5 分钟` 之前页面不生成组合,只显示倒计时并到点自动刷新(`app.py` → `COMBO_DELAY_MINUTES = 5`);
- **原有 4/5/7/8 号码页面不再显示 12 条推荐组合**(2026-10-20 起):`predict()` 不再生成 `combinations` 系列字段,流水表「组合命中」列、复盘卡片「推荐组合命中」文本同步移除;历史记录中的旧字段保留但不展示;
- 位置候选、评分、权重等预测逻辑保持不变。
### 15.2 生成规则(各档组合池)
| 档位 | 每位置参与组合的候选 | 池大小(前 4 位) | 理论组合数 | 推荐配额 |
|---|---|---|---|---|
| 4号码 | top4(独立反热权重 `four_weights`) | 4 | 4⁴ = 256 | 高 50 + 中 50(无防守层) |
| 5号码 | 核心 3 + 次级 2 | 5 | 5⁴ = 625 | 高 50 + 中 50 |
| 7号码 | 核心 3 + 次级 2(防守不参与,与现有 7号码 一致) | 5 | 5⁴ = 625 | 高 50 + 中 50 |
| 8号码 | 前 8 名(核心 3 + 次级 2 + 防守 3) | 8 | 8⁴ = 4096 | 高 50 + 中 30 + 覆盖 20 |
**置信分层定义**(按每个位置候选的排名,不是单纯按评分截断):
| 层级 | 定义 |
|---|---|
| 高置信 | 4 位全部来自各位置**前 3 名**(核心候选) |
| 中置信 | 4 位都在**前 5 名**,且至少 1 位来自第 4~5 名(次级候选) |
| 覆盖 | 含**第 6~8 名**(防守候选),仅 8号码 有该层 |
- 层内按「各位置评分之和 + 结构过滤得分」排序(`generate_combinations()` + `_tiered_select()`);
- 4/5/7 号码没有防守层,覆盖配额由中置信补满;
- **注意**:5号码与 7号码 的候选池完全相同(都是核心+次级 5 个),因此两档推荐**结果一致**,这是数据结果而非重复计算;
- 分层推荐会**牺牲部分覆盖率换取质量**:评分最高的组合不必然全部入选(例如只含高分但结构雷同的组合会被中置信组合替代)。
### 15.3 命中判定与落盘(只有命中的期才保存)
- 命中条件:开奖号**前 4 位整串**与某档**分层推荐集合(100 组)**中的某一组完全一致(`combo_hit_for_prediction()`);
- 只有命中的期次才落盘到 `data/combo_hits.json`,**未命中的期不写任何内容**;
- 每条命中记录只保存**命中的那一组**(含置信层级 `tier`):
```json
{
"lottery": "pl5", "issue": "26265", "date": "2026-10-06",
"draw": "9546", "profile": "4号码", "tier": "高置信", "combo": "9546",
"created_at": "2026-10-20 02:05:53"
}
```
- 同一期若多档同时命中(如 5号码、7号码 池相同),按档位各记一条;
- 扫描在页面访问时惰性执行(默认最近 30 期),进程内用 `_COMBO_SCAN_DONE` 去重,重启后重扫一次;历史命中可一次性全量补扫(`max_issues=1000`)。
### 15.4 性能与边界
| 项 | 实测 |
|---|---|
| 四档各 100 组合计生成 | 约 0.07 秒 |
| 页面响应(已扫描过) | 0.32 ~ 0.38 秒 |
| 页面响应(重启后首次,含 30 期扫描) | 约 1.3 秒 |
| 首次全量补扫历史 | qxc 30 期 + pl5 92 期,约 3.4 秒(一次性) |
- 组合仅为**统计推演结果**,不承诺命中;推荐集合是分层选取的 100 组,既不是池的全部组合,也不等于评分最高的 100 组;
- 新增文件仅 `templates/combo.html` 与数据文件 `data/combo_hits.json`;`lottery_core.py` 新增的方法均为独立方法,未修改既有预测/复盘逻辑。
### 15.5 每期评估记录(`combo_evals.json`,2026-10-20 加入)
为了给推荐组合积累可复盘、可调优的样本,每期开奖后会记录一条评估记录(**未命中的期也记录**):
```json
{
"lottery": "pl5", "issue": "26269", "date": "2026-10-10", "draw": "0674",
"profiles": {
"four": {"label": "4号码", "eligible": true, "rank": 206, "total": 256, "in_top100": false},
"five": {"label": "5号码", "eligible": true, "rank": 494, "total": 625, "in_top100": false},
"seven": {"label": "7号码", "eligible": true, "rank": 494, "total": 625, "in_top100": false},
"eight": {"label": "8号码", "eligible": true, "rank": 2711, "total": 4096, "in_top100": false}
}
}
```
| 字段 | 含义 |
|---|---|
| `eligible` | 开奖号每一位是否都落在该档候选池内;为 `false` 时该期与组合排序无关,不计入统计 |
| `rank` / `total` | 开奖组合在**全部组合**评分排序中的名次 / 组合总数 |
| `in_top100` / `in_recommended` | 是否进入**分层推荐集合**(100 组);`in_top100` 为兼容旧字段名,语义已改为"在推荐集合内" |
| `tier` | 命中时所在的置信层级(高置信 / 中置信 / 覆盖) |
页面「复盘明细」以**命中结果为主**显示:命中显示「命中 · 高置信/中置信/覆盖」,未命中显示「未命中」,不可评估显示「-」;`rank/total` 作为悬停提示("开奖组合在全部 N 个组合中排第 M 名"),不再直接展示。
- 页面访问时自动补记最近 2 期;历史可用一次性补扫(`scan_combo_evals(max_issues=1000)`,122 期约 3.5 秒);
- **不需要保存 100 组本身**:组合生成是确定性的,同一份预测记录重算结果完全一致,评估时按需重算即可;
- 页面「推荐复盘统计」展示各档可评估期数、命中期数与覆盖率;
- **自动调优门槛**:每档累计满 **30 期可评估样本**后才具备统计基础。当前(2026-10-20)可评估样本为 4/5/7 号码 2~8 期、8 号码 15~44 期,尚不足以训练,因此独立权重调优暂未启用。
## 16. 8号码独立指标体系(2026-10-23 加入)
### 16.1 为什么独立
在此之前,8号码 只是从 7号码 的同一份分位评分排序里截前 8 名(核心3 + 次级2 + 防守3),**没有自己的预测逻辑**,与 7/5 号码完全同源。
2026-10-23 起改为一套完全独立的逻辑:
1. 计算每期开奖的 **18 项整期技术指标**;
2. 对每个指标用「遗漏值尾 / 振幅遗漏值尾」推算下一期的**目标尾数**;
3. 枚举候选组合,按命中目标尾数的数量与强度打分;
4. 叠加**位置锚点**补上位置维度;
5. 由高分组合反推出**每个位置的前 8 名**。
**7号码、5号码、4号码 的候选生成路径与权重一字未动**,见 16.7 的验证方法。
### 16.2 18 项指标与计算公式
记号:`d0 d1 … d(n-1)` 为按开奖位序的数字,`srt` 为升序副本,`n` 为预测位数。
| # | 指标 | 公式 | 统计方式 |
|---|---|---|---|
| 1 | 和值 | `Σ di` | 遗漏值尾 |
| 2 | 和值尾 | `Σ di % 10` | 振幅遗漏值尾 |
| 3 | 均值 | `Σ di // n`(向下取整) | 振幅遗漏值尾 |
| 4 | 跨度 | `max − min` | 振幅遗漏值尾 |
| 5 | 最大值 | `max` | 振幅遗漏值尾 |
| 6 | 中间值 | 排序后中位数(偶数位取中间两个的向下平均) | 振幅遗漏值尾 |
| 7 | 最小值 | `min` | 振幅遗漏值尾 |
| 8 | 余数和 | `Σ (di % 3)` | 遗漏值尾 |
| 9 | 单选位积和 | `Σ di × (i+1)`(按开奖位序加权) | 遗漏值尾 |
| 10 | 组选位积和 | `Σ srt[i] × (i+1)`(按升序位序加权) | 遗漏值尾 |
| 11 | 单选位积和尾 | 第 9 项 `% 10` | 振幅遗漏值尾 |
| 12 | 组选位积和尾 | 第 10 项 `% 10` | 振幅遗漏值尾 |
| 13 | 单选反位积和 | `Σ di × (n−i)`(反向位序加权) | 遗漏值尾 |
| 14 | 组选反位积和 | `Σ srt[i] × (n−i)` | 遗漏值尾 |
| 15 | 单选反位积和尾 | 第 13 项 `% 10` | 振幅遗漏值尾 |
| 16 | 组选反位积和尾 | 第 14 项 `% 10` | 振幅遗漏值尾 |
| 17 | 数字累加 | 前缀和之和:`d0 + (d0+d1) + (d0+d1+d2) + …` | 振幅遗漏值尾 |
| 18 | 位置间距 | 相邻差值绝对值之和:`Σ abs(di − d(i−1))` | 振幅遗漏值尾 |
**计算示例**(号码 `2 5 7 0`,n = 4):
| 指标 | 值 |
|---|---|
| 和值 / 和值尾 | 14 / 4 |
| 均值 | 14 // 4 = 3 |
| 跨度 / 最大值 / 中间值 / 最小值 | 7 / 7 / (2+5)//2 = 3 / 0 |
| 余数和 | 2+2+1+0 = 5 |
| 单选位积和 | 2×1 + 5×2 + 7×3 + 0×4 = **33** |
| 单选反位积和 | 2×4 + 5×3 + 7×2 + 0×1 = **37** |
| 组选(升序 0,2,5,7)位积和 | 0×1 + 2×2 + 5×3 + 7×4 = **47** |
| 组选反位积和 | 0×4 + 2×3 + 5×2 + 7×1 = **23** |
| 数字累加 | 2 + 7 + 14 + 14 = **37** |
| 位置间距 | abs(2−5) + abs(5−7) + abs(7−0) = **12** |
### 16.3 遗漏值尾与振幅遗漏值尾
对某个指标的历史序列 `X`(最新在前):
- **遗漏值尾**:统计尾数 `0~9` 各自的当前遗漏期数(多少期没出现过该尾数),取遗漏最久的尾数作目标;并列时取尾数较小者,保证结果可复现。
- **振幅遗漏值尾**:先算振幅序列 `A[i] = abs(X[i] − X[i+1])`,再对 `A` 的尾数做同样的遗漏统计。
预测时,组合的该项指标若满足:
- 遗漏值尾型:`指标值 % 10 == 目标尾数`
- 振幅遗漏值尾型:`abs(指标值 − 最新一期该项指标值) % 10 == 目标振幅尾数`
即视为命中,累加该指标权重(权重 = 目标尾数的遗漏期数,归一化后使用)。
> **2026-10-23 修正**:目标尾数只在**历史上出现过的尾数**中选取,从未出现过的尾数(`omissions = -1`)不参与。此前把"从未出现"当作"遗漏最久",导致取值域窄的指标(如区间分布计数、和值%3)永远预测一个不可能开出的值——诊断中这类指标准确率为 0%。修正后 0% 命中指标从 53/63/16 项降至 0/7/2 项。详见 17.11。
### 16.4 位置锚点
18 项指标中有 **14 项不区分位置**(和值、跨度、最大/中间/最小、余数和、组选位积和/反位积和及其尾数、全部振幅类),它们只描述"这期由哪些数字组成"。若只靠这 18 项反推,各位置候选会趋同。
位置锚点补上位置维度:
1. 对每个位置,取该位置历史上每期开出数字**当时的遗漏期数尾数**,统计 0~9 各尾数的遗漏;
2. 选遗漏最久的尾数作该位置的目标尾数;
3. 下一期该位置上「当前遗漏期数 `% 10` == 目标尾数」的数字命为锚点;
4. 锚点数字在累计权重时放大 `(1 + anchor_gain)` 倍。
实测效果:七星彩 4 个位置、排列五 5 个位置的候选序列**全部互不相同**。
### 16.5 生成流程
```
最近 100 期开奖
→ 算 18 项整期指标(每期一组)
→ 各指标统计尾数遗漏 → 目标尾数 + 权重
→ 每个位置算遗漏期数尾数 → 位置锚点
→ 枚举全部组合(4 位 1 万组 / 5 位 10 万组)
→ 逐组合算 18 项指标,命中目标尾数则加分
→ 累计权重 score^score_power × 位置锚点增益
→ 每位置取累计权重前 8 名
→ 按 3 / 2 / 3 切分为核心 / 次级 / 防守
```
组合评分只在**至少命中 1 项整期指标**时计入(避免无信息组合稀释位置分布)。
### 16.6 参数配置
`config.json` → `model.eight_indicator`:
```json
"eight_indicator": {
"anchor_gain": 2.0,
"score_power": 3
}
```
| 参数 | 含义 | 调大后的效果 |
|---|---|---|
| `anchor_gain` | 锚点数字的权重增益倍数(实际倍数 = 1 + 该值) | 位置差异更明显,但整期指标的相对影响下降 |
| `score_power` | 组合得分幂次 | 更偏向少数高分组合,候选更集中 |
指标清单本身定义在 `lottery_core.py` 的 `LotteryService.EIGHT_INDICATOR_SPECS`(元组:指标键 / 中文名 / 统计方式 `tail` 或 `amp`)。
### 16.7 隔离性与验证方法
8号码 的独立逻辑只在 `predict()` 末尾调用一次 `predict_eight_by_indicators()`,**不进入 7/5/4 号码的任何代码路径**,也不参与 `optimize_model` 的自调优。
验证方式(改动后应执行的回归):
1. 分别用改动前后的 `lottery_core.py` 对同一份 `draws.json` 计算各位置的
`positions`(7号码)、`compact_positions`(4号码)、`five_positions`(5号码);
2. 对三者做 MD5 对比,应完全一致;
3. 2026-10-23 那次的验证结果:两彩种三个字段 MD5 **全部一致**。
### 16.8 生效范围与历史记录
- 新逻辑从**下一次预测**开始写入 `eight_positions`;
- 历史预测记录里的 `eight_positions` 由旧逻辑(7号码 排序截前 8)生成,**保留原样不再重算**,因此页面上新旧记录的 8号码 口径会并存;
- 候选结构与旧版完全一致(`core` / `secondary` / `defense` / `pool`),模板与 `build_timeline` 无需改动;
- 预测文件体积不受影响(新结构不含 `all_ranked`)。
### 16.9 性能与维护提示
| 彩种 | 组合枚举量 | 单次耗时(本地 Python 3.14) |
|---|---|---|
| 七星彩(4 位) | 10,000 | 约 0.08 秒 |
| 排列五(5 位) | 100,000 | 约 0.82 秒 |
- 生产环境为 Python 3.11 且**未安装 numpy**,因此实现全部使用纯 Python 标准库,未引入任何新依赖;
- 若未来位数增加(>5 位),枚举量会指数上升,需要改为降维或剪枝;
- 该体系目前**不参与复盘与自调优**:`review()` 只按候选是否命中判定,不根据历史命中率反调这 18 项指标的权重。若后续要做,应先积累足够样本再启用,避免拟合噪声。
## 17. 5号码独立指标体系(2026-10-23 加入)
### 17.1 与 8号码 的关系
5号码 与 8号码 是**两套彼此独立的逻辑**,共同点是都采用「整期指标 → 遗漏值尾目标 → 组合评分 → 反推每位置候选」这一框架,区别在指标集:
| | 8号码 | 5号码 |
|---|---|---|
| 指标数量(排列五 / 七星彩) | 18 / 18 项 | **72 / 60 项** |
| 是否含两两位置指标 | 否 | 是(10 组 / 6 组) |
| 是否含 012路、形态、区间 | 否 | 是 |
| 位置锚点 | 需要(14/18 项位置无关) | 默认需要(实测仍趋同) |
| 每位置候选数 | 8(3+2+3) | 5(3+2) |
| 排列五耗时 | 约 0.8 秒 | 约 5 秒 |
改造前,5号码 只是从 7号码 的同一份分位排序里截前 5 名;改造后不再复用任何分位评分结果。
### 17.2 位序与两两位置组合
**位序**(与系统 `numbers` 数组一致,万位在最右):
```
numbers[0] = 千位
numbers[1] = 百位
numbers[2] = 十位
numbers[3] = 个位
numbers[4] = 万位
```
组合按「万 > 千 > 百 > 十 > 个」命名:
| 位数 | 组合数 | 组合 |
|---|---|---|
| 5 位(排列五) | 10 | 万千、万百、万十、万个、千百、千十、千个、百十、百个、十个 |
| 4 位(七星彩) | 6 | 千百、千十、千个、百十、百个、十个 |
### 17.3 指标清单
| 分组 | 排列五 | 七星彩 | 内容 |
|---|---|---|---|
| 常用指标 | 18 | 18 | 和值、和值尾、均值、跨度、最大/中间/最小、余数和、单选/组选位积和及尾、单选/组选反位积和及尾、数字累加、位置间距 |
| 012路 | 4 | 4 | 和值 % 3、0路个数、1路个数、2路个数 |
| 余数和尾 3-7 | 5 | 5 | 各位 ÷ 3/4/5/6/7 的余数之和的尾数 |
| 两数和 | 10 | 6 | 每对位置相加 |
| 两数和尾 | 10 | 6 | 上述和的个位 |
| 两数差 | 10 | 6 | 每对位置差的绝对值 |
| 形态(单期) | 3 | 3 | 奇数个数、大数个数(≥5)、质数个数 |
| 区间分布 | 12 | 12 | 三区/四区/五区各区数字个数 |
| 跨期形态 | 10 | 10 | 复号、隔号、中号、重号、邻号、孤号、热号、温号、冷号、连号对数(**2026-10-23 起参与打分**,用遗漏值尾) |
| **合计(参与打分)** | **82** | **70** | |
**跨期形态口径**:
| 指标 | 算法 |
|---|---|
| 复号 / 重号 | 与上期同位置数字相同的个数(两者口径相同、数值恒等,按需求清单分属两组形态保留两份) |
| 隔号 | 与上上期同位置相同、且不与上期重复的个数 |
| 中号 | 位数 − 复号 − 隔号 |
| 邻号 | 与上期同位置相差 1 的个数 |
| 孤号 | 位数 − 重号 − 邻号 |
| 热号 / 温号 / 冷号 | 按近 30 期出现次数排序,前三为热、后三为冷、其余为温 |
| 连号对数 | 相邻两位差值为 1 的对数 |
候选组合的跨期值也按同一口径计算:把候选当作下一期,与真实最新一期、上上期比较。历史最旧 1~2 期缺少上期/上上期,对应项按 0 计。
**数字区间分法**(用户 2026-10-23 指定):
| 分区 | 划分 |
|---|---|
| 三区 | `0123` / `456` / `789` |
| 四区 | `012` / `34` / `56` / `789` |
| 五区 | `01` / `23` / `45` / `67` / `89` |
**关于重复项**:原需求中的「数字区间综合1-4」与已有指标内容重叠——综合1 是常用 18 项的子集,综合2 等同两数和尾,综合3 等同两数差。因此**只计算一次**,不做重复加权。
### 17.4 位置间距(5号码 新口径)
与 8号码 的「相邻差绝对值之和」不同,5号码 采用用户 2026-10-23 确认的分段口径:
```
前段 = | |d0 − d1| − |d1 − d2| |
后段 = | |d2 − d3| − |d3 − d4| |
位置间距 = |前段 − 后段|
```
**算例**:`74098`(其中 d0=7、d1=4、d2=0、d3=9、d4=8)
```
前段 = | |7−4| − |4−0| | = |3 − 4| = 1
后段 = | |0−9| − |9−8| | = |9 − 1| = 8
位置间距 = |1 − 8| = 7 ← 与需求算例一致
```
4 位时前段用 `d0..d2`、后段用 `d1..d3`(滑动窗口)。
### 17.5 统计方式的确定规则
每个指标需要确定用「遗漏值尾」还是「振幅遗漏值尾」。用户明确标注的按标注执行,未标注的按以下规则推定(集中在 `LotteryService._five_indicator_kind`):
| 指标类 | 方式 | 依据 |
|---|---|---|
| 常用 18 项 | 按原清单逐项标注 | 用户明确 |
| 两数和 | 振幅 | 用户明确 |
| 两数和尾、余数和尾 3-7 | 振幅 | 本身已是尾数,再取尾无意义 |
| 012路个数(0/1/2路) | 振幅 | 用户提到「0路个数振幅」 |
| 形态计数、区间分布、跨期形态(复号/隔号/重号/邻号/孤号/热号/温号/冷号/连号对数) | 遗漏值尾 | 计数类指标 |
| 012路之和值%3(`road012_sum`) | 遗漏值尾 | 非个数类,属余数本身 |
如需调整,改 `FIVE_INDICATOR_KINDS` 常量即可。
### 17.6 遗漏统计五项参数
每项指标的每个尾数(0-9)都统计以下参数,尾数表与振幅尾数表各一份:
| 参数 | 定义 |
|---|---|
| 出现次数 | 该尾数在统计期数内出现的期数 |
| 最大遗漏期数 | 历史最长连续未出现期数 |
| 最大连出期数 | 历史最长连续出现期数 |
| 平均遗漏期数 | 遗漏期数总和 ÷ 出现间隔数 |
| 当前遗漏期数 | 距最新一期已间隔多少期(0 = 本期即出现) |
统计入口:`indicator_report(lottery, limit)`,输出快照见 `data/indicator_report_{lottery}.json`。
> **注意**:均值、跨度、最大值、中间值、余数和这 5 项的尾 0 在最近 100 期从未出现(对应五位全同、全为 0 等极端情况),其当前遗漏恒为统计期数。打分时若直接取「遗漏最久」会让这 5 项永远指向尾 0,需在方案层处理。
### 17.7 生成流程
```
最近 100 期开奖
→ 逐期算 72(或 60)项指标
→ 每项按统计方式取遗漏最久的尾数作目标 + 权重
→ 每个位置算遗漏期数尾数 → 位置锚点
→ 枚举全部组合(4 位 1 万 / 5 位 10 万)
→ 命中目标尾数则按权重累加,score^score_power
→ 乘位置锚点增益
→ 每位置取前 5 名,按 3 / 2 切分为核心 / 次级
```
### 17.8 位置锚点
5号码 虽有 30 项两两位置指标(位置相关),但整期类指标仍占多数。**实测确认会趋同**:
| 彩种 | 未加锚点时 | 加锚点后 |
|---|---|---|
| 七星彩 | 位置1 = 位置2(3/4 唯一) | 4/4 全部不同 |
| 排列五 | 位置3 = 位置5(4/5 唯一) | 5/5 全部不同 |
锚点算法与 8号码 完全相同(见 16.4),共用 `model.eight_indicator.anchor_gain` 参数。
### 17.9 性能与隔离性
| 彩种 | 组合枚举 | 指标项(含跨期) | 5号码 单档耗时 | `predict()` 总耗时 |
|---|---|---|---|---|
| 七星彩 | 10,000 | 70 | 约 0.51 秒 | 约 0.80 秒 |
| 排列五 | 100,000 | 82 | 约 5.78 秒 | 约 6.5 秒 |
- 生产环境 Python 3.11 且未安装 numpy,实现全部使用纯 Python 标准库,无新增依赖;
- 两两组合列表按位数缓存(`_pair_cache`),避免组合枚举时重复计算;
- **隔离性**:改造后用生产版本做 MD5 回归,7号码、4号码 候选两彩种全部一致;8号码 输出不变。
### 17.10 生效范围与维护
- 新逻辑从**下一次预测**开始写入 `five_positions`;
- 历史记录里的 `five_positions` 由旧逻辑(7号码 排序截前 5)生成,保留原样不重算,页面新旧口径并存;
- 候选结构不变(`core` / `secondary` / `defense` / `pool`),模板与 `build_timeline` 无需改动;
- **不参与复盘与自调优**:`review()` 仅按候选是否命中判定,不依据历史命中率反调指标权重;
- 统计快照文件 `data/indicator_report_pl5.json`、`data/indicator_report_qxc.json` 只用于人工核对,不参与预测流程。
### 17.11 参数调优与指标诊断结论(2026-10-23)
为避免后续重复投入,把这一轮的验证结论固化在这里。
**① 参数回测(`backtest_indicator_params`)**
对 `anchor_gain`(1/2/3)× `score_power`(2/3/4)做 walk-forward 回测,训练段/评估段各 30 期:
| 彩种 / 档位 | 训练段 | 评估段 | 随机基线 | 结论 |
|---|---|---|---|---|
| 七星彩 5号码 | 45.0~49.2% | 54.2~58.3% | 50% | 训练段无信号,不稳定 |
| 排列五 8号码 | 80.0~82.0% | 76.7~78.0% | 80% | 评估段低于基线 |
| 七星彩 8号码(50 期) | — | 80.5~81.0% | 80% | 噪声级 |
- **`anchor_gain` 完全无效**:1.0/2.0/3.0 三档命中率完全相同(候选池占 10 个数字的 50%~80%,加权难以改变前 N 名归属);
- **`score_power` 方向矛盾**:七星彩 5号码 `power=4` 最好,排列五 8号码 `power=2` 最好。
**② 指标预测力诊断(`diagnose_indicator_power`)**
逐指标检验"遗漏值尾预测下一期"的准确率,**基线用该指标自己的取值种类数**(不是固定 10%——值域窄的指标基线天然更高):
| 彩种 / 档位 | 指标数 | 显著优于基线(≥+8pp) |
|---|---|---|
| 七星彩 5号码 | 60 | **0 项** |
| 排列五 5号码 | 72 | **0 项** |
| 七星彩 8号码 | 18 | **0 项** |
| 排列五 8号码 | 18 | **0 项** |
**③ 逻辑缺陷修正**
诊断暴露一个真实缺陷:目标尾数可能选中「历史上从未出现过的值」。修正后整体准确率提升(七星彩 5号码 2.7% → 7.3%、排列五 5号码 3.1% → 5.7%、排列五 8号码 4.6% → 5.6%),但仍低于随机水平。
**④ 结论**
- 该指标体系**不参与自动调优**,`optimize_model()` 只调 7号码 的 12 维分位权重;
- 不基于小样本调整 `anchor_gain` / `score_power`(数据不支持,且方向矛盾);
- 若未来要重新评估,应先积累样本并沿用「训练段选参 + 评估段验证」的流程,不要用全量数据直接调参。