# 股票估值判断逻辑详解

> **最后更新**: 2026-02-02
> **重要更新**: 修复股票筛选评分公式的量纲不一致问题，改用分位数归一化法

## 2026-03-22 前端展示修正

个股详情页中的 PE / PB 分位图不再使用多段彩色占位柱状图，而改为单值圆环分位图：

- 圆环高亮部分直接表示当前 `PE` 或 `PB` 所处历史分位
- `< 30%` 视为偏低估，`> 70%` 视为偏高估

这样前端展示和估值逻辑保持一致，避免把“历史分位”误渲染成一组无实际含义的彩色条块。

## 2026-05-13 详情页加载策略修正

- `GET /api/equity/valuation/<stock_code>/` 改为缓存优先读取：先返回本地/Data Center 已有估值、财务和最近日线，再仅在完全缺数据时触发 on-demand hydration。
- 个股详情页前端不再把技术图和实时价格串行挂在估值接口后面，避免单个慢数据源把整页长期卡在“加载中”。
- 估值接口前端请求增加超时保护，超时后页面仍继续展示代码、技术图、实时价和其他模块，估值卡片保持降级状态。

## 2026-05-14 技术图默认时间框架改为按市场会话判断

- 个股详情页不再在前端写死 `Asia/Shanghai` 和 A 股交易时段。
- 页面初始化时会读取后端注入的 `market_session_profile`，按股票所属交易所的时区和会话窗口决定默认显示 `分时` 还是 `日线`。
- 对已配置交易会话的市场，收盘后默认仍优先展示最近完整交易时段的 `分时`，避免用户在非盘中只能先看到 `日线` 才能再手动切回分时。
- 技术图前端现增加同页 timeframe 缓存与后台预取，日线 / 分时 / 周线 / 月线来回切换时不再每次都重新等待完整接口链路。
- 分时接口优先读取本地/Data Center 已落库的 `quote_snapshot`，仅在本地快照不足时再回退到 AKShare 主备分钟链路，减少详情页切换时的阻塞。
- 当前已内置 A 股、港股、美股和法兰克福会话配置；新增市场时应扩展后端市场会话注册表，而不是在模板里追加硬编码判断。

## 快速理解：系统如何判断低估还是高估？

---

## 股票筛选评分公式（更新于 2026-02-02）

## 详情页估值与行情颜色约定（更新于 2026-03-23）

- 详情页 PE/PB 分位图使用固定高度画布容器，避免 Chart.js 重绘导致页面滚动条持续变长。
- 行情相关颜色不再直接依赖页面里的 `text-red/text-green`，而是统一使用 `text-rise`、`text-fall`、`text-inflow`、`text-outflow`。
- 上述语义色由系统配置 `SystemSettingsModel.market_color_convention` 决定，默认采用 A 股 `红涨绿跌`，如需切换美股习惯可在系统配置中统一调整。
- 股票池页面中的 ROE、营收增长、利润增长高亮也已切换到同一套语义 token，避免和详情页出现颜色理解不一致。

### 背景问题

旧版本评分公式存在**量纲不一致**的金融工程问题：

```python
# ❌ 旧公式（错误）
growth_score = revenue_growth * 0.5 + net_profit_growth * 0.5  # 单位：%
profitability_score = roe  # 单位：%
valuation_score = 100 / pe  # 单位：1/PE（无量纲，但量级不同）

total_score = growth_score * 0.4 + profitability_score * 0.4 + valuation_score * 0.2
```

**问题**：直接将百分比（如 ROE=15%）与倒数项（如 100/PE=10）相加，违反金融工程原则。

### 新公式：分位数归一化法

```python
# ✅ 新公式（正确）
# 步骤 1：计算各指标在全市场中的分位数（0-1）
growth_percentile = (percentile(revenue_growth, 全市场营收增长) +
                    percentile(net_profit_growth, 全市场利润增长)) / 2

profitability_percentile = percentile(roe, 全市场ROE)

valuation_percentile = 1 - percentile(pe, 全市场PE)  # PE越低分越高

# 步骤 2：加权求和（所有指标都在 [0,1] 范围内）
total_score = (growth_percentile * 0.4 +
              profitability_percentile * 0.4 +
              valuation_percentile * 0.2)
```

