# 修复港股代码标准化问题

## 问题描述

用户反馈：分析港股 `00700`（腾讯控股）时，Yahoo Finance 返回错误：

```
ERROR | $00700.HK: possibly delisted; no price data found (1d 2025-09-13 -> 2025-10-13)
```

## 问题分析

### 数据流追踪

```
用户输入: 00700
↓
前端验证: ✅ 港股格式正确（5位数字）
↓
后端验证 (stock_validator.py):
  ├─ _detect_market_type: ✅ 识别为港股
  ├─ 格式化: 00700 → 0700.HK  ✅ 正确
  └─ 验证通过: ✅ 腾讯控股
↓
分析执行 (hk_stock.py):
  ├─ _normalize_hk_symbol: 00700 → 00700.HK  ❌ 错误！
  ├─ Yahoo Finance 查询: 00700.HK
  └─ 返回错误: possibly delisted  ❌
```

### 根本原因

系统中有**两套**港股代码标准化逻辑，它们的处理方式**不一致**：

#### 1. `stock_validator.py` ✅ 正确

```python
# tradingagents/utils/stock_validator.py:428-430
# 移除前导0，然后补齐到4位
clean_code = stock_code.lstrip('0') or '0'
formatted_code = f"{clean_code.zfill(4)}.HK"
# 00700 → 700 → 0700 → 0700.HK ✅
```

**处理逻辑**：
1. `00700` → 移除前导0 → `700`
2. `700` → 补齐到4位 → `0700`
3. `0700` → 添加后缀 → `0700.HK` ✅

#### 2. `hk_stock.py` ❌ 错误

```python
# tradingagents/dataflows/providers/hk/hk_stock.py:222-224 (旧代码)
# 如果是纯4-5位数字，添加.HK后缀
if symbol.isdigit() and 4 <= len(symbol) <= 5:
    return f"{symbol}.HK"
# 00700 → 00700.HK ❌ 错误！
```

**处理逻辑**：
1. `00700` → 检查是5位数字 → ✅
2. `00700` → 直接添加后缀 → `00700.HK` ❌ 错误！

### Yahoo Finance 的期望格式

Yahoo Finance 对港股代码的格式要求：

| 输入 | Yahoo Finance 期望 | 旧代码输出 | 结果 |
|------|-------------------|-----------|------|
| `700` | `0700.HK` | `700.HK` | ❌ 错误 |
| `0700` | `0700.HK` | `0700.HK` | ✅ 正确 |
| `00700` | `0700.HK` | `00700.HK` | ❌ 错误 |
| `9988` | `9988.HK` | `9988.HK` | ✅ 正确 |
| `09988` | `9988.HK` | `09988.HK` | ❌ 错误 |

**规则**：Yahoo Finance 期望港股代码是 **4位数字 + .HK 后缀**。

### 为什么会有两套逻辑？

1. **`stock_validator.py`**：用于验证阶段，确保股票代码存在
2. **`hk_stock.py`**：用于数据获取阶段，从 Yahoo Finance 获取数据

两个模块独立开发，没有统一标准化逻辑，导致不一致。

## 解决方案

### 修复 `hk_stock.py` 的标准化逻辑

统一使用与 `stock_validator.py` 相同的逻辑：**先移除前导0，再补齐到4位**。

```python
# tradingagents/dataflows/providers/hk/hk_stock.py:207-236 (新代码)
def _normalize_hk_symbol(self, symbol: str) -> str:
    """
    标准化港股代码格式
    
    Yahoo Finance 期望的格式：0700.HK（4位数字）
    输入可能的格式：00700, 700, 0700, 0700.HK, 00700.HK

    Args:
        symbol: 原始港股代码

    Returns:
        str: 标准化后的港股代码（格式：0700.HK）
    """
    if not symbol:
        return symbol

    symbol = str(symbol).strip().upper()

    # 如果已经有.HK后缀，先移除
    if symbol.endswith('.HK'):
        symbol = symbol[:-3]

    # 如果是纯数字，标准化为4位数字
    if symbol.isdigit():
        # 移除前导0，然后补齐到4位
        clean_code = symbol.lstrip('0') or '0'  # 如果全是0，保留一个0
        normalized_code = clean_code.zfill(4)
        return f"{normalized_code}.HK"

    return symbol
```

### 测试用例

