2. 跟踪误差的数学推导:从收益率序列到标准差的计算过程
跟踪误差这东西,说白了就是衡量你抄作业抄得有多像。
我刚开始做量化那会儿,领导丢给我一个任务:复制沪深300指数。我心想这还不简单?照着权重买不就完了。结果一算跟踪误差,差点没被骂哭。嗯,从那以后我才真正重视起这个指标的计算细节。
今天咱们就来掰扯掰扯,跟踪误差到底是怎么从一堆收益率数字,变成那个你熟悉的百分比数值的。
2.1 从收益率序列说起
跟踪误差的核心,是组合收益率与基准收益率之间的差异。这个差异,我们叫它「偏离度」或者「超额收益」——注意,这里的超额收益不是指跑赢了多少,而是单纯指差值。
假设我们有T个交易日的数据:
R_p,t:第t天组合的收益率R_b,t:第t天基准的收益率
那么第t天的偏离度就是:
d_t = R_p,t - R_b,t
就这么简单。但问题来了——你拿到的是每天的收益率,而跟踪误差是一个统计量。怎么从一堆d_t变成一个数字?
核心思想:跟踪误差 = 偏离度序列的标准差
说白了,就是看你的组合每天跟基准「差多少」,然后算这些差值的波动有多大。波动越大,说明你的复制效果越差。
2.2 标准差的计算公式
这里我要提醒一句:金融里算跟踪误差,通常用的是样本标准差,不是总体标准差。为什么?因为我们永远只能拿到有限的历史数据,不可能观测到所有可能的收益率。
样本标准差的公式长这样:
TE = sqrt( (1/(T-1)) * Σ(d_t - d̄)² )
其中:
T:样本天数d_t:第t天的偏离度d̄:偏离度的均值Σ:求和符号,从t=1到T
你可能会问:为什么是T-1而不是T?
我当年学统计时也纠结过这个问题。简单说,因为我们用样本均值d̄去估计了真实的均值,损失了一个自由度。用T-1做分母,得到的估计是无偏的。虽然在实际中T很大时差别不大,但专业报告里都认T-1这个口径。
2.3 年化处理:把日度跟踪误差变成年度
实际工作中,我们很少说「日跟踪误差是多少」,因为不同产品的持仓周期不一样。行业惯例是年化。
年化公式很简单:
TE_annual = TE_daily * sqrt(252)
252是一年大概的交易天数。为什么用平方根?因为方差是线性累加的,标准差是方差的平方根,所以年化时要用sqrt。
我的习惯:在代码里我会把252定义成一个常量,方便以后调整。有些市场用250,有些用252,甚至有人用260。我个人建议A股用252,因为扣除周末和法定节假日,差不多就是这个数。
2.4 完整计算流程(附代码)
光讲公式太枯燥,咱们直接上代码。这是我实际项目中用的一段核心逻辑:
import numpy as np
import pandas as pd
def calculate_tracking_error(portfolio_returns, benchmark_returns, annual_factor=252):
"""
计算年化跟踪误差
参数:
portfolio_returns: 组合日收益率序列 (array-like)
benchmark_returns: 基准日收益率序列 (array-like)
annual_factor: 年化因子,默认252
返回:
te_annual: 年化跟踪误差
"""
# 计算每日偏离度
deviation = np.array(portfolio_returns) - np.array(benchmark_returns)
# 计算样本标准差 (ddof=1 表示用T-1)
te_daily = np.std(deviation, ddof=1)
# 年化
te_annual = te_daily * np.sqrt(annual_factor)
return te_annual
# 示例
portfolio = [0.001, -0.002, 0.003, -0.001, 0.002]
benchmark = [0.0005, -0.001, 0.002, 0.0, 0.0015]
te = calculate_tracking_error(portfolio, benchmark)
print(f"年化跟踪误差: {te:.4f} 或 {te*100:.2f}%")
这段代码我用了不下几百次。注意ddof=1这个参数,它就是决定用T还是T-1的关键。忘了加这个,算出来的值会偏小一点点。
2.5 一个完整的计算示例
咱们拿真实数据走一遍流程。假设某指数增强产品5天的数据如下:
| 日期 | 组合收益率(%) | 基准收益率(%) | 偏离度(%) |
|---|---|---|---|
| Day 1 | 0.50 | 0.40 | 0.10 |
| Day 2 | -0.30 | -0.20 | -0.10 |
| Day 3 | 0.80 | 0.60 | 0.20 |
| Day 4 | 0.10 | 0.15 | -0.05 |
| Day 5 | -0.20 | -0.10 | -0.10 |
计算步骤:
- 偏离度均值 d̄ = (0.10 - 0.10 + 0.20 - 0.05 - 0.10) / 5 = 0.01%
- 各偏离度与均值的差平方:(0.09² + 0.11² + 0.19² + 0.06² + 0.11²) = 0.0081 + 0.0121 + 0.0361 + 0.0036 + 0.0121 = 0.072
- 方差 = 0.072 / (5-1) = 0.018
- 日跟踪误差 = sqrt(0.018) ≈ 0.134%
- 年化跟踪误差 = 0.134% * sqrt(252) ≈ 0.134% * 15.87 ≈ 2.13%
我曾经踩过的坑:有一次我直接用Excel的STDEV函数算偏离度的标准差,忘了检查数据里有没有空值。结果因为某天基准数据缺失,Excel自动跳过了那行,导致样本量对不上,算出来的跟踪误差差了0.3%。后来我养成了一个习惯——算之前先检查数据完整性,用pd.isnull().sum()扫一遍。
2.6 知识体系流程图
下面这张图帮你理清整个计算逻辑的脉络:
2.7 几个容易翻车的细节
做跟踪误差计算这么多年,我总结了几条血泪教训:
- 收益率单位要统一:有人用百分比(0.5%),有人用小数(0.005),混在一起算出来直接翻车。我习惯在数据预处理阶段全部转成小数。
- 注意复利 vs 单利:日收益率用对数收益率还是简单收益率?短周期差别不大,但长周期建议用对数收益率,因为可加性更好。
- 样本量别太少:少于20个交易日算出来的跟踪误差基本没有统计意义。我一般至少用60个交易日(约一个季度)。
- 异常值处理:如果某天组合因为大额申赎导致收益率异常,要不要剔除?我的建议是:如果这个异常是运营层面的问题,应该剔除;如果是投资决策导致的,必须保留。
一个小技巧:在Python里,如果你用pandas的rolling()方法,可以很方便地计算滚动跟踪误差。比如deviation.rolling(window=60).std(ddof=1) * np.sqrt(252),这样就能看到跟踪误差随时间的变化趋势,比只看一个静态数字有用得多。
好了,跟踪误差的数学推导就讲到这里。从收益率序列到标准差,再到年化处理,每一步都有它的道理。下次你看到别人报告里的跟踪误差数字,应该能一眼看出它是不是算对了。
可可精品资料库