### 分位数定义

| 分位数 | 含义 | 市场地位 |
|-------|------|---------|
| 1.0 | 全市场最优 | 超过 100% 的股票 |
| 0.8 | 优秀 | 超过 80% 的股票 |
| 0.5 | 平均水平 | 位于市场中位数 |
| 0.2 | 较差 | 低于 80% 的股票 |
| 0.0 | 全市场最差 |

### 优势

1. **消除量纲问题**：所有指标归一化到 [0, 1]
2. **自动适应市场**：牛市/熊市自动调整
3. **结果直观**：0.5 表示市场平均，0.8 表示前 20%
4. **边界安全**：极端值自动处理，不会出现无穷大

### 示例计算

假设全市场有 100 只股票：

| 股票 | 营收增长 | ROE | PE | 营收分位 | ROE分位 | PE分位 | 估值得分(1-PE分位) | **总分** |
|------|---------|-----|---- |---------|-------|-------|------------------|----------|
| A | 30% | 20% | 10 | 0.90 | 0.85 | 0.10 | 0.90 | **0.87** |
| B | 15% | 12% | 25 | 0.50 | 0.50 | 0.50 | 0.50 | **0.50** |
| C | 5% | 8% | 50 | 0.10 | 0.20 | 0.90 | 0.10 | **0.14** |

计算过程（股票A）：
```
growth_percentile = (0.90 + 0.90) / 2 = 0.90  # 营收和利润都是前10%
profitability_percentile = 0.85  # ROE在前15%
valuation_percentile = 1 - 0.10 = 0.90  # PE极低，估值得分高

total_score = 0.90 * 0.4 + 0.85 * 0.4 + 0.90 * 0.2 = 0.87
```

---

### 简单流程

```
输入股票代码
    ↓
获取数据（PE、PB、财务指标、历史数据）
    ↓
┌─────────────────────────────────────────────────┐
│           多维度估值分析（并行）                    │
├─────────────────────────────────────────────────┤
│ 1️⃣ PE/PB 百分位分析（30%）                        │
│    → 当前估值 vs 历史                             │
│    → PE=12，历史[8-25] → 20%分位 → 低估            │
│                                                 │
│ 2️⃣ 相对行业估值（20%）                            │
│    → 当前估值 vs 行业平均                          │
│    → PE/行业PE = 12/20 = 0.6 → 低估 40%          │
│                                                 │
│ 3️⃣ PEG 估值（20%）                               │
│    → PE / 增长率                                  │
│    → 12/30% = 0.4 → 低估                         │
│                                                 │
│ 4️⃣ 质量评分（15%）                               │
│    → ROE、增长率、负债率                           │
│    → ROE=18% → 评分75 → 合理                      │
│                                                 │
│ 5️⃣ DCF 绝对估值（15%）                           │
│    → 计算内在价值                                 │
│    → 内在价值28元 vs 当前23元 → 低估 22%           │
└─────────────────────────────────────────────────┘
    ↓
加权综合评分（0-100）
    ↓
判断信号
├─────────────────┬─────────────────┬─────────────────┐
│  85-100分        │  70-84分        │  40-69分        │
│  强烈买入        │  买入           │  持有           │
└─────────────────┴─────────────────┴─────────────────┘
```

---

## 核心方法详解

### 方法 1: PE/PB 百分位分析 ⭐ 最常用

**问题**：PE=12 到底是贵还是便宜？

**解决**：看历史数据！

```python
# 假设某股票过去 1 年的 PE 数据
历史PE = [25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
         15, 14, 13, 12.5, 12, 11.5, 11, 10.5, 10, 9,
         8.5, 8.2, 8, 8.1, 8.5, ...]

当前PE = 12

# 计算分位数
比12低的历史天数 = 200天
总天数 = 252天
PE百分位 = 200/252 = 79%

# 判断
79% > 70% → 高估（虽然绝对值不高，但相对历史偏高）
```

