在量化投资的世界里,收益率是我们衡量投资表现最基础的指标。想象一下,你昨天用100元买入一只股票,今天涨到了105元,那么这5元的盈利就是你的收益,而收益率就是5元相对于100元的比例,也就是5%。
简单收益率(Simple Return)的计算公式非常直观:
code复制简单收益率 = (当前价格 - 前期价格) / 前期价格
在Python中,我们可以用pandas的pct_change()方法轻松计算简单收益率。这个方法会自动计算当前值与前一值的百分比变化,非常适合处理时间序列数据。
对数收益率(Log Return)则是另一种表达方式,它的计算公式是:
code复制对数收益率 = ln(当前价格) - ln(前期价格)
为什么需要两种收益率计算方法呢?简单收益率更符合我们的直觉,而对数收益率在数学处理上有独特的优势。举个生活中的例子,就像我们用摄氏度和华氏度测量温度一样,两种收益率各有适用的场景。
首先,我们需要准备好Python环境和数据。我推荐使用Jupyter Notebook进行这类分析,因为可以实时看到每一步的结果。
python复制import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 读取股票数据
data = pd.read_csv('stock_data.csv', index_col=0, parse_dates=True)
data.head()
简单收益率的计算在pandas中非常简单:
python复制data['simple_return'] = data['close'].pct_change()
这里有几个实用技巧:
对数收益率的计算同样直接:
python复制data['log_return'] = np.log(data['close'] / data['close'].shift(1))
或者使用另一种等效写法:
python复制data['log_return'] = np.log(data['close']).diff()
这两种写法得到的结果完全相同,可以根据个人喜好选择。
简单收益率最大的特点是直观易懂。比如20元涨到30元,收益率就是50%,这个计算方式与我们日常生活中的理解完全一致。
但是简单收益率在长期计算时有个缺点:它不具备可加性。也就是说,5天的收益率不能简单相加得到5天的总收益率,而是需要累乘:
python复制total_return = (1 + r1) * (1 + r2) * ... * (1 + rn) - 1
对数收益率最大的优势就是具有可加性。这在长期分析中特别有用:
python复制# 5天的对数收益率总和等于这5天的总对数收益率
total_log_return = log_r1 + log_r2 + ... + log_r5
这种可加性使得对数收益率在构建资产净值曲线时特别方便。我们可以通过累加对数收益率,再取指数,就能得到净值曲线。
对数收益率的可加性使得净值计算变得非常简单:
python复制data['cumulative_log'] = np.exp(data['log_return'].cumsum())
这个操作背后的数学原理是:
code复制净值 = exp(对数收益率之和)
虽然简单收益率不具备可加性,但我们仍然可以通过累乘来计算净值:
python复制data['cumulative_simple'] = (1 + data['simple_return']).cumprod()
有趣的是,虽然计算方法不同,但两种方法得到的净值曲线是完全一致的。这是因为:
code复制exp(ln(Pt/P0)) = Pt/P0
这个数学等式保证了两种方法的等价性。在实际操作中,我通常会同时计算两种净值曲线,作为互相验证的手段。
让我们通过一个完整的例子来演示整个过程。假设我们有一只股票的历史价格数据:
python复制# 生成示例数据
np.random.seed(42)
dates = pd.date_range('2023-01-01', periods=100)
prices = 100 * np.exp(np.random.normal(0, 0.02, 100).cumsum())
data = pd.DataFrame({'close': prices}, index=dates)
# 计算收益率
data['simple_return'] = data['close'].pct_change()
data['log_return'] = np.log(data['close']).diff()
# 计算净值
data['cumulative_log'] = np.exp(data['log_return'].cumsum())
data['cumulative_simple'] = (1 + data['simple_return']).cumprod()
# 绘制净值曲线
plt.figure(figsize=(12, 6))
plt.plot(data.index, data['cumulative_log'], label='Log Return')
plt.plot(data.index, data['cumulative_simple'], '--', label='Simple Return')
plt.title('Cumulative Return Comparison')
plt.legend()
plt.show()
在真实项目中,有几个关键点需要注意:
我曾经在一个项目中忽略了复权处理,导致收益率计算出现了偏差。后来通过添加复权因子修正了这个问题:
python复制# 复权处理示例
data['adjusted_close'] = data['close'] * data['adjust_factor']