# 预测逻辑记录

> 项目路径:`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`(数据不支持,且方向矛盾);
- 若未来要重新评估,应先积累样本并沿用「训练段选参 + 评估段验证」的流程,不要用全量数据直接调参。