⚠ 交易存在重大亏损风险。本网站的所有内容仅供教育用途,不构成财务建议。
第 11 课,共 13 课 · 免费

在 pandas 中做投资组合分析:相关系数矩阵与协方差矩阵、加权投资组合波动率和再平衡模拟

根据收益率计算年化协方差矩阵和相关系数矩阵,用 NumPy 推导投资组合波动率和风险贡献,并模拟权重漂移与日历再平衡的差异。

作者: Moustafa Hijazi内容审核日期: 2026-10-30阅读约 8 分钟自学课程

你将学到什么

  • 如何把多个价格序列对齐到同一个收益率 DataFrame 中,并正确地年化计算 .cov() 和 .corr()。
  • 投资组合波动率的矩阵公式 w.T @ Σ @ w,以及如何解读每项资产对风险的贡献。
  • 如何模拟一个权重自然漂移的买入并持有组合,以及一个按日历再平衡的组合。
  • 哪些数值陷阱(日期未对齐、混用货币、协方差窗口中的前视偏差)会导致错误答案。

讲解

相关性与投资组合总风险敞口(课程《风险与交易管理》,第 6 课)、组合两个系统(课程《系统化交易与回测》,第 10 课)以及再平衡规则(课程《ETF、基金与长期投资》,第 10 课)已在其他地方讲过;本课用代码把它们实现为适用于任意数量资产的形式。

从价格到收益率矩阵

把每个品种的复权收盘价(第 4 课)加载到同一个 DataFrame 中,每个代码一列:prices = pd.concat(series_dict, axis=1)。不同市场的假期不同,会产生 NaN 行;请明确地在 prices.dropna()(只保留共同交易日)和 prices.ffill()(把最后价格向前延续)之间做出选择。然后计算 rets = prices.pct_change().dropna()。先把所有数据换算成同一种货币;欧元投资者持有的美国 ETF 必须用 EUR/USD 序列进行换算,否则它的波动率和相关性描述的就是错误的对象。

协方差、相关系数与年化

rets.cov() 是日收益率的样本协方差矩阵;乘以 252 即可年化(方差随时间缩放)。rets.corr() 没有单位,无需缩放。对角线上是每项资产的方差,因此 np.sqrt(np.diag(cov_a)) 给出年化波动率。关系式 Σ_ij = ρ_ij × σ_i × σ_j 让你可以根据波动率和相关系数构建一个矩阵,用来测试诸如“危机中相关系数升至 0.8”之类的假设情景。

投资组合波动率与风险贡献

  • w = np.array([0.5, 0.3, 0.2]) # 权重,总和为 1
  • cov_a = rets.cov().values * 252
  • port_var = w @ cov_a @ w
  • port_vol = np.sqrt(port_var)
  • marginal = cov_a @ w # d(var)/d(w)
  • risk_contrib = w * marginal / port_var # 各份额之和为 1

@ 是矩阵乘法。risk_contrib 告诉你每项资产承担了投资组合方差的多大比例;它通常与资本权重相差甚远,而这一差距正是风险预算的起点(课程《深入投资组合构建:风险预算、市场状态与压力测试》,第 1 课)。

再平衡模拟

买入并持有会让权重漂移:表现好的资产会占据更大的份额。日历再平衡则在固定日期把权重重置为目标值。在 pandas 中,把收益率重采样到再平衡频率,然后对各个期间进行循环:

  • period_rets = (1 + rets).resample('ME').prod() - 1 # 月度收益率
  • target = np.array([0.6, 0.4]); hold = 10_000 * target; path = []
  • for _, r in period_rets.iterrows():
  • hold = hold * (1 + r.values) # 各部分分别增长
  • path.append(hold.sum())
  • hold = hold.sum() * target # 再平衡至目标权重

对于权重漂移的版本,删除最后一行即可。季度使用 'QE',年度使用 'YE'(pandas 2.2 及以后版本;更早的版本使用 'M'、'Q'、'A')。一次再平衡的换手为 abs(new_hold - old_hold).sum();乘以一个成本费率(例如 0.1%)后扣除。在德国的应税账户中,再平衡还会实现收益;请向 Steuerberater(税务顾问)核实税务影响。

实例演算

假设示例,输入数据均为编造;不计手续费、点差和税费。

第 1 部分:三项资产的波动率。年化波动率为 20%、10%、15%;相关系数 ρ₁₂ = 0.2,ρ₁₃ = 0.6,ρ₂₃ = 0.1;权重为 50 / 30 / 20%。

  1. 协方差:Σ₁₂ = 0.2 × 0.20 × 0.10 = 0.0040;Σ₁₃ = 0.6 × 0.20 × 0.15 = 0.0180;Σ₂₃ = 0.1 × 0.10 × 0.15 = 0.0015。对角线:0.0400、0.0100、0.0225。
  2. 投资组合方差 = Σ wᵢ wⱼ Σᵢⱼ = 0.25 × 0.04 + 0.09 × 0.01 + 0.04 × 0.0225 + 2 × (0.5 × 0.3 × 0.004 + 0.5 × 0.2 × 0.018 + 0.3 × 0.2 × 0.0015) = 0.0100 + 0.0009 + 0.0009 + 2 × (0.0006 + 0.0018 + 0.00009) = 0.01678。
  3. 投资组合波动率 = √0.01678 = 12.95%,而各波动率的加权平均为 16.0%;两者之差就是分散化带来的好处。
  4. 风险贡献:资产 1 以 50% 的资本承担了 73.9% 的方差;资产 2 以 30% 的资本承担了 9.5%;资产 3 以 20% 的资本承担了 16.6%。

