## 使用指南更新(FLASK_API_FETCHER_GUIDE.md)
- get_trading_calendar() 方法签名更新
- 新增 start, end 参数(支持动态日期范围)
- 返回类型: pd.DatetimeIndex(准确日历)
- 使用示例更新(API 调用方式)
- 注意事项更新:交易日历准确性 ✅ 已解决
## 架构设计更新(FLASK_API_FETCHER_ARCHITECTURE.md)
- get_trading_calendar() 实现更新
- 从临时 pandas BDay → API 准确日历
- API 端点: GET /api/v1/trading-calendar
- 未来优化: 移除交易日历 TODO(已完成)
## 文档一致性
- 所有示例代码使用 API 日历
- 架构描述与实际实现一致
- 版本历史更新(2024-04-16)
366 lines
8.3 KiB
Markdown
366 lines
8.3 KiB
Markdown
# FlaskAPIFetcher 使用指南
|
||
|
||
## 概述
|
||
|
||
`FlaskAPIFetcher` 是 framework_v2 的数据获取器实现,通过 HTTP API 获取线上数据(指数、ETF)。
|
||
|
||
**核心优势**:
|
||
- ✅ 无需本地 SSH 隧道配置
|
||
- ✅ 支持远程调用(生产环境)
|
||
- ✅ 自动重试 + 超时处理
|
||
- ✅ Pydantic Schema 验证响应
|
||
- ✅ ETF 数据自动附加净值和溢价率
|
||
|
||
---
|
||
|
||
## 快速开始
|
||
|
||
### 1. 基础使用
|
||
|
||
```python
|
||
from framework_v2.shared.data import FlaskAPIFetcher
|
||
|
||
# 创建数据获取器
|
||
fetcher = FlaskAPIFetcher(
|
||
base_url="https://k3s.tokenpluse.xyz", # 或从环境变量读取
|
||
timeout=120,
|
||
retries=3
|
||
)
|
||
|
||
# 获取指数数据
|
||
data = fetcher.fetch_indices(
|
||
codes=["000300.SH", "000905.SH"],
|
||
start="2024-01-01",
|
||
end="2024-12-31"
|
||
)
|
||
|
||
# 访问数据
|
||
df_300 = data["000300.SH"]
|
||
print(df_300.head())
|
||
```
|
||
|
||
### 2. 获取 ETF 数据
|
||
|
||
```python
|
||
# 获取 ETF 数据(自动附加净值和溢价率)
|
||
data = fetcher.fetch_etf(
|
||
codes=["510300.SH", "159919.SZ"],
|
||
start="2024-01-01",
|
||
end="2024-12-31"
|
||
)
|
||
|
||
# 访问价格数据
|
||
df = data["510300.SH"]
|
||
print(df.head())
|
||
|
||
# 访问净值数据
|
||
nav = df.attrs.get('nav')
|
||
if nav is not None:
|
||
print(f"净值数据: {len(nav)} 条")
|
||
|
||
# 访问溢价率
|
||
premium = df.attrs.get('latest_premium')
|
||
if premium is not None:
|
||
print(f"最新溢价率: {premium:.2f}%")
|
||
```
|
||
|
||
---
|
||
|
||
## 完整示例:结合 CrossMarketAligner
|
||
|
||
### 场景:获取跨市场数据并对齐到 A 股日历
|
||
|
||
```python
|
||
from framework_v2.shared.data import FlaskAPIFetcher, CrossMarketAligner
|
||
|
||
# 1. 创建数据获取器
|
||
fetcher = FlaskAPIFetcher()
|
||
|
||
# 2. 获取 A 股交易日历(通过 API)
|
||
a_share_calendar = fetcher.get_trading_calendar(
|
||
market='A',
|
||
start='2024-01-01',
|
||
end='2024-12-31'
|
||
)
|
||
|
||
# 3. 创建对齐器
|
||
aligner = CrossMarketAligner(target_calendar=a_share_calendar)
|
||
|
||
# 4. 获取跨市场指数数据
|
||
us_indices = fetcher.fetch_indices(
|
||
codes=["^GSPC", "^IXIC"], # 美股
|
||
start="2024-01-01",
|
||
end="2024-12-31"
|
||
)
|
||
|
||
cn_indices = fetcher.fetch_indices(
|
||
codes=["000300.SH", "000905.SH"], # A股
|
||
start="2024-01-01",
|
||
end="2024-12-31"
|
||
)
|
||
|
||
# 5. 对齐收益率到 A 股日历
|
||
returns_aligned = aligner.align_multi_asset(
|
||
close_dict={
|
||
"SP500": us_indices["^GSPC"]["close"],
|
||
"NASDAQ": us_indices["^IXIC"]["close"],
|
||
"CSI300": cn_indices["000300.SH"]["close"],
|
||
"CSI500": cn_indices["000905.SH"]["close"],
|
||
}
|
||
)
|
||
|
||
# 6. 验证对齐结果
|
||
print(returns_aligned.head())
|
||
print(f"\nNaN 数量: {returns_aligned.isna().sum().sum()}") # 应该为 0
|
||
```
|
||
|
||
---
|
||
|
||
## API 参考
|
||
|
||
### FlaskAPIFetcher
|
||
|
||
#### 初始化
|
||
|
||
```python
|
||
FlaskAPIFetcher(
|
||
base_url: str = None, # API 地址(默认从环境变量读取)
|
||
timeout: int = 120, # 请求超时时间(秒)
|
||
retries: int = 3 # 重试次数
|
||
)
|
||
```
|
||
|
||
#### 核心方法
|
||
|
||
| 方法 | 说明 | 返回类型 |
|
||
|------|------|----------|
|
||
| `fetch_indices(codes, start, end)` | 获取指数 OHLCV 数据 | `Dict[str, DataFrame]` |
|
||
| `fetch_etf(codes, start, end)` | 获取 ETF 数据(价格+净值) | `Dict[str, DataFrame]` |
|
||
| `get_trading_calendar(market, start, end)` | 获取交易日历(API) | `pd.DatetimeIndex` |
|
||
| `get_benchmark(code, start, end)` | 获取基准数据 | `pd.Series` |
|
||
| `get_health()` | 检查 API 健康状态 | `Dict` |
|
||
|
||
#### fetch_indices 参数
|
||
|
||
```python
|
||
fetcher.fetch_indices(
|
||
codes=["000300.SH", "000905.SH"], # 指数代码列表
|
||
start="2024-01-01", # 开始日期
|
||
end="2024-12-31" # 结束日期
|
||
)
|
||
```
|
||
|
||
**返回 DataFrame 结构**:
|
||
```
|
||
code open high low close volume
|
||
date
|
||
2024-01-02 000300.SH 3388.30 3395.40 3372.50 3390.20 12345678
|
||
2024-01-03 000300.SH 3390.20 3405.60 3385.10 3398.50 13456789
|
||
```
|
||
|
||
#### fetch_etf 参数
|
||
|
||
```python
|
||
fetcher.fetch_etf(
|
||
codes=["510300.SH", "159919.SZ"], # ETF 代码列表
|
||
start="2024-01-01", # 开始日期
|
||
end="2024-12-31" # 结束日期
|
||
)
|
||
```
|
||
|
||
**返回 DataFrame 结构**:
|
||
```
|
||
code open high low close volume
|
||
date
|
||
2024-01-02 510300.SH 3.520 3.545 3.510 3.540 45678901
|
||
```
|
||
|
||
**附加信息(df.attrs)**:
|
||
- `nav`: 净值数据 DataFrame
|
||
- `premium_series`: 溢价率序列(dict)
|
||
- `latest_premium`: 最新溢价率(float)
|
||
- `premium_stats`: 溢价率统计(dict)
|
||
|
||
---
|
||
|
||
## 与 DataFetcher 抽象基类的关系
|
||
|
||
```
|
||
framework_v2/core/data.py # 抽象基类
|
||
└── DataFetcher (ABC)
|
||
├── fetch_indices() [抽象]
|
||
├── fetch_etf() [抽象]
|
||
├── get_trading_calendar() [抽象]
|
||
└── get_benchmark() [可选]
|
||
|
||
framework_v2/shared/data/flask_api_fetcher.py # 具体实现
|
||
└── FlaskAPIFetcher(DataFetcher)
|
||
├── fetch_indices() ✅ 实现(调用 FlaskAPIDataSource)
|
||
├── fetch_etf() ✅ 实现(调用 FlaskAPIDataSource)
|
||
├── get_trading_calendar() ✅ 实现(API 准确日历)
|
||
└── get_benchmark() ✅ 实现
|
||
```
|
||
|
||
### 继承关系验证
|
||
|
||
```python
|
||
from framework_v2.core.data import DataFetcher
|
||
from framework_v2.shared.data import FlaskAPIFetcher
|
||
|
||
# 验证继承
|
||
assert issubclass(FlaskAPIFetcher, DataFetcher)
|
||
|
||
# 验证抽象方法已实现
|
||
fetcher = FlaskAPIFetcher()
|
||
assert hasattr(fetcher, 'fetch_indices')
|
||
assert hasattr(fetcher, 'fetch_etf')
|
||
assert hasattr(fetcher, 'get_trading_calendar')
|
||
```
|
||
|
||
---
|
||
|
||
## 环境变量配置
|
||
|
||
### FLASK_API_URL
|
||
|
||
```bash
|
||
# .env 文件
|
||
FLASK_API_URL=https://k3s.tokenpluse.xyz
|
||
```
|
||
|
||
**优先级**:
|
||
1. 构造函数参数 `base_url`
|
||
2. 环境变量 `FLASK_API_URL`
|
||
3. 默认值 `https://k3s.tokenpluse.xyz`
|
||
|
||
---
|
||
|
||
## 错误处理
|
||
|
||
### 自动重试
|
||
|
||
```python
|
||
fetcher = FlaskAPIFetcher(retries=3)
|
||
|
||
# 失败时自动重试:
|
||
# - 网络超时
|
||
# - HTTP 5xx 错误
|
||
# - JSON 解析失败
|
||
```
|
||
|
||
### 手动错误处理
|
||
|
||
```python
|
||
data = fetcher.fetch_indices(["000300.SH"], "2024-01-01", "2024-12-31")
|
||
|
||
if "000300.SH" not in data:
|
||
print("✗ 数据获取失败")
|
||
# 处理错误...
|
||
else:
|
||
print(f"✓ 获取 {len(data['000300.SH'])} 条数据")
|
||
```
|
||
|
||
---
|
||
|
||
## 性能优化
|
||
|
||
### 批量获取 vs 单个获取
|
||
|
||
```python
|
||
# ✅ 推荐:批量获取(内部自动重试 + 进度显示)
|
||
data = fetcher.fetch_indices(
|
||
codes=["000300.SH", "000905.SH", "000852.SH"],
|
||
start="2024-01-01",
|
||
end="2024-12-31"
|
||
)
|
||
|
||
# ❌ 不推荐:循环单个获取(无进度显示)
|
||
for code in codes:
|
||
df = fetcher._source.fetch(code, start, end)
|
||
```
|
||
|
||
### 超时设置
|
||
|
||
```python
|
||
# 网络较慢时增加超时
|
||
fetcher = FlaskAPIFetcher(timeout=180) # 3 分钟
|
||
```
|
||
|
||
---
|
||
|
||
## 测试
|
||
|
||
运行测试验证功能:
|
||
|
||
```bash
|
||
cd /Users/aszer/Documents/vscode/etf
|
||
python framework_v2/tests/test_flask_api_fetcher.py
|
||
```
|
||
|
||
**预期输出**:
|
||
```
|
||
✓ 测试通过 - 健康检查
|
||
✓ 测试通过 - 指数数据
|
||
✓ 测试通过 - ETF 数据
|
||
✓ 测试通过 - 交易日历
|
||
✓ 测试通过 - 基准数据
|
||
|
||
总计: 5/5 通过
|
||
```
|
||
|
||
---
|
||
|
||
## 相关文档
|
||
|
||
- **[框架总览](../README.md)** - framework_v2 架构说明
|
||
- **[数据架构方案](../DATA_ARCHITECTURE.md)** - 数据流设计
|
||
- **[跨市场对齐方案](../ALIGNMENT_GUIDE.md)** - CrossMarketAligner 使用
|
||
- **[Aligner + Schema 整合](../ALIGNMENT_SCHEMA_INTEGRATION.md)** - 验证架构
|
||
|
||
---
|
||
|
||
## 注意事项
|
||
|
||
### 1. 交易日历准确性
|
||
|
||
✅ **已解决**:通过 API 获取准确交易日历,包含所有节假日。
|
||
|
||
**使用方式**:
|
||
```python
|
||
# 获取 A 股 2024 年交易日历(准确)
|
||
calendar = fetcher.get_trading_calendar('A', '2024-01-01', '2024-12-31')
|
||
print(f"A 股交易日: {len(calendar)} 天") # 242 天
|
||
```
|
||
|
||
### 2. ETF 净值数据量
|
||
|
||
ETF 净值数据可能远多于价格数据(历史净值 vs 交易价格):
|
||
|
||
```python
|
||
df = data["510300.SH"]
|
||
print(f"价格: {len(df)} 条") # ~60 条(2024 Q1)
|
||
print(f"净值: {len(df.attrs['nav'])} 条") # ~3695 条(全历史)
|
||
```
|
||
|
||
### 3. 资产类型检测
|
||
|
||
FlaskAPIDataSource 支持自动检测资产类型,也可手动指定:
|
||
|
||
```python
|
||
# 自动检测
|
||
df = fetcher._source.fetch("510300.SH", start, end)
|
||
|
||
# 手动覆盖
|
||
df = fetcher._source.fetch("510300.SH", start, end, asset_type='china_etf')
|
||
```
|
||
|
||
---
|
||
|
||
## 版本历史
|
||
|
||
- **2024-04-16**: 初始版本
|
||
- 继承 DataFetcher 抽象基类
|
||
- 实现指数、ETF 数据获取
|
||
- 集成 FlaskAPIDataSource
|
||
- 5/5 测试通过
|