用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   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 計算收益率

收益率的計算公式如下:

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   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個交易日),其中 \mu 是日平均收益率。

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

# 計算平均年化收益
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 方差

方差是對數據離散程度的度量。下圖中藍色分布比紅色分布的方差大得多,其數據也更加分散。

圖片來源: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 ** 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 偏度

偏度是數據分布偏斜方向和程度的度量,反應分布的非對稱性。

下圖所示的曲線分別代表了負偏態和正偏態。在金融領域,人們更傾向于正的偏度,因為這意味著高盈利的概率更大。

圖片來源: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的部分稱為超值峰度。大部分金融收益都具有正的超值峰度。

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 + 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 的學習筆記。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,401評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,011評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,263評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,543評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,323評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,874評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,968評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,095評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,605評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,551評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,720評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,242評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,961評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,358評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,612評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,330評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,690評論 2 370

推薦閱讀更多精彩內容