**阈值**：
- **< 30%**：低估
- **30-70%**：合理
- **> 70%**：高估

---

### 方法 2: 相对行业估值

**问题**：不同行业估值水平不同，PE=20 在银行算贵，但在科技股算便宜

**解决**：和同行业比！

```python
# 示例：某券商股
当前PE = 12
行业平均PE = 15

相对比率 = 12/15 = 0.8

# 判断
0.8 < 0.8 → 不算低估（刚好在临界值）
# 如果 < 0.8 才算低估
```

**阈值**：
- **< 0.8**：低估（比行业便宜 20% 以上）
- **0.8-1.2**：合理
- **> 1.2**：高估

---

### 方法 3: PEG 估值（适用于成长股）

**问题**：高 PE 不一定是贵，如果增长快呢？

**解决**：PEG 指标！

```python
# 示例：某成长股
PE = 30
净利润增长率 = 40%

PEG = PE / 增长率 = 30/40 = 0.75

# 判断
PEG < 1 → 低估（增长快足以支撑高估值）
PEG = 1 → 合理
PEG > 1 → 高估
```

**阈值**：
- **< 0.8**：低估
- **0.8-1.2**：合理
- **> 1.2**：高估

**注意**：只适用于增长率为正的股票！

---

### 方法 4: 质量评分

**问题**：便宜就是好？不一定，可能是"价值陷阱"

**解决**：评估企业质量！

```python
# 评分系统（满分 100）
基础分 = 50

# ROE（最高 30 分）
ROE = 18%
→ 加 20 分

# 营收增长（最高 20 分）
营收增长 = 15%
→ 加 10 分

# 净利润增长（最高 20 分）
利润增长 = 20%
→ 加 15 分

# 资产负债率（扣分项）
负债率 = 55%
→ 扣 10 分

总分 = 50 + 20 + 10 + 15 - 10 = 85 分

# 判断
85分 > 80分 → 低估（质量好，隐含低估）
```

**阈值**：
- **≥ 80**：低估（质量好）
- **60-79**：合理
- **< 60**：高估（质量差）

---

### 方法 5: DCF 绝对估值

**问题**：能不能算出股票"值多少钱"？

**解决**：自由现金流折现模型！

```python
# 步骤 1: 预测未来现金流
当前自由现金流 = 10 亿
增长率 = 10%

第1年现金流 = 10 × 1.1 = 11 亿
第2年现金流 = 10 × 1.1² = 12.1 亿
第3年现金流 = 10 × 1.1³ = 13.31 亿
第4年现金流 = 10 × 1.1⁴ = 14.64 亿
第5年现金流 = 10 × 1.1⁵ = 16.11 亿

# 步骤 2: 折现到现值（折现率 10%）
PV1 = 11 / 1.1 = 10 亿
PV2 = 12.1 / 1.1² = 10 亿
PV3 = 13.31 / 1.1³ = 10 亿
PV4 = 14.64 / 1.1⁴ = 10 亿
PV5 = 16.11 / 1.1⁵ = 10 亿
现值之和 = 50 亿

# 步骤 3: 计算终值（永续增长 3%）
终值 = 16.11 × 1.03 / (0.10 - 0.03) = 237 亿
终值现值 = 237 / 1.1⁵ = 147 亿

# 步骤 4: 企业总价值
总价值 = 50 + 147 = 197 亿

# 步骤 5: 判断
当前市值 = 150 亿
内在价值 = 197 亿
197 > 150 → 低估
上涨空间 = 197/150 - 1 = 31%
```

---

## 综合判断示例

### 案例：某券商股（600030.SH）

| 方法 | 评分 | 信号 | 说明 |
|------|------|------|------|
| PE/PB 百分位 | 80 | 低估 | PE=12，处于历史 20% 分位 |
| 相对行业 | 70 | 低估 | 比行业平均便宜 20% |
| PEG | 85 | 低估 | PEG=0.5，增长快估值低 |
| 质量评分 | 65 | 合理 | ROE=16%，质量不错 |
| DCF | 75 | 低估 | 内在价值 28 元 vs 当前 23 元 |

