連載
» 2021年11月26日 05時00分 公開

Pythonの「Prophet」ライブラリで株価予測をしてみよう「Python」×「株価データ」で学ぶデータ分析のいろは(終)(1/3 ページ)

日々変動する株価データを題材にPythonにおけるデータ分析のいろはを学んでいく本連載。最終回はローソク足とともにこれまでに計算したオシレーターなど一式を1つのグラフで表示する方法や過去の株価データを基にした株価予測の方法を解説します。

[片渕彼富(著)/山田祥寛(監修),WINGSプロジェクト]

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

はじめに

 本連載第4回まで、オシレーターの計算とゴールデンクロス/デッドクロスの算出方法を解説しました。連載最終回としてこれまでに表示したグラフを1つにまとめて表示したり、過去の株価データを基に予測したりしてみます。連載の趣旨がデータ分析である以上、Python自体の言語仕様や文法に関しては詳しい説明を割愛する場合があることをご了承ください。

サンプルの実行方法

 サンプルファイルを実行する場合は、サンプルファイルのリンクを開いた後に、メニューの「ファイル」から「ドライブにコピーを保存」を選択して保存したコピーを「Google Colaboratory」で実行してください。

株価データの準備

 各オシレーターをグラフで表示するため、これまでに説明して方法で表示する株価データのデータフレームを作成します。pytiとTa-Libをインストールして進めてください。

株価の取得とボリンジャーバンドの計算

 日本製鉄(5401)の株価を例に、これまでのおさらいを兼ねて表示するデータを準備します。株価の取得とpytiを利用してボリンジャーバンドを計算します。

from pyti.bollinger_bands import upper_bollinger_band as bb_up
from pyti.bollinger_bands import middle_bollinger_band as bb_mid
from pyti.bollinger_bands import lower_bollinger_band as bb_low
df = get_stock_data(1928)
data = df['Close'].tolist()
period = 25
bb_up, bb_mid, bb_low = bb_up(data, period), bb_mid(data, period), bb_low(data, period) 
df['bb_up'], df['bb_mid'], df['bb_low']  = bb_up, bb_mid, bb_low
株価データの取得とボリンジャーバンドの計算(Ch5.ipynb抜粋)

オシレーターと移動平均の計算

 Ta-Libを利用して「MACD」(Moving Average Convergence Divergence)と「RSI」(Relative Strength Index)と移動平均を計算します。

import talib as ta
close = df['Close']
macd, macdsignal, _ = ta.MACD(close, fastperiod=12, slowperiod=26, signalperiod=9)
df['macd'], df['macd_signal'] = macd, macdsignal
rsi14, rsi28 = ta.RSI(close, timeperiod=14), ta.RSI(close, timeperiod=28)
df['rsi14'], df['rsi28'] = rsi14, rsi28
ma5, ma25, ma75  = ta.SMA(close, timeperiod=5), ta.SMA(close, timeperiod=25), ta.SMA(close, timeperiod=75)
df['ma5'], df['ma25'], df['ma75'] = ma5, ma25, ma75
移動平均とオシレーターの計算(Ch5.ipynb抜粋)

ゴールデンクロスとデッドクロスの算出

 移動平均からゴールデンクロスとデッドクロスを算出します。

import numpy as np
ma5, ma25 = df['ma5'], df['ma25']
cross  = ma5 > ma25
cross_shift = cross.shift(1)
temp_gc = (cross != cross_shift) & (cross == True)
temp_dc  = (cross != cross_shift) & (cross == False)
gc = [m if g == True else np.nan for g, m in zip(temp_gc, ma5)]
dc = [m if d == True else np.nan for d, m in zip(temp_dc, ma25)]
df["gc"], df["dc"] = gc, dc
ゴールデンクロスとデッドクロスの算出(Ch5.ipynb抜粋)

計算結果を確認

 計算結果を確認するため、グラフを描画させてみます(第4回のときのグラフと同じものです)。直近120日分のデータを表示します。

import plotly.graph_objs as go
pdf = df.tail(120)
layout = {
            'title'  : { 'text': "5401", 'x':0.5 }, 
            'xaxis' : { 'title': "日付", 'rangeslider': { 'visible': False } },
            'yaxis' : { 'title': "価格(円)", 'tickformat': ',' },
            'plot_bgcolor':'light blue'
          }
