为了账号安全,请及时绑定邮箱和手机立即绑定

用Python分析股票的收益和风险

标签:
Python

一、股票的收益

1.1 导入CSV时序数据

本文将分析微软2000年以来的股票交易数据(点我下载哦),它是一个 csv 格式的时间序列数据。你将使用 pandas 读取 csv 数据,并存储为DataFrame格式。

# 导入pandas包import pandas as pd# 读取csv文件,并将‘Date’列解析为日期时间格式,并设为索引StockPrices = pd.read_csv('MSFTPrices.csv', parse_dates=['Date'], index_col='Date')# 将数据按日期这一列排序(保证后续计算收益率的正确性)StockPrices = StockPrices.sort_values(by='Date')# 打印数据的前5行print(StockPrices.head())
              Open    High     Low     Close    Volume   AdjustedDate                                                             2000-01-03  88.777  89.722  84.712  58.28125  53228400  38.5278092000-01-04  85.893  88.588  84.901  56.31250  54119000  37.2263452000-01-05  84.050  88.021  82.726  56.90625  64059600  37.6188512000-01-06  84.853  86.130  81.970  55.00000  54976600  36.3586882000-01-07  82.159  84.901  81.166  55.71875  62013600  36.833828

该股票数据包括了交易日期、开盘价、最高价、最低价、收盘价、调整后的收盘价以及成交量。其中调整后的收盘价最为重要,它对股票分割、股息和其他公司行为进行了标准化,能真实地反映股票随时间的回报。所以本文后续的计算都是基于调整后的收盘价(Adjusted)这一列数据。

1.2 计算收益率

收益率的计算公式如下:

R_{t2} = \frac{P_{t2} - P_{t1}}{P_{t1}}

这里可理解为两天的价格差除以前一天的价格。在 pandas 中,使用 .pct_change() 方法来计算收益率。

# 增加一列'Returns', 存储每日的收益率StockPrices['Returns'] = StockPrices['Adjusted'].pct_change()# 检查前5行数据print(StockPrices.head())
              Open    High     Low     Close    Volume   Adjusted   ReturnsDate                                                                       2000-01-03  88.777  89.722  84.712  58.28125  53228400  38.527809       NaN2000-01-04  85.893  88.588  84.901  56.31250  54119000  37.226345 -0.0337802000-01-05  84.050  88.021  82.726  56.90625  64059600  37.618851  0.0105442000-01-06  84.853  86.130  81.970  55.00000  54976600  36.358688 -0.0334982000-01-07  82.159  84.901  81.166  55.71875  62013600  36.833828  0.013068

数据框增加了 Returns 一列,即股票的收益。注意第一天的收益率是缺失值 NaN,因为没有前一天的数据用于计算。
为了后续计算方便,我们选取 Returns 这一列,并将缺失值丢弃,存储在新的变量 clean_returns 中。使用 .dropna() 方法来删除缺失值。

clean_returns = StockPrices['Returns'].dropna()

绘制每日收益随时间变化的图。

# 导入matplotlib绘图包中的pyplot模块import matplotlib.pyplot as plt#绘图clean_returns.plot()
plt.show()

webp

1.3 收益的均值

均值是最常用的统计量,它将一串数据平均后浓缩为一个数值,但同时也丢失了数据波动性的信息。

可使用 numpy 包中的 mean() 函数计算股票历史收益的均值。

# 导入numpy包import numpy as np# 计算股票的日平均收益mean_return_daily = np.mean(clean_returns)
print("日平均收益:", mean_return_daily)
日平均收益: 0.00037777546435757725

通过以下公式,将日收益率转换为年化收益率(一般假设一年252个交易日),其中 \mu 是日平均收益率。

平均年化收益率 =(1+\mu)^{252}−1

# 计算平均年化收益mean_return_annualized = ((1 + mean_return_daily)**252) - 1print("平均年化收益:", mean_return_annualized)
平均年化收益: 0.09985839482858783

1.4 收益的分布

绘制收益的直方图可了解其分布情况,同时也能观察到收益中的异常值。一般在收益分布的两侧有两条长长的尾巴,在投资时一般会尽量避免左侧尾巴上的异常值,因为他们代表了较大的亏损;而分布在右侧尾巴上的异常值通常是件好事,它代表较大的盈利。

使用 matplotlib 绘图包中的 hist()函数绘制直方图。

# 绘制直方图plt.hist(clean_returns, bins=75)
plt.show()

webp

上图所示的收益是个怎样的分布呢?是正态分布吗?我们将在后续揭晓答案。

二、风险的衡量

金融市场的风险是对不确定性的度量,反应在收益的波动上。一般可用以下统计量来表示:

  • 方差或标准差

  • 偏度

  • 峰度

接下来我们将逐个计算它们。

2.1 方差

方差是对数据离散程度的度量。下图中蓝色分布比红色分布的方差大得多,其数据也更加分散。

webp

图片来源:https://en.wikipedia.org/wiki/Standard_deviation

标准差又称均方差,是方差的算数平方根。投资回报中较高的标准差意味着较高的风险,因为数据分布离均值更远了,收益的波动幅度更大。