**综合评分** = 80×0.3 + 70×0.2 + 85×0.2 + 65×0.15 + 75×0.15
             = 24 + 14 + 17 + 9.75 + 11.25
             = **76 分**

**综合信号**：买入（70-84 分）
**置信度**：0.82（4/5 方法认为低估）

---

## 特殊情况处理

### 1. 周期股

**问题**：周期股在景气顶点盈利好、PE 低，但反而是高估！

**调整**：
- 不看 PE，看 PB
- 看 ROE 相对于历史的位置
- 在 ROE 高位时反而要谨慎

```python
# 示例：某航运股
当前PE = 5  # 看起来很便宜
当前ROE = 30%  # 历史高位
当前PB = 1.5  # 历史高位

# 判断
虽然 PE 低，但 ROE 和 PB 都在历史高位
→ 可能是周期顶部，反而要谨慎
→ 综合信号：高估
```

### 2. 成长股

**问题**：高 PE 但高增长

**调整**：
- 使用 PEG 而不是 PE
- 关注营收和利润增长可持续性
- 可以容忍更高的估值

```python
# 示例：某科技股
当前PE = 50  # 看起来很贵
净利润增长 = 50%
PEG = 1.0  # 合理

# 判断
PEG 合理，增长持续
→ 综合信号：合理/低估
```

### 3. 亏损股

**问题**：PE 为负，无法用常规方法

**调整**：
- 使用 PB 或 PS（市销率）
- 关注现金流
- 评估扭亏预期

```python
# 示例：某亏损股
PE = 负数  # 无法计算
PB = 1.2  # 可以用
PS = 2.0  # 可以用
营收增长 = 30%  # 快速增长

# 判断
虽然亏损，但营收快速增长
→ 如果有扭亏预期，可以考虑
→ 综合信号：合理（高风险）
```

---

## 最佳实践

### 数据同步说明

个股详情页的估值与财务指标优先读取 data_center 事实表，再回退到 equity 本地表。AKShare 财务指标同步使用东方财富主要指标接口，写入 `data_center_financial_fact` 后即可被详情页读取；估值指标同步使用百度股市通估值序列，市值统一换算为元。

### ✅ DO（应该做的）

1. **结合多种方法**：不要只看一个指标
2. **关注置信度**：低置信度的判断要谨慎
3. **定期更新**：估值数据每月更新
4. **结合宏观**：在衰退期更保守，复苏期更积极
5. **了解行业**：不同行业的估值逻辑不同

### ❌ DON'T（不应该做的）

1. **机械套用**：不要生搬硬套阈值
2. **忽视周期**：周期股不能用常规方法
3. **只看估值**：好公司太贵也不要买
4. **追涨杀跌**：低估时不买，高估时不卖
5. **忽视风险**：低估值可能有合理的理由

---

## 快速查询表

| 指标 | 低估阈值 | 合理区间 | 高估阈值 |
|------|---------|---------|---------|
| PE 百分位 | < 30% | 30-70% | > 70% |
| PB 百分位 | < 30% | 30-70% | > 70% |
| 相对行业比率 | < 0.8 | 0.8-1.2 | > 1.2 |
| PEG | < 0.8 | 0.8-1.2 | > 1.2 |
| 质量评分 | ≥ 80 | 60-79 | < 60 |
| 综合评分 | ≥ 85 | 40-84 | < 40 |

---

## API 使用示例

```python
# 1. 获取 PE/PB 百分位分析
GET /api/equity/valuation/600030.SH/?lookback_days=252

# 2. 获取 DCF 估值
POST /api/equity/dcf/
{
    "stock_code": "600030.SH",
    "growth_rate": 0.1,
    "discount_rate": 0.1
}

# 3. 获取综合估值（推荐）
POST /api/equity/comprehensive-valuation/
{
    "stock_code": "600030.SH",
    "lookback_days": 252,
    "industry_avg_pe": 20.0,
    "industry_avg_pb": 2.0
}
```