第 2 部分:权重漂移与再平衡。€10,000 按 60 / 40 分配给资产 A 和资产 B。年收益率:A 为 +20%、−10%、+15%;B 为 +2%、+4%、+1%。

  1. 权重漂移:A:6,000 × 1.20 × 0.90 × 1.15 = €7,452;B:4,000 × 1.02 × 1.04 × 1.01 = €4,285.63。合计 €11,737.63;A 的权重已漂移至 63.5%。
  2. 每年再平衡:第 1 年合计 = 7,200 + 4,080 = €11,280 → 重置为 6,768 / 4,512;第 2 年 = 6,091.20 + 4,692.48 = €10,783.68 → 重置;第 3 年 = 7,440.74 + 4,356.61 = €11,797.35。
  3. 再平衡最终多出 €59.72,因为它在 A 上涨 20% 后卖出,并在下跌 10% 后买回。如果 A 持续单边上涨,权重漂移反而会胜出;再平衡控制的是风险,并不保证收益。

常见错误

用全样本协方差矩阵来配置一个从样本起点开始的投资组合一个在 2015–2025 年数据上计算 rets.cov()、再用结果设定 2015 年权重的回测,使用的是来自未来的信息。请在滚动窗口或扩展窗口上估计协方差(rets.rolling(252).cov() 或 rets.loc[:date].cov()),并只将其应用于随后的期间。危机中相关性也会上升,因此用平静时期估计的矩阵会在最关键的时刻低估风险。

练习活动

在纸上完成:两项资产的年化波动率分别为 18% 和 6%,相关系数 0.3,权重 70 / 30%。(a) 构建 2 × 2 协方差矩阵。(b) 计算投资组合的方差和波动率。(c) 计算每项资产的风险贡献在方差中所占的份额。(d) 在相关系数为 0.9 时重新计算波动率,并用一句话说明这为什么重要。

显示答案

(a) Σ₁₁ = 0.0324;Σ₂₂ = 0.0036;Σ₁₂ = 0.3 × 0.18 × 0.06 = 0.00324。

(b) 方差 = 0.49 × 0.0324 + 0.09 × 0.0036 + 2 × 0.7 × 0.3 × 0.00324 = 0.015876 + 0.000324 + 0.0013608 = 0.0175608;波动率 = 13.25%。

(c) 边际贡献:资产 1:0.7 × 0.0324 + 0.3 × 0.00324 = 0.023652;资产 2:0.7 × 0.00324 + 0.3 × 0.0036 = 0.003348。贡献:0.7 × 0.023652 / 0.0175608 = 94.3%;0.3 × 0.003348 / 0.0175608 = 5.7%。

(d) ρ = 0.9 时:Σ₁₂ = 0.00972;方差 = 0.015876 + 0.000324 + 0.0040824 = 0.0202824;波动率 = 14.24%。当相关性上升时,这个“分散化资产”几乎起不到作用,而这恰恰是抛售行情中常见的情形;评判一个投资组合应当依据压力情景下的相关性,而不仅仅是历史平均值。

局限性:用几年日度数据估计的样本协方差噪声很大;窗口的微小变化就可能让相关系数变动 0.1 甚至更多。

要点回顾

  • 在计算收益率之前先对齐日期和货币;明确决定如何处理缺失的交易日。
  • 把协方差乘以每年期数即可年化;相关系数无需缩放。
  • 投资组合波动率为 √(wᵀ Σ w);风险贡献 w × (Σw) / 方差 显示风险真正集中在哪里。
  • 通过重采样收益率并重置持仓来模拟再平衡;只用当时可得的数据估计协方差。

下一步

第 12 课把日常流程自动化:一个定时运行的脚本,负责获取数据、计算信号并生成报告,同时妥善处理 API 密钥和速率限制。

自测

回答问题后核对答案。你可以随意重试多次。

1. 两项资产的年化波动率分别为 20% 和 10%,相关系数为 0.0,权重为 50 / 50%。投资组合波动率是多少?

2. 某日收益率 DataFrame 的协方差矩阵中,资产 X 对应的对角线元素为 0.0001。X 的年化波动率(252 天)是多少?

3. 在一次再平衡模拟中,每次循环迭代都先执行 hold = hold.sum() * target,再执行 hold = hold * (1 + r.values)。这有什么影响?

供您自行复习的自动自测。您的答案在浏览器中核对,我们不会查看或评估。这不是考试,也不是资格证书。

您的进度

“已完成”仅表示您将本课标记为已学完,并不是对您理解程度的测试。 学习进度和笔记仅保存在此设备的此浏览器中,而非账户中。