Files
etf/docs/etf_tracking_error_calculation.md
aszerW 3b0688930d docs: 添加ETF跟踪误差计算方法文档
- 完整计算流程(ETF单位净值 vs 基准指数)
- 数据源选择(Tushare指数/期货/Flask API)
- 关键注意事项(unit_nav、标的指数基准、年化因子)
- 与天天基金数据校验结果(平均差异0.009%)
- Python代码示例
2026-06-20 17:06:26 +08:00

234 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ETF跟踪误差计算方法
**文档版本**: v1.0
**创建日期**: 2026-06-19
**适用范围**: 轮动策略标的池ETF跟踪准确率评估
---
## 一、定义
**跟踪误差Tracking Error, TE**衡量ETF净值收益率与标的指数收益率之间偏离程度的指标反映基金经理的追踪能力。
**核心公式**
```
跟踪误差(TE) = STDEV(每日跟踪偏离度) × √252
```
---
## 二、计算步骤
### 2.1 数据准备
| 数据类型 | 字段 | 来源 | 说明 |
|---------|------|------|------|
| ETF单位净值 | `unit_nav` | Tushare `fund_nav` | 必须用单位净值,不能用累计净值 |
| 基准收盘价 | `close` | Tushare `index_daily` / `fut_daily` / Flask API | 根据标的类型选择数据源 |
### 2.2 计算流程
```
步骤1: 获取ETF单位净值序列
NAV[t], NAV[t-1], NAV[t-2], ...
步骤2: 获取基准收盘价序列
Index[t], Index[t-1], Index[t-2], ...
步骤3: 计算ETF日收益率
ETF_ret[t] = (NAV[t] - NAV[t-1]) / NAV[t-1]
步骤4: 计算基准日收益率
Index_ret[t] = (Index[t] - Index[t-1]) / Index[t-1]
步骤5: 计算每日跟踪偏离度
Deviation[t] = ETF_ret[t] - Index_ret[t]
步骤6: 计算偏离度标准差
Std = STDEV(Deviation序列)
步骤7: 年化处理
TE = Std × √252
```
### 2.3 Python代码示例
```python
import numpy as np
import pandas as pd
def calculate_tracking_error(etf_nav: pd.Series, benchmark_close: pd.Series) -> dict:
"""
计算ETF跟踪误差
Args:
etf_nav: ETF单位净值序列index=date, value=unit_nav
benchmark_close: 基准收盘价序列index=date, value=close
Returns:
dict: 包含跟踪误差、R²、相关系数等指标
"""
# 计算收益率
etf_ret = etf_nav.pct_change().dropna()
bench_ret = benchmark_close.pct_change().dropna()
# 对齐日期
common = etf_ret.index.intersection(bench_ret.index)
if len(common) < 20:
return None
e = etf_ret.loc[common]
b = bench_ret.loc[common]
# 每日偏离度
daily_deviation = e - b
# 跟踪误差 = 标准差 × √252
tracking_error = daily_deviation.std() * np.sqrt(252)
# 其他指标
correlation = e.corr(b)
r_squared = correlation ** 2
# 累计收益
etf_cum = (1 + e).prod() - 1
bench_cum = (1 + b).prod() - 1
excess = etf_cum - bench_cum
return {
'annual_tracking_error': round(tracking_error * 100, 4), # %
'correlation': round(correlation, 6),
'r_squared': round(r_squared, 6),
'etf_cum_return': round(etf_cum * 100, 2), # %
'benchmark_cum_return': round(bench_cum * 100, 2), # %
'excess_return': round(excess * 100, 2), # %
'common_days': len(common),
}
```
---
## 三、基准数据来源
### 3.1 数据源选择
| 标的类型 | 示例 | 基准来源 | Tushare接口 | 数据可用性 |
|---------|------|---------|------------|-----------|
| A股指数 | 创业板指、红利低波 | 指数收盘价 | `index_daily` | ✅ 完整 |
| 商品期货 | 黄金、有色金属 | 期货主力合约 | `fut_daily` | ✅ 完整 |
| 海外指数 | 纳指、恒生、日经、DAX | 指数收盘价 | Flask API (yfinance) | ✅ 完整 |
### 3.2 接口调用示例
```python
# A股指数
index_data = pro.index_daily(
ts_code='399006.SZ',
start_date='20250601',
end_date='20260619'
)
# 商品期货
futures_data = pro.fut_daily(
ts_code='AU.SHF',
start_date='20250601',
end_date='20260619'
)
# 海外指数通过Flask API
from datasource.flask_api_source import FlaskAPIDataSource
flask_source = FlaskAPIDataSource()
index_data = flask_source.fetch('^NDX', '2025-06-01', '2026-06-19')
```
---
## 四、关键注意事项
### 4.1 必须使用单位净值unit_nav
| 净值类型 | 含义 | 是否可用 |
|---------|------|---------|
| **单位净值** (unit_nav) | 当前每份基金的实际价值 | ✅ **必须用这个** |
| 累计净值 (accum_nav) | 单位净值 + 历史分红 | ❌ 会虚高规模 |
**原因**:累计净值包含了历史分红再投资,会导致规模计算偏大。
### 4.2 必须使用标的指数做基准
| 基准类型 | 计算结果 | 说明 |
|---------|---------|------|
| **标的指数** | 真实跟踪误差 | ✅ 反映基金经理追踪能力 |
| 另一只ETF价格 | 价格一致性 | ❌ 包含溢价率波动噪声 |
### 4.3 年化因子
- 使用 **√252**假设一年252个交易日
- 如果使用月度数据,则用 **√12**
- 如果使用周度数据,则用 **√52**
---
## 五、校验结果
### 5.1 与天天基金数据对比
我们用 Tushare 计算的创业板指 ETF 跟踪误差 vs 天天基金官方数据:
| ETF代码 | Tushare TE | 天天基金 TE | 差异 |
|--------|-----------|------------|------|
| 159948.SZ | 0.3302% | 0.32% | +0.0102% |
| 159952.SZ | 0.3559% | 0.35% | +0.0059% |
| 159205.SZ | 0.3698% | 0.36% | +0.0098% |
| 159977.SZ | 0.3727% | 0.36% | +0.0127% |
**平均差异:+0.0091%** → 高度一致
### 5.2 结论
- Tushare 数据计算的跟踪误差与天天基金官方数据**高度一致**
- 验证了计算方法的正确性
- 可用于日常跟踪误差监控
---
## 六、完整计算脚本
参考文件:`rotation/tracking_error_full.py`
### 6.1 主要功能
- 覆盖轮动策略标的池全部10个标的
- 自动选择合适的数据源Tushare指数/期货/Flask API
- 批量获取ETF净值数据
- 计算跟踪误差并排序
- 与天天基金数据对比校验
### 6.2 运行方式
```bash
cd /Users/aszer/code/etf
python3 rotation/tracking_error_full.py
```
### 6.3 输出结果
- JSON文件`rotation/results/tracking_error_full.json`
- 包含每个标的下所有ETF的跟踪误差、R²、超额收益等指标
---
## 七、相关文档
- [ETF竞品分析报告](./etf_competitor_analysis_report.md)
- [跟踪误差校验报告](./tracking_error_validation_report.md)
- [ETF数据源说明](../datasource/README.md)
---
## 八、更新日志
| 版本 | 日期 | 变更内容 |
|------|------|---------|
| v1.0 | 2026-06-19 | 初始版本,包含完整计算方法和校验结果 |