Python
pandas
株価
Anaconda
金融

Pythonで株価チャートのゴールデンクロスを検出

はじめに

株の買い時のシグナルとして、ゴールデンクロスというチャート上の現象が存在します。チャート分析の本には大体載っている手法ですが、実際に有効な手法なのでしょうか?本稿では、ゴールデンクロスを定義し、有効な買い時のシグナルか検討します。(注意:あくまで定義した範囲で有効かの議論であり、手法の批判を目的としたものではありません。そのため、参考にした金融に関するサイトのリンクは張っていません。また、プログラム及び分析結果の活用は自己責任でお願いします。)
【実施内容】

  • ゴールデンクロスの定義と検出プログラムの作成
  • ゴールデンクロスは買い時のシグナルかの検証

ゴールデンクロスの定義

 ゴールデンクロスとは、短期の移動平均が長期の移動平均を上回るときとされています(移動平均に関しては、 Pythonで投資アルゴリズムを開発してみる 2を参考にしてください)。まず、毎日の株価を終値に設定しました(正直、「始値」「終値」「高値」「低値」のどれがよいかわかりません)。次に、この平均する期間の長さを設定する必要があります。今回は短期平均を5日、長期平均を25日としました。最後に「上回った日」を前日は長期平均の方が高く、当日は短期平均の方が高い日としました。

ゴールデンクロスの検出

 ゴールデンクロスを検出するプログラムの説明をします。出力結果は以下のようになります。青い線が毎日の株価であり、赤い四角がゴールデンクロスを示しています(視認性向上のため、赤い四角のy値を株価にしています)。
goldencross_detection.png

プログラムの順番に説明をしていきます(まとめたソースはgoldencross_detection.pyとして、一番下に置きました)。最初の株価取得に関しては、Pythonで株価取得とローソク足チャート作成を見てください。

株価取得
import datetime
import pandas_datareader.data as web
import matplotlib.pyplot as plt
import pandas as pd

#期間の設定
start = datetime.datetime(2011, 1, 1)
end = datetime.datetime(2017, 5, 30)

#株価取得
df = web.DataReader('TM', 'google', start, end)
df = df.loc[:, ['Close']]

移動平均の計算には、pandas.rollingを用います。プログラムのとおり、windowsで平均する期間の長さを調整します。当然、平均をとるのは当日を最終日とた期間の平均です。移動平均では用いませんが、center=Trueにすることで、当日を中心日とした平均にすることもできます。

移動平均の計算
#平均する期間の設定
short_term = 5
long_term = 25

#期間平均の計算
df['av_short'] = df['Close'].rolling(window=short_term).mean()#短期平均
df['av_long'] = df['Close'].rolling(window=long_term).mean()#長期平均

ゴールデンクロスの検出を実施します。プログラムでは、列'golden_flag'にゴールデンクロスの日に当日の株価、当該日以外にNoneをいれています。

ゴールデンクロスの検出と図示
#ゴールデンクロスの検出
df['golden_flag'] = 0
current_flag=0
previous_flag=1
for i,price in df.iterrows():
    if(price['av_short']>price['av_long']):
        current_flag = 1
    else:
        current_flag = 0
    if(current_flag*(1-previous_flag)):
        df.loc[i,'golden_flag']=price['av_long']
    else:
        df.loc[i,'golden_flag']= None
    previous_flag = current_flag

#図示
df.plot(style=['-'])
plt.scatter(x= df.index,y = df['golden_flag'],marker='s',color='red')
plt.show()

ゴールデンクロス後の株価推移

 次にゴールデンクロスの後に、株価が上昇しているかを見ていきます。ゴールデンクロス当日の株価を1.0として、1~20日後の株価をプロットしていきます。仮にゴールデンクロスが買い時のシグナルであれば、全体的に株価が上昇していくはずです。プログラム(transition_after_goldencross.py)に関してですが、重複内容が多いので3点だけ説明します。
1、DataFrame.indexに基づいた次の日
 datetimeモジュールで日付を1日後に変換するには、"day+1"ではエラーになるので、"day+datetime.timedelta(days=1)"とする必要があります。さらに、次の日に株価が存在しているとは限らないので、DataFrameのindexの入っている次の日を返す関数を下のように作りました。

株価の存在する次の日を返す関数
def GetIndexNextDay(df,day):
    for p in range(1,10)://10は適当
        if((day+datetime.timedelta(days=p)) in df.index):
            next_day = day+datetime.timedelta(days=p)
            return next_day

