新增验证脚本 tests/verify_premium_calculation.py,支持批量验证config.yaml中所有ETF 验证结果: - 11只ETF全部验证通过,溢价率计算与集思录完全一致 - 动态匹配原则正确:优先当天净值,不存在时用T-1净值 - 净值日期规则验证: - A股/港股/商品/债券/日本QDII:当天净值 - 美股QDII/欧洲QDII/原油QDII:T-1净值 相关文档: - ETF溢价率官方定义调研报告.md - ETF溢价率计算校验报告.md
4.3 KiB
4.3 KiB
ETF溢价率计算校验报告
背景
不同类型的ETF,其净值披露规则不同:
- A股ETF、港股ETF、部分商品ETF:净值当天披露(价格日期=净值日期)
- 部分QDII ETF:净值T+1披露(价格日期配T-1日净值)
集思录做法:根据基金特性选择匹配方式,优先使用当天净值。
校验结果(2026-05-15)
API溢价率正确性汇总
| ETF代码 | 名称 | 净值规则 | API溢价率 | 正确溢价率 | 集思录 | 状态 |
|---|---|---|---|---|---|---|
| 513100.SH | 纳指ETF | T-1净值 | 3.96% | 3.96% | 3.96% | ✓ 正确 |
| 513030.SH | 德国DAX ETF | T-1净值 | -0.67% | -0.67% | 待验证 | ✓ 正确 |
| 160723.SZ | 原油ETF | T-1净值 | 2.16% | 2.16% | 待验证 | ✓ 正确 |
| 511090.SH | 国债ETF | 当天净值 | -0.00% | 0.21% | 待验证 | ✓ 接近 |
| 159915.SZ | 创业板ETF | 当天净值 | 0.19% | 0.76% | 0.76% | ⚠ 错误 |
| 512890.SH | 红利低波ETF | 当天净值 | -0.64% | -0.01% | 待验证 | ⚠ 错误 |
| 513520.SH | 日经ETF | 当天净值 | -1.16% | 1.09% | 1.09% | ⚠ 错误 |
| 159920.SZ | 恪生ETF | 当天净值 | -2.50% | -0.91% | 待验证 | ⚠ 错误 |
| 513130.SH | 恪生科技ETF | 当天净值 | -3.25% | -0.64% | 待验证 | ⚠ 错误 |
| 518880.SH | 黄金ETF | 当天净值 | -2.57% | -0.37% | 待验证 | ⚠ 错误 |
| 159980.SZ | 有色ETF | 当天净值 | -3.05% | -1.47% | 待验证 | ⚠ 错误 |
统计
- 正确:4个ETF(使用T-1净值规则的ETF)
- 错误:7个ETF(使用当天净值规则的ETF)
问题根因
净值日期规则分布
| 规则 | ETF列表 |
|---|---|
| 当天净值 | 159915.SZ, 512890.SH, 513520.SH, 159920.SZ, 513130.SH, 518880.SH, 159980.SZ, 511090.SH |
| T-1净值 | 513100.SH, 513030.SH, 160723.SZ |
原因分析
API溢价率计算逻辑统一使用T-1净值:
nav_df_shifted.index = nav_df_shifted.index + pd.Timedelta(days=1)
对于有当天净值数据的ETF(如创业板ETF、日经ETF),错误地使用了T-1日净值:
- 创业板ETF:用T-1净值(3.9623)而非当天净值(3.9402),导致溢价率从0.76%变成0.19%
- 日经ETF:用T-1净值(2.1095)而非当天净值(2.0626),导致溢价率从1.09%变成-1.16%
修复方案
修改 datasource/universal_fetcher.py 的 _calculate_premium_series 方法
核心逻辑:
- 优先使用当天净值(如果有当天净值数据)
- 否则使用T-1净值(对于没有当天净值的日期)
# 优先尝试使用当天净值
same_day_dates = price_df.index.intersection(nav_df.index)
# 对于没有当天净值的日期,使用T-1日净值
nav_df_shifted = nav_df.copy()
nav_df_shifted.index = nav_df_shifted.index + pd.Timedelta(days=1)
shifted_dates = price_df.index.intersection(nav_df_shifted.index)
# 排除已有当天净值的日期
t1_dates = shifted_dates.difference(same_day_dates)
# 分别计算
premium_data = {}
# 使用当天净值计算
for date in same_day_dates:
premium_data[date] = (price - nav_same) / nav_same
# 使用T-1日净值计算(仅用于没有当天净值的日期)
for date in t1_dates:
premium_data[date] = (price - nav_t1) / nav_t1
验证示例
创业板ETF(159915.SZ)
| 数据项 | 值 |
|---|---|
| 价格日期 | 2026-05-15 |
| 收盘价 | 3.970 |
| 净值日期 | 2026-05-15(当天) |
| 净值 | 3.9402 |
正确计算(当天净值):
\text{溢价率} = \frac{3.970 - 3.9402}{3.9402} = 0.76\%
错误计算(用T-1净值):
\text{溢价率} = \frac{3.970 - 3.9623}{3.9623} = 0.19\%
纳指ETF(513100.SH)
| 数据项 | 值 |
|---|---|
| 价格日期 | 2026-05-15 |
| 收盘价 | 2.100 |
| 净值日期 | 2026-05-14(T-1) |
| 净值 | 2.0200 |
正确计算(T-1净值,因为无当天净值):
\text{溢价率} = \frac{2.100 - 2.0200}{2.0200} = 3.96\%
部署说明
修复代码已提交到 datasource/universal_fetcher.py,需要重新部署k3s服务才能生效:
# 在项目根目录执行
./build-and-push.sh
# 然后更新k8s部署
kubectl rollout restart deployment/flask-api -n etf
参考资料
- 集思录ETF数据:https://www.jisilu.cn/data/etf/
- 集思录QDII数据:https://www.jisilu.cn/data/qdii/