data =  [
    go.Candlestick(name="chart", x = pdf.index, open=pdf['Open'], high=pdf['High'], low=pdf['Low'], close=pdf['Close'], 
                   increasing_line_color= '#00ada9', decreasing_line_color= '#a0a0a0'), 
    go.Scatter(x=pdf.index, y=pdf["ma5"], name='MA5', line=dict(color="#ff007f" ,width=1.2)),
    go.Scatter(x=pdf.index, y=pdf["ma25"], name='MA25', line=dict(color='#7fbfff' ,width=1.2)), 
    go.Scatter(x=pdf.index, y=pdf["gc"], name="Golden Cross", mode='markers', marker=dict(size = 12, color='blueviolet')),
    go.Scatter(x=pdf.index, y=pdf["dc"], name="Dead Cross", mode='markers', marker=dict(size = 12, color='black', symbol = 'x'))   
]
fig = go.Figure(data = data, layout = go.Layout(layout))
fig.show()
グラフ表示(Ch5.ipynb抜粋)
直近120日分のデータ 直近120日分のデータ

ボリンジャーバンドの表示とデータの調整

 まず、先ほど算出したボリンジャーバンドをグラフに表示します。その際にデータの日付についても調整します。

ボリンジャーバンドを表示する

 ボリンジャーバンドは、バンドの上限と下限が株価の変動範囲です。このバンドの幅をグレーでグラフに表示します。サンプル内のグラフに表示するデータを次のように修正します。

data =  [
    # 中略
    go.Scatter(x=pdf.index ,y=pdf["bb_up"], name= '',line=dict(width=0)),
    go.Scatter(x=pdf.index ,y=pdf["bb_low"], name= 'BB',line=dict(width=0), fill='tonexty', fillcolor="rgba(170,170,170,0.25)"),
]
ボリンジャーバンドの表示(Ch5.ipynb抜粋)
ボリンジャーバンドの表示 ボリンジャーバンドの表示

 バンドの上限と下限を線で描画します。バンド下限のfillプロパティにtonexty(線のY軸まで塗りつぶし)を指定して、線より上の色を指定します。バンドの上限では、色を指定していないので、そこで色を付ける処理が止まります。その結果として、バンドの上限と下限の間に色が付いて株価の変動幅が表示されます。

日付曜日を考慮する

 株価(データフレーム)のindexはDateTime型です。グラフに表示する際には、株価データの存在しない営業日以外の土日祝日もデータがあるものと自動的に解釈されるので、X軸が空いてしまっている部分があります。グラフをマウスで選択すると、選択範囲が拡大できます。

土日部分の空きが確認できる 土日部分の空きが確認できる

 X軸の空きをなくす処理を作成してX軸に空きがないようにします。まずインデックスをDateTime型でない数値の連番に変更します。

df.reset_index(inplace=True)
インデックスのリセット(Ch5.ipynb抜粋)

 reset_indexメソッドでインデックスをリセットします。引数のinplaceにTrueを指定して連番のインデックスを振り直します。次に、グラフに表示する際にインデックスに対応した日付を表示する処理を作成します。

 振り直した連番のインデックスに対応する日付を表示すれば、X軸に日付は表示されます。ただし、そのまま日付を表示すると、全ては表示できなかったり、重なって表示されたりするため、3日に1日のみ表示するようにします。データフレームのDateカラムを利用して3日に1日の日付を取り出す処理は次のように考えられます。

3日に1日の日付を取り出す処理 3日に1日の日付を取り出す処理

 3日に1日の日付を取り出した後に、その日付をX軸に表示する処理は次のように書くことができます。

# 3日に1日の日付を取り出す
days_list = [df.index[idx:idx + 3] for idx in range(0,len(df.index), 3)]
dates = [df['Date'][r[0]] for r in days_list]
# X軸を更新
fig['layout'].update({
    'xaxis':{
        'showgrid': True,
        'tickvals': np.arange(0, df.index[-1],3),
        'ticktext': [x.strftime('%m/%d') for x in dates],
        }
})
グラフ表示(Ch5.ipynb抜粋)

 plotly.graph_objsのupdateメソッドを利用して、x軸(xasis)に対する表示を変更します。updateメソッドで指定できるプロパティには次のものがあります。

名前 概要
showgrid グリッドに表示するか
tickvals 表示するインデックスのリスト
ticktext 表示する文字列のリスト
レイアウトで指定するプロパティ

 tickvalsプロパティで指定したインデックスに対応する日付を、ticktextプロパティで指定します。サンプルでは、MM/DDの書式で日付を表示しています。

土日祝日を除いたグラフ 土日祝日を除いたグラフ

 サンプルを実行すると、データのない営業日以外の土日祝日を除いたグラフを表示します。ローソク足が途切れずに表示されていることを確認してみてください。

       1|2|3 次のページへ

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。