2、ListからDataFrameへ
 株価推移をListで保存して、DataFrameに変換後にプロットしました。最初から、DataFrameでできるだろうと思いながらも、なんとなくこういう形にしました。
3、図示の工夫
 2011年から2017年のゴールデンクロス全ての推移だけを見てもよくわかないので、平均を計算して、目立つように(赤色)プロットしました。
 以上、3つの事項を踏まえた結果が以下になります。黒色の線が各ゴールデンクロス検出の日からの株価の推移です。検出日の株価を1.0としているので、day=0では、全て1.0になっています。赤色の線は全黒色の線の平均です。正直、平均的に上がっているようには見えません。
transition_after_goldencross.png

終わりに

 ゴールデンクロスは、個人的に買い時のシグナルには見えませんでした。ただし、よく見ると多くのサイト、本で偽のゴールデンクロスがあるので注意しなさいと書いていました。見分け方も書いていましたが、感覚的に書かれており、簡単に実装できなさそうので、今回はここで終わりにしておきます。

参考サイト

pandasのDataFrameのインデックスでの要素参照と代入
https://hydrocul.github.io/wiki/numpy/pandas-dataframe-ref-index.html

matplotlib.markers
http://matplotlib.org/api/markers_api.html#module-matplotlib.markers

Dataframeの代入方法
http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

Pythonで投資アルゴリズムを開発してみる 2
http://qiita.com/hiroshimoda/items/6337543ba3eb700d0aaa

ソースコード

goldencross_detection.py
import datetime
import pandas_datareader.data as web
import matplotlib.pyplot as plt
import pandas as pd

#期間の設定
start = datetime.datetime(2011, 1, 1)
end = datetime.datetime(2017, 5, 30)

#株価取得
df = web.DataReader('TM', 'google', start, end)
df = df.loc[:, ['Close']]

#平均する期間の設定
short_term = 5
long_term = 25

#期間平均の計算
df['av_short'] = df['Close'].rolling(window=short_term).mean()#短期平均
df['av_long'] = df['Close'].rolling(window=long_term).mean()#長期平均

#ゴールデンクロスの検出
df['golden_flag'] = 0
current_flag=0
previous_flag=1
for i,price in df.iterrows():
    if(price['av_short']>price['av_long']):
        current_flag = 1
    else:
        current_flag = 0
    if(current_flag*(1-previous_flag)):
        df.loc[i,'golden_flag']=price['av_long']
    else:
        df.loc[i,'golden_flag']= None
    previous_flag = current_flag


#図示
df.plot(style=['-'])
plt.scatter(x= df.index,y = df['golden_flag'],marker='s',color='red')

plt.show()
transition_after_goldencross.py
import datetime
import pandas_datareader.data as web
import matplotlib.pyplot as plt
import pandas as pd

def GetIndexNextDay(df,day):
    for p in range(1,10):
        if((day+datetime.timedelta(days=p)) in df.index):
            next_day = day+datetime.timedelta(days=p)
            return next_day

#株価取得
start = datetime.datetime(2011, 1, 1)#株価取得開始日
end = datetime.datetime(2017, 5, 30)#株価取得終了日
df = web.DataReader('TM', 'google', start, end)
df = df.loc[:, ['Close']]

#期間平均の計算
short_term = 5#短期平均の長さ
long_term = 25#長期平均の長さ
df['av_short'] = df['Close'].rolling(window=short_term).mean()#短期平均の計算
df['av_long'] = df['Close'].rolling(window=long_term).mean()#長期平均の計算

#ゴールデンクロスの検出
golden_day = []
df['golden_flag'] = 0
current_flag=0
previous_flag=1
for i,price in df.iterrows():
    if(price['av_short']>price['av_long']):
        current_flag = 1
    else:
        current_flag = 0
    if(current_flag*(1-previous_flag)):
        df.loc[i,'golden_flag']=price['Close']
        golden_day.append(i)
    else:
        df.loc[i,'golden_flag']= None
    previous_flag = current_flag

#推移の保存
transitions = []
for day in golden_day:
    day_transition = [df['Close'][day]/df['Close'][day]]
    next_day = day
    for term in range(1,20):
        next_day = GetIndexNextDay(df,next_day)
        day_transition.append(df['Close'][next_day]/df['Close'][day])
    transitions.append(day_transition)

#図示
df2 = (pd.DataFrame(ss)).T
df_mean = ((df2.T).mean()).T
df2.plot(legend=False,color = 'black')
df_mean.plot(color = 'red',lw=5)
plt.show()