# FlaskAPIFetcher 交易日历 API 集成

## 更新日期

2024-04-16

---

## 变更概述

将 `FlaskAPIFetcher.get_trading_calendar()` 从临时的 pandas BDay 实现升级为通过 API 获取准确交易日历。

---

## 变更详情

### 变更前（临时实现）

```python
def get_trading_calendar(self, market: str = 'A') -> pd.Index:
    """使用 pandas BDay 生成近似日历"""
    
    if market == 'A':
        calendar = pd.bdate_range(start='2020-01-01', end='2025-12-31')
        # 手动移除节假日（不完整）
        holidays = ['2024-02-10', '2024-02-11', ...]
        calendar = calendar[~calendar.isin(pd.to_datetime(holidays))]
        return calendar
    
    elif market == 'US':
        return pd.bdate_range(start='2020-01-01', end='2025-12-31')
```

**问题**：
- ❌ 使用 `bdate_range` 生成近似日历
- ❌ 节假日列表不完整
- ❌ 不支持动态日期范围
- ❌ 可能包含非交易日

---

### 变更后（API 实现）

```python
def get_trading_calendar(
    self,
    market: str = 'A',
    start: str = None,
    end: str = None
) -> pd.Index:
    """通过 API 获取准确交易日历"""
    
    # 默认日期范围
    if start is None:
        start = '2020-01-01'
    if end is None:
        end = '2025-12-31'
    
    # 调用 API 获取准确日历
    calendar = self._source.get_trading_calendar(
        market=market,
        start_date=start,
        end_date=end
    )
    
    if calendar is None:
        raise ValueError(
            f"交易日历获取失败: market={market}, {start} ~ {end}"
        )
    
    return calendar
```

**优势**：
- ✅ 通过 API 获取准确日历
- ✅ 包含所有节假日处理
- ✅ 支持动态日期范围
- ✅ API 失败时抛出异常（不静默降级）

---

## API 端点

### 请求

```
GET /api/v1/trading-calendar

参数:
  - market: 市场代码 ('A', 'US', 'HK')
  - start: 开始日期 (YYYY-MM-DD)
  - end: 结束日期 (YYYY-MM-DD)
```

### 响应

```json
{
  "market": "A",
  "exchange": "SSE",
  "trading_dates": ["2024-01-02", "2024-01-03", ...],
  "count": 242
}
```

---

## 使用示例

### 基础使用

```python
from framework_v2.shared.data import FlaskAPIFetcher

fetcher = FlaskAPIFetcher()

# 获取 A 股 2024 年交易日历
calendar = fetcher.get_trading_calendar(
    market='A',
    start='2024-01-01',
    end='2024-12-31'
)

print(f"A 股交易日: {len(calendar)} 天")  # 242 天
```

### 在数据对齐中使用

```python
from framework_v2.shared.data import FlaskAPIFetcher, CrossMarketAligner

fetcher = FlaskAPIFetcher()

# 1. 获取数据
data = fetcher.fetch_indices(["^IXIC"], "2024-01-01", "2024-12-31")

# 2. 获取准确交易日历
calendar = fetcher.get_trading_calendar(
    market='A',
    start='2024-01-01',
    end='2024-12-31'
)

# 3. 创建对齐器
aligner = CrossMarketAligner(target_calendar=calendar)

# 4. 对齐收益率
returns = aligner.align_returns(data["^IXIC"]["close"], code="^IXIC")
```

---

## 测试验证

### 端到端测试结果

```
阶段 3: 数据对齐（到 A 股日历）
======================================================================

[3.1] 获取 A 股交易日历（通过 API）...
✓ A (SSE): 484 个交易日 (2023-01-03 ~ 2024-12-31)
  A 股交易日: 484 天
  日期范围: 2023-01-03 00:00:00 ~ 2024-12-31 00:00:00

[3.2] 对齐因子到 A 股日历...

  对齐 ^IXIC 因子...
    对齐后天数: 484
    填充天数: 18 (3.7%)
    NaN 数量: 15

  对齐 399006.SZ 因子...
    对齐后天数: 484
    填充天数: 0 (0.0%)
    NaN 数量: 19

[3.3] 对齐收益率到 A 股日历...

  对齐 ^IXIC 收益率...
    对齐后天数: 484
    收益率范围: -3.6391% ~ 4.4159%
    NaN 数量: 0
    零收益率天数: 18 (休市日) ✅

  对齐 399006.SZ 收益率...
    对齐后天数: 484
    收益率范围: -10.5941% ~ 17.2494%
    NaN 数量: 0
    零收益率天数: 0 (休市日) ✅

✓ 阶段 3 通过
```

### 关键验证

| 验证项 | 预期 | 实际 | 状态 |
|--------|------|------|------|
| API 调用成功 | 是 | 是 | ✅ |
| 返回天数准确 | 484 天 | 484 天 | ✅ |
| 纳指休市日 | 18 天 | 18 天 | ✅ |
| 创业板休市日 | 0 天 | 0 天 | ✅ |
| 收益率 NaN | 0 | 0 | ✅ |

---

## 影响分析

### 正面影响

1. **准确性提升**: 从近似日历 → 准确日历
2. **维护成本降低**: 无需手动维护节假日列表
3. **多市场支持**: A 股、美股、港股统一 API
4. **动态日期范围**: 支持任意日期范围查询

### 无破坏性变更

- ✅ 方法签名向后兼容（新增可选参数 `start`, `end`）
- ✅ 返回类型兼容（`pd.DatetimeIndex` 是 `pd.Index` 的子类）
- ✅ 现有代码无需修改

---

## 相关文件

| 文件 | 变更 |
|------|------|
| `framework_v2/shared/data/flask_api_fetcher.py` | 更新 `get_trading_calendar()` 实现 |
| `framework_v2/tests/test_end_to_end.py` | 更新测试使用 API 日历 |
| `framework_v2/FLASK_API_FETCHER_GUIDE.md` | 更新文档 |
| `framework_v2/FLASK_API_FETCHER_ARCHITECTURE.md` | 更新架构说明 |
| `datasource/flask_api_source.py` | 底层 API 调用（已存在） |

---

## 版本历史

- **2024-04-16**: API 交易日历集成
  - 替换临时 pandas BDay 实现
  - 调用 `/api/v1/trading-calendar` 端点
  - 支持动态日期范围
  - 端到端测试通过

- **2024-04-15**: 初始版本
  - 临时实现（pandas BDay + 手动节假日）
  - 固定日期范围（2020-2025）
