本文將用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 Adjusted
Date
2000-01-03 88.777 89.722 84.712 58.28125 53228400 38.527809
2000-01-04 85.893 88.588 84.901 56.31250 54119000 37.226345
2000-01-05 84.050 88.021 82.726 56.90625 64059600 37.618851
2000-01-06 84.853 86.130 81.970 55.00000 54976600 36.358688
2000-01-07 82.159 84.901 81.166 55.71875 62013600 36.833828
該股票數據包括了交易日期、開盤價、最高價、最低價、收盤價、調整后的收盤價以及成交量。其中調整后的收盤價最為重要,它對股票分割、股息和其他公司行為進行了標準化,能真實地反映股票隨時間的回報。所以本文后續的計算都是基于調整后的收盤價(Adjusted)這一列數據。
1.2 計算收益率
收益率的計算公式如下:
這里可理解為兩天的價格差除以前一天的價格。在 pandas 中,使用 .pct_change()
方法來計算收益率。
# 增加一列'Returns', 存儲每日的收益率
StockPrices['Returns'] = StockPrices['Adjusted'].pct_change()
# 檢查前5行數據
print(StockPrices.head())
Open High Low Close Volume Adjusted Returns
Date
2000-01-03 88.777 89.722 84.712 58.28125 53228400 38.527809 NaN
2000-01-04 85.893 88.588 84.901 56.31250 54119000 37.226345 -0.033780
2000-01-05 84.050 88.021 82.726 56.90625 64059600 37.618851 0.010544
2000-01-06 84.853 86.130 81.970 55.00000 54976600 36.358688 -0.033498
2000-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()
1.3 收益的均值
均值是最常用的統計量,它將一串數據平均后濃縮為一個數值,但同時也丟失了數據波動性的信息。
可使用 numpy 包中的 mean()
函數計算股票歷史收益的均值。
# 導入numpy包
import numpy as np
# 計算股票的日平均收益
mean_return_daily = np.mean(clean_returns)
print("日平均收益:", mean_return_daily)
日平均收益: 0.00037777546435757725
通過以下公式,將日收益率轉換為年化收益率(一般假設一年252個交易日),其中 是日平均收益率。
# 計算平均年化收益
mean_return_annualized = ((1 + mean_return_daily)**252) - 1
print("平均年化收益:", mean_return_annualized)
平均年化收益: 0.09985839482858783
1.4 收益的分布
繪制收益的直方圖可了解其分布情況,同時也能觀察到收益中的異常值。一般在收益分布的兩側有兩條長長的尾巴,在投資時一般會盡量避免左側尾巴上的異常值,因為他們代表了較大的虧損;而分布在右側尾巴上的異常值通常是件好事,它代表較大的盈利。
使用 matplotlib 繪圖包中的 hist()
函數繪制直方圖。
# 繪制直方圖
plt.hist(clean_returns, bins=75)
plt.show()
上圖所示的收益是個怎樣的分布呢?是正態分布嗎?我們將在后續揭曉答案。
二、風險的衡量
金融市場的風險是對不確定性的度量,反應在收益的波動上。一般可用以下統計量來表示:
- 方差或標準差
- 偏度
- 峰度
接下來我們將逐個計算它們。
2.1 方差
方差是對數據離散程度的度量。下圖中藍色分布比紅色分布的方差大得多,其數據也更加分散。
標準差又稱均方差,是方差的算數平方根。投資回報中較高的標準差意味著較高的風險,因為數據分布離均值更遠了,收益的波動幅度更大。
可使用 numpy 包中的 std()
函數計算標準差 ,方差則是標準差的平方
.
# 計算標準差
sigma_daily = np.std(clean_returns)
print("標準差: ", sigma_daily)
# 計算方差
variance_daily = sigma_daily ** 2
print("方差: ", variance_daily)
標準差: 0.019341100408708328
方差: 0.0003740781650197374
以上計算的是每日的方差,我們可以將之轉化成年化方差。將標準差乘以交易日數目的平方根,得到年化標準差。將年化標準差平方,就得到年化方差。
# 計算年化標準差
sigma_annualized = sigma_daily*np.sqrt(252)
print("年化標準差:", sigma_annualized)
# 計算年化方差
variance_annualized = sigma_annualized ** 2
print("年化方差:", variance_annualized)
年化標準差: 0.3070304505826317
年化方差: 0.09426769758497383
2.2 偏度
偏度是數據分布偏斜方向和程度的度量,反應分布的非對稱性。
下圖所示的曲線分別代表了負偏態和正偏態。在金融領域,人們更傾向于正的偏度,因為這意味著高盈利的概率更大。
可使用 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的部分稱為超值峰度。大部分金融收益都具有正的超值峰度。
使用scipy.stats提供的 kurtosis()
函數計算分布的超值峰度。
# 從 scipy.stats 導入 kurtosis 函數
from scipy.stats import kurtosis
# 計算收益分布的超值峰度
excess_kurtosis = kurtosis(clean_returns)
print("超值峰度:", excess_kurtosis)
# 計算峰度
fourth_moment = excess_kurtosis + 3
print("峰度:", 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()
三、收益分布正態性檢驗
現在讓我們回到第一部分結尾提出的問題:該股票的收益分布是正態分布嗎?
我們知道正態分布是對稱的,其偏度為0,而該股票收益具有正的偏度0.219。正態分布的峰度是3,而該股票收益的峰度高達13.31。從這兩個統計量看出,該股票收益并不是正態分布,它稍微向右偏斜,并且具有比較尖的峰。
但是這就能讓我們自信的下結論嗎?為了判斷股票收益分布的正態性,我們需要使用真正的統計檢驗方法,而不是簡單地檢查峰度或偏度。
這里使用 scipy.stats 提供的 shapiro()
函數,對股票收益分布進行 Shapiro-Wilk 檢驗。該函數有兩個返回值,一個是檢驗的t統計量,另一個是p值。現在你并不需要知道 Shapiro-Wilk 檢驗到底是個什么鬼,只要知道如何使用p值判斷數據的正態性:如果p值小于等于0.05,就拒絕正態性假設,得出數據非正態分布的結論。
# 從 scipy.stats 導入shapiro
from 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檢驗正態性
如果你想自己下載股票數據的話,可以參考這篇文章 《如何用Python下載金融數據》。
注:本文是 DataCamp 課程 Intro to Portfolio Risk Management in Python 的學習筆記。