Pyhton|S&P 500的平均報酬及標準差

MinKuan
5 min readFeb 2, 2023

--

使用python及yfinance抓取S&P 500的歷史報價,最後則是繪製縱軸為報酬,橫軸為標準差的散佈圖。

在本文開始前可以先閱讀Python|S&P 500中股票的產業別,因後續會根據股票的產業類別繪製散佈圖。若尚未安裝yfinance的同學們,可以先去看https://pypi.org/project/yfinance/,當中會教學如何安裝以及使用。本文的完整程式碼放置在最下方。

首先需要取得S&P 500的股票代號。

import pandas as pd

table = pd.read_html("https://en.wikipedia.org/wiki/List_of_S%26P_500_companies")[0]#爬取網站及讀取需要的表格
table = table[['Symbol', 'GICS Sector']]#擷取需要的欄位
table

接著就是使用yfinance 抓取需要的股價以及期間。

import yfinance as yf
data = yf.download(table['Symbol'].to_list(), start='2012-01-01', end='2022-12-31')
data

有了報價後,則可以直接計算每日的股價報酬,而股價報酬又有分為簡單報酬以及取log的報酬,分別如下:

Simple return
Log return
#Simple return
data['Adj Close'].pct_change()

#Log return
import numpy as np
np.log(data['Adj Close']) - np.log(data['Adj Close'].shift(1))

在本文中選擇使用log return,單純覺得較為炫泡。為了方便後續使用,直接另一個DataFrame。

df = np.log(data['Adj Close']) - np.log(data['Adj Close'].shift(1))

接著就可以根據報酬計算平均及標準差了,並在後續也是存成DataFrame。常用的年化天數包含250、252、365,此處使用365為年化標準,要注意的是年化並不會250搭配252使用,一定要統一使用相同的天數。

ret_mean = df.mean()*356 #annualized rate of mean return

ret_std = df.std()*(365**0.5) #annualized rate of std return

dfs = pd.DataFrame({'ret_mean':ret_mean, 'ret_std':ret_std})

還記得先前的產業別嗎?經過一連串的股價資料處理後,則是需要將產業的標籤給貼上去。

dfs = pd.merge(dfs, table, on='Symbol', how='left')

最後就是繪製出報酬散佈圖。

import matplotlib.pyplot as plt
import seaborn as sns

plt.rcParams.update({'font.size': 16})

fig, ax = plt.subplots(figsize=(8,5))

ax = sns.scatterplot(x="ret_std", y="ret_mean" ,hue="GICS Sector", data=dfs,
alpha=0.8, s=100)

ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))

ax.set(title='S&P 500 Sector Return')

plt.show()

然而有些人可能僅對部分產業有興趣,則可以事先挑選出來再繪製。

# Focus on the interested sectors from S&P 500
labels = ['Health Care','Information Technology', 'Financials']
focus = dfs.loc[dfs['GICS Sector'].isin(labels)]
display(focus)

plt.rcParams.update({'font.size': 16})

fig, ax = plt.subplots(figsize=(8,5))

#change the data to focus
ax = sns.scatterplot(x="ret_std", y="ret_mean" ,hue="GICS Sector", data=focus,
alpha=0.8, s=100)

ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))

ax.set(title='S&P 500 Sector Return')

plt.show()

本文程式碼在https://github.com/MinKuanIsHere/SP500SectorandQuote/blob/main/SP500Quote.ipynb

--

--

MinKuan
MinKuan

No responses yet