用数组算收益率
有了收盘价,第一件要算的通常是涨了多少。本章用 NumPy 计算相邻两天的简单收益率,并计算这组收益率的均值和样本标准差。
学完后,应能不用循环算出一列价格的简单收益率,并说明 std(ddof=1) 和 std(ddof=0) 的差别。
简单收益率
第 \(t\) 天的简单收益率是
四天价格 [10.0, 10.5, 10.2, 11.0] 能算出三天收益。第一天没有前一天,所以收益率比价格少一个。
import numpy as np
prices = np.array([10.0, 10.5, 10.2, 11.0])
returns = prices[1:] / prices[:-1] - 1
print(prices[1:])
print(prices[:-1])
print(returns)
[10.5 10.2 11. ]
[10. 10.5 10.2]
[ 0.05 -0.02857143 0.07843137]
prices[1:] 是从第二天起的价格,prices[:-1] 是到倒数第二天为止的价格。两段对齐之后相除,再减 1。
手工核对第一天:\(10.5 / 10.0 - 1 = 0.05\),也就是上涨 5%。第二天:\(10.2 / 10.5 - 1 \approx -0.0286\),下跌约 2.86%。
均值和标准差
print(returns.mean())
print(returns.std(ddof=1))
print(returns.std(ddof=0))
0.03328664799253037
0.05542474143737393
0.04525411188241907
mean() 是算术平均。这三天的平均简单收益率约为 0.0333,也就是 3.33%。
标准差衡量这组数散得有多开。样本标准差的分母是 \(n-1\),NumPy 里写成 ddof=1。ddof=0 的分母是 \(n\),数值会小一点。课程里报告一组历史收益的波动时,用 ddof=1。后面讲年化波动率,也沿用这个约定。
三个数的样本标准差大约是 0.0554。样本只有三天,这个数还不能当成这只证券的波动率,这里只是把公式跑通。
先写成数组,再考虑循环
同一计算用循环可以写成:
out = []
for i in range(1, len(prices)):
out.append(prices[i] / prices[i - 1] - 1)
结果和 prices[1:] / prices[:-1] - 1 相同。数组写法短,也不容易把下标写错。数据到了几千行,数组运算通常也更快。循环留到下标规则本身就是题目的时候再用,例如“只保留成交量大于某个门槛的那些天”,那种筛选放到 Pandas 一章。
和后面章节的关系
本章的收益率是简单收益率,用在持有期收益、净值连乘。对数收益率是 \(\ln(P_t / P_{t-1})\),用在波动率和蒙特卡洛,到可视化与时间序列和收益分布与风险价值再算。两套数不要混在同一个公式里。
课堂练习
- 用
[10, 10, 10, 12]计算简单收益率,说明为什么前两天的收益是 0。 - 把
returns.mean()的结果乘以 100,写成百分数,保留两位小数。 - 对同一组收益率分别打印
std(ddof=1)和std(ddof=0),写出哪一个更大。
例子见 examples/fintech/returns.py。