pandasを使用して株価の日次リターン、累積リターン、リターン分布、正規Q-Qプロットを行う
以前、Rを使って試したことと同様のことをpythonで試す。
主なお題は次。
・日次リターンの計算
・日次リターンから累積リターンを求める
・リターン分布を描く
・正規Q-Qプロットを行う
まずは前回まで使用したのと同じコードで株価データを取得。
#coding:utf-8 import pandas as pd import datetime as dt import pandas_datareader.data as pdd import matplotlib.pyplot as plt ######## Define Method ######## def getMultiStockData(tickerList, date_from, date_to): def getStockData(ticker): stockData = pdd.DataReader(ticker, 'yahoo', date_from, date_to) return stockData datas = map(getStockData, tickerList) return pd.concat(datas, keys=tickerList, names=['Ticker', 'Date']) ######### 処理######### # 期間設定 date_from = dt.date(2016, 1, 24) date_to = dt.date(2016, 10, 6) # 株価取得 tickerList = ['AAPL', 'MSFT', 'IBM'] multiStockData = getMultiStockData(tickerList, date_from, date_to) # 終値を取得 adjClosingPrice = multiStockData[['Adj Close']] adjClosingPrice = adjClosingPrice.reset_index() # pandas.DataFrameをpivotingして終値データをticker毎に纏める adjClosingPriceTable = adjClosingPrice.pivot( index='Date', columns='Ticker', values='Adj Close' )
これを前提に話を進めていく。
・日次リターンの計算
これは以前「pandasで時系列データを扱う(pandas.Seriesとpandas.DataFrameを使って時系列データを扱う)2」でも触れたようにlagを取って計算するだけ。
前回は、「pandas.DataFrame.shift」を使用したが、今回は「pandas.DataFrame.pct_change」を使用する。
具体的にはこんな感じ。
daily_pct_change = adjClosingPriceTable.pct_change() # 日次リターンの計算
・日次リターンから累積リターンを求める
また、日次リターンの累積リターンを求める。
これも以前と同様に次のように実施すると良い。
# 日次リターンの累積を求める cum_daily_return = (1 + daily_pct_change).cumprod()
可視化までのソースは次。
#coding:utf-8 import pandas as pd import datetime as dt import pandas_datareader.data as pdd import matplotlib.pyplot as plt ######## Define Method ######## def getMultiStockData(tickerList, date_from, date_to): def getStockData(ticker): stockData = pdd.DataReader(ticker, 'yahoo', date_from, date_to) return stockData datas = map(getStockData, tickerList) return pd.concat(datas, keys=tickerList, names=['Ticker', 'Date']) ######### 処理######### # 期間設定 date_from = dt.date(2016, 1, 24) date_to = dt.date(2016, 10, 6) # 株価取得 tickerList = ['AAPL', 'MSFT', 'IBM'] multiStockData = getMultiStockData(tickerList, date_from, date_to) # 終値を取得 adjClosingPrice = multiStockData[['Adj Close']] adjClosingPrice = adjClosingPrice.reset_index() # pandas.DataFrameをpivotingして終値データをticker毎に纏める adjClosingPriceTable = adjClosingPrice.pivot( index='Date', columns='Ticker', values='Adj Close' ) # 日次リターンを求める daily_pct_change = adjClosingPriceTable.pct_change() # 日次リターンの計算 daily_pct_change.fillna(0, inplace=True) # Nanを0で埋める #daily_pct_change2 = adjClosingPriceTable/adjClosingPriceTable.shift(1) - 1 # 日次リターンの累積を求める cum_daily_return = (1 + daily_pct_change).cumprod() # グラフ cum_daily_return.plot(figsize=(12,8)) plt.legend(loc='Best')
・リターン分布を描く
日次リターンの値は既に求めてあるので、それをヒストグラムにするだけ。
日次リターンをヒストグラムにする部分のソースだけをピックアップしたものは次。
### 日次リターンの分布をヒストグラムにする # AAPLの日次リターン return_aapl = daily_pct_change['AAPL'] # AAPLの日次リターンヒストグラム return_aapl.hist(bins=50, figsize=(12,8)); # 全ての株価の日次リターンヒストグラム daily_pct_change.hist(bins=50, sharex=True, figsize=(12,8));
グラフを見ると、次のように見える。
・日次リターンは0近辺に集まりがち
・若干偏りは見られるが、正規分布のように見える
これを数値で確認するには、describeメソッドを使用する。
# describe print return_aapl.describe()
結果は次。
count 179.000000
mean 0.000965
std 0.014991
min -0.065707
25% -0.005662
50% 0.000901
75% 0.008158
max 0.064963
Name: AAPL, dtype: float64
・正規Q-Qプロットを行う
「scipy.stats」を使用する。
最後なので、全てコードを載せておく。
#coding:utf-8 import pandas as pd import numpy as np import datetime as dt import pandas_datareader.data as pdd import matplotlib.pyplot as plt import scipy.stats as stats ######## Define Method ######## def getMultiStockData(tickerList, date_from, date_to): def getStockData(ticker): stockData = pdd.DataReader(ticker, 'yahoo', date_from, date_to) return stockData datas = map(getStockData, tickerList) return pd.concat(datas, keys=tickerList, names=['Ticker', 'Date']) ######### 処理######### # 期間設定 date_from = dt.date(2016, 1, 24) date_to = dt.date(2016, 10, 6) # 株価取得 tickerList = ['AAPL', 'MSFT', 'IBM'] multiStockData = getMultiStockData(tickerList, date_from, date_to) # 終値を取得 adjClosingPrice = multiStockData[['Adj Close']] adjClosingPrice = adjClosingPrice.reset_index() # pandas.DataFrameをpivotingして終値データをticker毎に纏める adjClosingPriceTable = adjClosingPrice.pivot( index='Date', columns='Ticker', values='Adj Close' ) # 日次リターンを求める daily_pct_change = adjClosingPriceTable.pct_change() # 日次リターンの計算 daily_pct_change.fillna(0, inplace=True) # Nanを0で埋める # AAPLの日次リターン return_aapl = daily_pct_change['AAPL'] # プロット f = plt.figure(figsize=(12, 8)) ax = f.add_subplot(111) ax.set_title("Probplot") stats.probplot(return_aapl, dist='norm', plot=ax) plt.show()
※)グラフを描画した直後に下記エラーが発生する。
line 313, in probplot
plot.title('Probability Plot')
TypeError: 'Text' object is not callable
発生箇所は、morestats.pyの次の箇所。
line 313, in probplot plot.title('Probability Plot') TypeError: 'Text' object is not callable
原因は調べられていないが、フレーム内部なのでバグかもしれない。あとで調べておく。
最後に、scipyでShapiro Testを行う。
# Shapiro Test print stats.shapiro(return_aapl)
結果は・・・。
あれ、これはp値が0.05未満なのでデータが正規分布に従っているという帰無仮説が棄却される?
(0.9281759858131409, 9.659175503884398e-08)