使用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
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