第三章 资产收益率与风险:对数收益率计算、协方差矩阵、年化波动率
好,咱们进入第三章。说实话,这一章是整门课里最「数学」的部分,但也是最有用的部分。你想想看,做投资组合优化,核心就两件事:收益和风险。收益怎么算?风险怎么量化?这章就是解决这两个问题的。
我个人习惯,拿到一组价格数据后,第一件事就是算对数收益率。为什么?因为对数收益率在时间上可加,而且更符合正态分布的假设。嗯,这里要注意,普通收益率(简单收益率)在计算多期收益时会有偏差,而对数收益率没有这个问题。
3.1 对数收益率计算
对数收益率的公式很简单:
r_t = ln(P_t / P_{t-1})
其中 P_t 是 t 时刻的价格,P_{t-1} 是 t-1 时刻的价格。
用 Python 实现起来也就几行代码:
import numpy as np
import pandas as pd
# 假设 prices 是一个包含收盘价的 DataFrame
# 列名是股票代码,行是日期
prices = pd.read_csv('stock_prices.csv', index_col=0, parse_dates=True)
# 计算对数收益率
log_returns = np.log(prices / prices.shift(1))
# 去掉第一行的 NaN
log_returns = log_returns.dropna()
print(log_returns.head())
我在项目中遇到过一个问题:数据里偶尔会有价格为 0 的情况。你想想看,ln(0) 是什么?负无穷!所以一定要先做数据清洗。我曾经因为没检查这个,结果协方差矩阵里全是 NaN,折腾了半天才发现是数据源的问题。
prices[prices <= 0] = np.nan 先处理掉。
3.2 协方差矩阵
协方差矩阵是投资组合优化的核心。它衡量的是不同资产之间的联动关系。说白了,就是 A 涨的时候,B 是跟着涨还是跌?涨跌幅度有多大?
数学上,协方差矩阵的定义是:
Σ = E[(R - μ)(R - μ)^T]
其中 R 是收益率向量,μ 是期望收益率向量。
在 Python 里,计算协方差矩阵超级简单:
# 计算协方差矩阵
cov_matrix = log_returns.cov()
# 查看前几行
print(cov_matrix.head())
这里有个细节:cov() 默认是样本协方差,分母是 n-1。如果你想要总体协方差,可以用 cov(ddof=0)。我个人习惯用样本协方差,因为金融数据通常只是历史样本,不是全量数据。
np.linalg.eig(cov_matrix) 检查它是否正定——这在后续的优化中很重要。
3.3 年化波动率
波动率是风险的核心指标。日波动率怎么年化?很简单,乘以 sqrt(252)。为什么是 252?因为一年大约有 252 个交易日。
公式:
σ_annual = σ_daily * sqrt(252)
代码实现:
# 计算日波动率(标准差)
daily_vol = log_returns.std()
# 年化波动率
annual_vol = daily_vol * np.sqrt(252)
# 输出结果
print("年化波动率:")
print(annual_vol)
嗯,这里要注意:年化波动率假设收益率是独立同分布的。实际上,金融数据有波动率聚集效应——大涨之后往往跟着大跌。所以年化波动率只是一个近似值,别把它当真理。
3.4 知识体系总览
为了让你更直观地理解这一章的知识结构,我画了一张图:
3.5 实战:完整流程
最后,我把整个流程串起来,给你一个完整的代码示例:
import numpy as np
import pandas as pd
# 1. 加载数据
prices = pd.read_csv('portfolio_prices.csv', index_col=0, parse_dates=True)
# 2. 数据清洗:检查是否有0或负值
if (prices <= 0).any().any():
print("警告:发现非正价格,正在处理...")
prices[prices <= 0] = np.nan
prices = prices.fillna(method='ffill')
# 3. 计算对数收益率
log_returns = np.log(prices / prices.shift(1)).dropna()
# 4. 计算协方差矩阵(年化)
cov_matrix_annual = log_returns.cov() * 252
# 5. 计算年化波动率
annual_vol = np.sqrt(np.diag(cov_matrix_annual))
# 6. 输出结果
print("="*50)
print("资产年化波动率:")
for i, vol in enumerate(annual_vol):
print(f"{prices.columns[i]}: {vol:.4f} ({vol*100:.2f}%)")
print("="*50)
print("\n年化协方差矩阵:")
print(cov_matrix_annual.round(6))
好了,这一章的内容就这些。记住:对数收益率是基础,协方差矩阵是核心,年化波动率是输出。这三者构成了投资组合优化的数据基石。下一章我们会用这些数据来做真正的优化——找到那条漂亮的有效前沿。