From 3b0688930d15c9cb516049b33e58b89560dad75e Mon Sep 17 00:00:00 2001 From: aszerW Date: Sat, 20 Jun 2026 17:06:26 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=B7=BB=E5=8A=A0ETF=E8=B7=9F=E8=B8=AA?= =?UTF-8?q?=E8=AF=AF=E5=B7=AE=E8=AE=A1=E7=AE=97=E6=96=B9=E6=B3=95=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 完整计算流程(ETF单位净值 vs 基准指数) - 数据源选择(Tushare指数/期货/Flask API) - 关键注意事项(unit_nav、标的指数基准、年化因子) - 与天天基金数据校验结果(平均差异0.009%) - Python代码示例 --- docs/etf_tracking_error_calculation.md | 233 +++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 docs/etf_tracking_error_calculation.md diff --git a/docs/etf_tracking_error_calculation.md b/docs/etf_tracking_error_calculation.md new file mode 100644 index 0000000..eb0eca4 --- /dev/null +++ b/docs/etf_tracking_error_calculation.md @@ -0,0 +1,233 @@ +# 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 | 初始版本,包含完整计算方法和校验结果 |