可使用 numpy 包中的 std() 函数计算标准差 \sigma,方差则是标准差的平方 \sigma^2.

# 计算标准差sigma_daily = np.std(clean_returns)
print("标准差: ", sigma_daily)# 计算方差variance_daily = sigma_daily ** 2print("方差: ", variance_daily)
标准差:  0.019341100408708328方差:  0.0003740781650197374

以上计算的是每日的方差,我们可以将之转化成年化方差。将标准差乘以交易日数目的平方根,得到年化标准差。将年化标准差平方,就得到年化方差。

# 计算年化标准差sigma_annualized = sigma_daily*np.sqrt(252)
print("年化标准差:", sigma_annualized)# 计算年化方差variance_annualized = sigma_annualized ** 2print("年化方差:", variance_annualized)
年化标准差: 0.3070304505826317年化方差: 0.09426769758497383

2.2 偏度

偏度是数据分布偏斜方向和程度的度量,反应分布的非对称性。

下图所示的曲线分别代表了负偏态和正偏态。在金融领域,人们更倾向于正的偏度,因为这意味着高盈利的概率更大。

webp

图片来源:https://en.wikipedia.org/wiki/Skewness

可使用 scipy.stats 提供的 skew() 函数计算收益分布的偏度。

# 从 scipy.stats 导入skew函数from scipy.stats import skew# 计算收益分布的偏度returns_skewness = skew(clean_returns)
print("偏度:", returns_skewness)
偏度: 0.21935459193067852

回顾之前绘制的收益分布图,乍看之下似乎是对称分布,但经过偏度的计算,我们知道它具有稍许的正偏度。

2.3 峰度

峰度表征概率密度分布曲线在平均值处峰值高低的特征数,反映了峰部的尖度。通常将样本的峰度和正态分布相比较,因为正态分布的峰度是3,所以将超出3的部分称为超值峰度。大部分金融收益都具有正的超值峰度。

webp

kurtosis.png

使用scipy.stats提供的 kurtosis() 函数计算分布的超值峰度。

# 从 scipy.stats 导入 kurtosis 函数from scipy.stats import kurtosis# 计算收益分布的超值峰度excess_kurtosis = kurtosis(clean_returns)
print("超值峰度:", excess_kurtosis)# 计算峰度fourth_moment = excess_kurtosis + 3print("峰度:", fourth_moment)
超值峰度: 10.31457261802553峰度: 13.31457261802553

上述峰度的计算结果表明,该股票收益的峰比正态分布高得多。我们也可通过下图概率密度分布的比较看出来,图中橙色代表收益的分布,而蓝色表正态分布。

# 模拟正态分布数据,其均值和标准差与文中的股票收益相同。mu = mean_return_daily
sigma = sigma_daily
norm = np.random.normal(mu, sigma, size=10000)# 绘制正态分布的概率密度分布图plt. hist(norm, bins=100, alpha=0.8, density=True, label='Normal Distribution')# 绘制收益的概率密度分布图plt.hist(clean_returns, bins=75, alpha=0.7, density=True, label='Returns')# 增加图例说明plt.legend()# 绘图plt.show()

webp

三、收益分布正态性检验

现在让我们回到第一部分结尾提出的问题:该股票的收益分布是正态分布吗?

我们知道正态分布是对称的,其偏度为0,而该股票收益具有正的偏度0.219。正态分布的峰度是3,而该股票收益的峰度高达13.31。从这两个统计量看出,该股票收益并不是正态分布,它稍微向右偏斜,并且具有比较尖的峰。

但是这就能让我们自信的下结论吗?为了判断股票收益分布的正态性,我们需要使用真正的统计检验方法,而不是简单地检查峰度或偏度。

这里使用 scipy.stats 提供的 shapiro() 函数,对股票收益分布进行 Shapiro-Wilk 检验。该函数有两个返回值,一个是检验的t统计量,另一个是p值。现在你并不需要知道 Shapiro-Wilk 检验到底是个什么鬼,只要知道如何使用p值判断数据的正态性:如果p值小于等于0.05,就拒绝正态性假设,得出数据非正态分布的结论。

# 从 scipy.stats 导入shapirofrom scipy.stats import shapiro# 对股票收益进行Shapiro-Wilk检验shapiro_results = shapiro(clean_returns)
print("Shapiro-Wilk检验结果: ", shapiro_results)# 提取P值p_value = shapiro_results[1]
print("P值: ", p_value)
Shapiro-Wilk检验结果:  (0.9003633260726929, 0.0)P值:  0.0

计算得到的p值非常小,在目前的精度下等于0,所以我们可以肯定地说该收益分布不是正态分布。

小结

本文用Python计算了股票的收益和风险,我们首先查看了股票的收益率及其分布,接着计算指示风险的统计量:方差、偏度和峰度,最后检验了收益分布的正态性。

另外我们还学到了以下统计函数:

import numpy as np
np.mean()   # 均值np.std()    # 标准差from scipy.stats import skew, kurtosis, shapiro
skew()      # 偏度kurtosis()  # 超值峰度shapiro()   # Shapiro-Wilk检验正态性




作者:鱼心DrFish
链接:https://www.jianshu.com/p/b22bd9a587a2


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消