| 输入 | 旧代码输出 | 新代码输出 | Yahoo Finance 结果 |
|------|-----------|-----------|-------------------|
| `700` | `700.HK` ❌ | `0700.HK` ✅ | ✅ 成功 |
| `0700` | `0700.HK` ✅ | `0700.HK` ✅ | ✅ 成功 |
| `00700` | `00700.HK` ❌ | `0700.HK` ✅ | ✅ 成功 |
| `9988` | `9988.HK` ✅ | `9988.HK` ✅ | ✅ 成功 |
| `09988` | `09988.HK` ❌ | `9988.HK` ✅ | ✅ 成功 |
| `0700.HK` | `0700.HK` ✅ | `0700.HK` ✅ | ✅ 成功 |
| `00700.HK` | `00700.HK` ❌ | `0700.HK` ✅ | ✅ 成功 |

## 修改文件

**文件**：`tradingagents/dataflows/providers/hk/hk_stock.py`

**位置**：`_normalize_hk_symbol` 方法，第 207-236 行

**修改内容**：
1. 先移除 `.HK` 后缀（如果有）
2. 移除前导0
3. 补齐到4位数字
4. 添加 `.HK` 后缀

## 日志对比

### 修复前

```
INFO  | 📊 [港股数据] 开始准备00700的数据
DEBUG | 🔍 [港股数据] 代码格式化: 00700 → 0700.HK  ← ✅ 验证阶段正确
INFO  | ✅ [港股数据] 基本信息获取成功: 0700.HK - 腾讯控股
INFO  | 🇭🇰 获取港股数据: 00700.HK (2025-09-13 到 2025-10-13)  ← ❌ 数据获取阶段错误
ERROR | $00700.HK: possibly delisted; no price data found  ← ❌ Yahoo Finance 错误
```

### 修复后

```
INFO  | 📊 [港股数据] 开始准备00700的数据
DEBUG | 🔍 [港股数据] 代码格式化: 00700 → 0700.HK  ← ✅ 验证阶段正确
INFO  | ✅ [港股数据] 基本信息获取成功: 0700.HK - 腾讯控股
INFO  | 🇭🇰 获取港股数据: 0700.HK (2025-09-13 到 2025-10-13)  ← ✅ 数据获取阶段正确
INFO  | ✅ 港股数据获取成功: 0700.HK, 30条记录  ← ✅ Yahoo Finance 成功
```

## 影响范围

### 使用 `HKStockProvider` 的地方

1. **`tradingagents/dataflows/interface.py`**
   - `get_hk_stock_data_unified()` - 统一港股数据获取接口

2. **`tradingagents/agents/utils/agent_utils.py`**
   - `get_stock_market_data_unified()` - 统一市场数据工具
   - 港股数据获取

3. **`tradingagents/dataflows/providers/hk/improved_hk.py`**
   - `get_hk_stock_data_akshare()` - 兼容性函数

### 修复效果

- ✅ 所有港股代码格式统一为 `0700.HK`（4位数字）
- ✅ Yahoo Finance 可以正确识别和获取数据
- ✅ 验证阶段和数据获取阶段使用相同的标准化逻辑
- ✅ 支持各种输入格式：`700`, `0700`, `00700`, `0700.HK`, `00700.HK`

## 相关修复

这是一系列港股代码识别和格式化问题的修复：

1. ✅ **前端验证** - 支持 4-5 位数字
2. ✅ **后端验证** - 支持 4-5 位数字，格式化为 `0700.HK`
3. ✅ **市场类型识别** - `StockUtils` 识别纯数字港股代码
4. ✅ **代码标准化** - `hk_stock.py` 统一标准化逻辑 ← **本次修复**

## 总结

### 问题
- ❌ `hk_stock.py` 的代码标准化逻辑不正确
- ❌ `00700` 被格式化为 `00700.HK`（5位数字）
- ❌ Yahoo Finance 无法识别，返回 "possibly delisted" 错误

### 原因
- ❌ 直接添加 `.HK` 后缀，没有移除前导0
- ❌ 与 `stock_validator.py` 的逻辑不一致

### 修复
- ✅ 统一标准化逻辑：先移除前导0，再补齐到4位
- ✅ 与 `stock_validator.py` 保持一致
- ✅ 符合 Yahoo Finance 的格式要求

### 效果
- ✅ `00700` 正确格式化为 `0700.HK`
- ✅ Yahoo Finance 可以正确获取数据
- ✅ 所有港股代码格式统一
- ✅ 系统中所有地方的港股代码标准化逻辑一致

