こんにちは。TATです。
今日のテーマは「Pythonでゴールデンクロスとデッドクロスを判定する」です。
Pythonを使って、移動平均線やMACDなどのゴールデンクロスやデッドクロスを判定する方法について解説します。
過去にPythonでテクニカル分析の計算方法について解説しました。
【コード解説】Pythonで株価データから主要なテクニカル分析を計算して可視化する【移動平均線、MACD、RSI】
続きを見る
また、Pythonで株価データを扱う記事については記事が散在しているのでこちらにまとめましたのでご参考ください!
Pythonで株価データを扱う方法まとめ【データの取得・分析・可視化等、なんでもできます】
続きを見る
ここで紹介している記事は自由にパクっていただいて大丈夫です!
僕のコード以外にもいい方法はいくらでもあるので、使いやすいように適宜改良しちゃってください。
目次
【コード解説】Pythonでゴールデンクロスとデッドクロスを検出する
(おさらい)株価データを用意する
まずは分析に使う株価データを用意します。
こちらについては過去記事でも解説済みなのでさらっといきます。
株価データを取得する
株価データの取得方法についてはこちらの記事で解説済みです。
お好きな方法を参考にしていただければと思います。
【日本株対応】Pythonで株価のローソク足データを取得する方法まとめ【CSV、ライブラリ、スクレイピング】
続きを見る
【Pythonコード解説】yahoo_finance_api2で日本株の株価データを取得する
続きを見る
ここではトヨタ自動車(証券コード: 7203)の日足データを使って解説していきます。
用意したデータはこんな感じです。
移動平均線を計算する
次に移動平均線を計算します。
こちらについても過去記事で解説済みなのでサクッといきます。
【コード解説】Pythonで株価データから主要なテクニカル分析を計算して可視化する【移動平均線、MACD、RSI】
続きを見る
今回は5日移動平均線と25日移動平均線でゴールデンクロスとデッドクロスを判定することにします。
df["SMA5"] = df["close"].rolling(window=5).mean() df["SMA25"] = df["close"].rolling(window=25).mean()
完成したデータがこちらです。
前半はデータがないので、ラスト5行を表示しています。
これで必要なデータは揃いました。
次にゴールデンクロスとデッドクロスを検出する方法を考えていきます。
ゴールデンクロス・デッドクロスの検出方法を考える
ゴールデンクロスとデッドクロスを判定する方法はシンプルです。
ゴールデンクロス・デッドクロスの定義を考える
まずは定義から考えてみます。
5日移動平均線と25日移動平均線で考えるとこんな感じですね。
判定方法
- 5日移動平均線が25日移動平均線を下から上に突き抜けるとゴールデンクロス
- 5日移動平均線が25日移動平均線を上から下に突き抜けるとデッドクロス
移動平均線でゴールデンクロスおよびデッドクロスを判定するなら、期間の異なる2種類の移動平均線が必要です。
期間の短いものが長いものを、下から上に突き抜けるとゴールデンクロスで、上から下に突き抜けるとデッドクロスになります。
これをプログラムでどう実装していくかを考えていきます。
ポイントは差分を見ること!
この状況をプログラムに判定させようと思うと、2つの移動平均線を差分を見ることがポイントになります。
解説のために簡単なグラフを作りました。
5日移動平均線(SMA5)と25日移動平均線(SMA25)の差分(SMA5 - SMA25)をプロットしています。
ここからわかることは次の通りです。
ポイント
- SMA5がSMA25より上にあるときは、SMA5 - SMA25はプラスの値になる。逆だとマイナスになる。
- ゴールデンクロスは、SMA5 - SMA25がマイナスからプラスに反転する。
- デッドクロスは、SMA5 - SMA25がプラスからマイナスに反転する。
チャートを見ると明らかですね。
プログラムでゴールデンクロスやデッドクロスを判定するためには、SMA5 - SMA25が反転するのを判定できれば良いことになります。
ちなみに上記のチャートはplotlyというPythonのライブラリーを使っています。
PythonのPlotlyでインタラクティブな株価のローソク足チャートを描く【コード解説】
続きを見る
プログラムではロジックをシンプルに!
また、プログラムで実装する際には、なるべくシンプルにしたいところです。
例えば、SMA5 - SMA25の値については、絶対値がいくらであるかはさほど重要でなく、プラスかマイナスかがわかればOKです。
プラスなら+1、マイナスなら−1にしておけば十分です。
こうしておくと、SMA5とSMA25の値は、-1, 0, 1のいずれかになります。
シンプルですね。
そしてこの差分の符号の反転を判定するには、1つ前の数値と比較すればOKです。
-1から1になればゴールデンクロス、1から−1になればデッドクロスです。
SMA5 - SMA25をdiff(0), その1日前の値をdiff(1)とすると次の式が成り立ちます。
ポイント
diff(0) - diff(1)の結果は、
- 2((+1)-(-1))だとゴールデンクロスを意味する
- -2((-1)-(+1))だとデッドクロスを意味する
- そのほかは何もないので無視する
かなりシンプルになりました。
これで、ゴールデンクロスとデッドクロスを判定することができます。
目で見るとゴールデンクロスやデッドクロスを判断するのは簡単ですが、プログラムで実行するとなるとこのようにロジックに落とし込んでいく必要があります。
ここがプログラムをする楽しみでもあります。
ゴールデンクロス・デッドクロスの判定ロジックをPythonで実装する
ロジックがわかったところでPythonで実装していきます。
先ほど用意したデータを使います。
基本のプログラム(とりあえずこれパクればOKです)
先ほどご紹介したロジックをプログラムで実行する流れは次のようになります。
ポイント
- SMA5 - SMA25を計算する(この結果がdiff(0)となる)
- shift関数を使ってdiffの値を1つずらす(これがdiff(1)になる)
- diff(0) - diff(1)を計算する
- 計算結果が2ならゴールデンクロス、−2ならデッドクロスと判定する
ややこしく書いていますが、プログラムとしてはとても短く済ませることができます。
まずはコードをどうぞ。2行で完了します。
import numpy as np # SMA5 と SMA25の差分を計算する diff = df["SMA5"] - df["SMA25"] # diffの各値を直前のデータで引く 2ならゴールデンクロス(GC), -2ならデッドクロス(DC)と判定する cross = np.where(np.sign(diff) - np.sign(diff.shift(1)) == 2, "GC", np.where(np.sign(diff) - np.sign(diff.shift(1)) == -2, "DC", np.nan))
これだとSMA5とSMA25にしか適用できないので、関数を作って2種類のデータを渡すと自動でゴールデンクロスとデッドクロスを判定できるようにします。
関数名はfind_crossとしました。
import numpy as np def find_cross(short, long): # 差分を計算する diff = short - long # diffの各値を直前のデータで引く 2ならゴールデンクロス(GC), -2ならデッドクロス(DC)と判定する cross = np.where(np.sign(diff) - np.sign(diff.shift(1)) == 2, "GC", np.where(np.sign(diff) - np.sign(diff.shift(1)) == -2, "DC", np.nan)) return cross
これでshortとlongを渡してあげるとゴールデンクロスとデッドクロスを判定してくれます。
こんな感じです。
なんにもなければnan、ゴールデンクロスならGC、デッドクロスならDCと返ってきます。
ざっくりコードを解説します
ここで少しコードを解説しておきます。
2行にまとめてしまったのでわかりにくいかもしれません。特に2行目。。。
最初のdiffの計算はいいですよね。
列ごと引き算しているだけです。
問題は2行目のcrossの計算です。
ポイントになるのはnumpyのwhereとsign、pandasのshiftです。
numpyのwhere
numpyのwhereは条件式に基づいて、TrueのときとFalseのときで任意の数値を返すことができます。
np.where(condition, Trueの返り値, Falseの返り値) といった使い方です。
ここでは、whereを2回使って、3つに条件分岐しています。
2のときと、−2のときと、どちらにも当てはまらないときです。
2ならGC、−2ならGC、それ以外ならnanを返します。
numpyのsign
numpyのsignを使うと、データの符号を判定することができます。
プラスなら1、マイナスなら−1が返ってきます。
これで絶対値は気にせずに数字の符号だけを扱うことができるようになります。
pandasのshift
最後にpandasのshiftです。
これを使うとデータを任意の数だけずらすことができます。
デフォルトだと1つだけずらします。
数値を入れると任意の数だけずらすことも可能です。
マイナスを入れると逆向きにシフトします。
このshiftを利用すれば、1つ前のデータと計算するのがとても容易になります。
コードにあるnp.sign(diff) - np.sign(diff.shift(1))がまさにそれです。
shiftを使って1つ前のデータを引き算して、さらにsignを合わせて1か−1に変換しています。
この結果をwhereを使って、2ならGC、−2ならDC、それ以外ならnanを返します。
numpyとpandasを利用すると、複雑な計算を短いコードで実装することが可能になります。
移動平均線でゴールデンクロス・デッドクロスを判定する
それでは計算結果を可視化してみます。
ゴールデンクロス・デッドクロスの列を追加
まずはSMA5とSMA25のゴールデンクロスとデッドクロスをプロットします。
計算結果をcrossという列として追加します。
ラスト10行を見るとDC(デッドクロス)が発生していますね。
実際に先ほどのチャートを見るとデッドクロスが起きていることがわかりますね。
チャートに描く
それではチャートにゴールデンクロスとデッドクロスをプロットしてみます。
SMA5 - SMA25は出来高に変更します。
普通のチャートはこんな感じです。
ここで使ったコードも公開しておきます。
import pandas as pd import plotly.graph_objects as go from plotly.subplots import make_subplots d_all = pd.date_range(start=df['datetime'].iloc[0],end=df['datetime'].iloc[-1]) d_obs = [d.strftime("%Y-%m-%d") for d in df['datetime']] d_breaks = [d for d in d_all.strftime("%Y-%m-%d").tolist() if not d in d_obs] # figを定義 fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.05, row_width=[0.2, 0.7], x_title="Date") # Candlestick fig.add_trace( go.Candlestick(x=df["datetime"], open=df["open"], high=df["high"], low=df["low"], close=df["close"], name="OHLC"), row=1, col=1 ) # SMA fig.add_trace(go.Scatter(x=df["datetime"], y=df["SMA5"], name="SMA5", mode="lines"), row=1, col=1) fig.add_trace(go.Scatter(x=df["datetime"], y=df["SMA25"], name="SMA25", mode="lines"), row=1, col=1) # Volume fig.add_trace( go.Bar(x=df["datetime"], y=df["volume"], name="volume"), row=2, col=1 ) # Layout fig.update_layout( title={ "text": "トヨタ自動車(7203)の日足チャート", "y":0.9, "x":0.5, } ) # y軸名を定義 fig.update_yaxes(title_text="株価", row=1, col=1) fig.update_yaxes(title_text="出来高", row=2, col=1) # 不要な日付を非表示にする fig.update_xaxes( rangebreaks=[dict(values=d_breaks)] ) fig.update(layout_xaxis_rangeslider_visible=False) fig.show()
こちらのチャートはplotlyで描いており、過去記事で解説しています。
PythonのPlotlyでインタラクティブな株価のローソク足チャートを描く【コード解説】
続きを見る
ゴールデンクロスとデッドクロスを追加する
ここにゴールデンクロスとデッドクロスを追加します。
ちょっと色変わっちゃいましたが、marker_colorを指定して適宜調整してください。
使用したコードはこちらです。
import pandas as pd import plotly.graph_objects as go from plotly.subplots import make_subplots d_all = pd.date_range(start=df['datetime'].iloc[0],end=df['datetime'].iloc[-1]) d_obs = [d.strftime("%Y-%m-%d") for d in df['datetime']] d_breaks = [d for d in d_all.strftime("%Y-%m-%d").tolist() if not d in d_obs] # figを定義 fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.05, row_width=[0.2, 0.7], x_title="Date") # Candlestick fig.add_trace( go.Candlestick(x=df["datetime"], open=df["open"], high=df["high"], low=df["low"], close=df["close"], name="OHLC"), row=1, col=1 ) # SMA fig.add_trace(go.Scatter(x=df["datetime"], y=df["SMA5"], name="SMA5", mode="lines"), row=1, col=1) fig.add_trace(go.Scatter(x=df["datetime"], y=df["SMA25"], name="SMA25", mode="lines"), row=1, col=1) """ 追加ここから """ # ゴールデンクロス fig.add_trace(go.Scatter(x=df[df["cross"]=="GC"]["datetime"], y=df[df["cross"]=="GC"]["SMA5"]*0.98, name="GC", mode="markers", marker_symbol="triangle-up", marker_size=10, marker_color="black"), row=1, col=1) # デッドクロス fig.add_trace(go.Scatter(x=df[df["cross"]=="DC"]["datetime"], y=df[df["cross"]=="DC"]["SMA5"]*1.02, name="DC", mode="markers", marker_symbol="triangle-down", marker_size=10, marker_color="black"), row=1, col=1) """ 追加ここまで """ # Volume fig.add_trace( go.Bar(x=df["datetime"], y=df["volume"], name="volume"), row=2, col=1 ) # Layout fig.update_layout( title={ "text": "トヨタ自動車(7203)の日足チャート", "y":0.9, "x":0.5, } ) # y軸名を定義 fig.update_yaxes(title_text="株価", row=1, col=1) fig.update_yaxes(title_text="出来高", row=2, col=1) # 不要な日付を非表示にする fig.update_xaxes( rangebreaks=[dict(values=d_breaks)] ) fig.update(layout_xaxis_rangeslider_visible=False) fig.show()
「追加ここから」から「追加ここまで」の部分が追加箇所になります。
ゴールデンクロスとデッドクロスでそれぞれ追加します。
条件指定でcross列がGCあるいはDCとなっているところの値をプロットします。
SMA5の値をそのまま使うとグラフが被ってしまうので、0.98倍とか1.02倍とかして少しずらして表示するようにしています。
ここの調整も好みの問題ですね。自由に変えちゃってください。
これでゴールデンクロスとデッドクロスをチャートで描くことができました。
(応用編)MACDでゴールデンクロス・デッドクロスを判定する
最後に応用編です。
MACDでゴールデンクロスとデッドクロスを判定してみます。
先ほどご紹介した関数(find_cross)を使えば、任意データのゴールデンクロスとデッドクロスを判定することができます。
ここに引き渡すデータをMACDに変更して、チャートに描いてみます。
MACDの計算
MACDの計算方法についてはこちらの記事で解説しているので割愛します。
【コード解説】Pythonで株価データから主要なテクニカル分析を計算して可視化する【移動平均線、MACD、RSI】
続きを見る
使用したコードはこちらです。
def macd(df): FastEMA_period = 12 # 短期EMAの期間 SlowEMA_period = 26 # 長期EMAの期間 SignalSMA_period = 9 # SMAを取る期間 df["MACD"] = df["close"].ewm(span=FastEMA_period).mean() - df["close"].ewm(span=SlowEMA_period).mean() df["Signal"] = df["MACD"].rolling(SignalSMA_period).mean() return df # MACDを計算する df = macd(df)
計算結果はこのようになりました。
ゴールデンクロス・デッドクロスを判定する
結果をもとにゴールデンクロスとデッドクロスを判定してみます。
返り値をcrossというカラムに格納します。
ラスト20行を確認するとデッドクロスが判定されていることが確認できました。
MACDをチャートに描く
最後に計算した結果をチャートにプロットしてみます。
出来高に加えてMACDを追加して、さらにゴールデンクロスとデッドクロスも表記します。
使用したコードがこちらです。
import pandas as pd import plotly.graph_objects as go from plotly.subplots import make_subplots d_all = pd.date_range(start=df['datetime'].iloc[0],end=df['datetime'].iloc[-1]) d_obs = [d.strftime("%Y-%m-%d") for d in df['datetime']] d_breaks = [d for d in d_all.strftime("%Y-%m-%d").tolist() if not d in d_obs] # figを定義 fig = make_subplots(rows=3, cols=1, shared_xaxes=True, vertical_spacing=0.05, row_width=[0.2, 0.2, 0.7], x_title="Date") # Candlestick fig.add_trace( go.Candlestick(x=df["datetime"], open=df["open"], high=df["high"], low=df["low"], close=df["close"], name="OHLC"), row=1, col=1 ) # Volume fig.add_trace( go.Bar(x=df["datetime"], y=df["volume"], name="volume"), row=2, col=1 ) """ MACD 追記ここから """ fig.add_trace(go.Scatter(x=df["datetime"], y=df["MACD"], name="MACD", mode="lines"), row=3, col=1) fig.add_trace(go.Scatter(x=df["datetime"], y=df["Signal"], name="Signal", mode="lines"), row=3, col=1) # ゴールデンクロス fig.add_trace(go.Scatter(x=df[df["cross"]=="GC"]["datetime"], y=df[df["cross"]=="GC"]["MACD"]-50, name="GC", mode="markers", marker_symbol="triangle-up", marker_size=7, marker_color="black"), row=3, col=1) # デッドクロス fig.add_trace(go.Scatter(x=df[df["cross"]=="DC"]["datetime"], y=df[df["cross"]=="DC"]["MACD"]+50, name="DC", mode="markers", marker_symbol="triangle-down", marker_size=7, marker_color="black"), row=3, col=1) """ MACD 追記ここまで """ # Layout fig.update_layout( title={ "text": "トヨタ自動車(7203)の日足チャート", "y":0.9, "x":0.5, } ) # y軸名を定義 fig.update_yaxes(title_text="株価", row=1, col=1) fig.update_yaxes(title_text="出来高", row=2, col=1) fig.update_yaxes(title_text="MACD", row=3, col=1) # 不要な日付を非表示にする fig.update_xaxes( rangebreaks=[dict(values=d_breaks)] ) fig.update(layout_xaxis_rangeslider_visible=False) fig.show()
これで完成したチャートがこちらです。
MACDのチャートを追加しつつ、ゴールデンクロスとデッドクロスもきちんと表記されていることが確認できました。
以上にように、find_cross関数で任意のデータを引き渡せば、ゴールデンクロスとデッドクロスを判定できるので、お好きなデータでご活用いただければと思います。
データの分析・可視化にはPythonが最適!
本記事で紹介したコードは、全てPythonを使って書いています。
Pythonはデータの分析や可視化を得意とするプログラミング言語で、さらにAI関連のライブラリーも豊富で昨今のAIブームで需要が急拡大しています。
→ 【いますぐ始められます】データ分析をするならPythonが最適です。
また、Pythonは比較的学びやすい言語でもあります。
実際、僕は社会人になってからPythonを独学で習得して転職にも成功し、Python独学をきっかけに人生が大きく変わりました。
→ 【実体験】ゼロからのPython独学を決意してから転職を掴み取るまでのお話。
Pythonの学習方法についてはいろいろな方法があります。
僕はUdemyを選びましたが、書籍やプログラミングスクールも選択肢になります。
→ 【決定版】Python独学ロードマップ【完全初心者からでもOKです】
→ 【まとめ】Pythonが学べるおすすめプログラミングスクール
→ プログラミングの独学にUdemyをおすすめする理由!【僕はUdemyでPythonを独学しました!】
まとめ
いかがでしたでしょうか。
ここでは「Pythonでゴールデンクロスとデッドクロスを判定する」というテーマで、Pythonを使って、移動平均線やMACDなどのゴールデンクロスやデッドクロスを判定する方法について解説しました。
Pythonなら複雑な処理でも短いコードで実装することができます。
ここでご紹介したコードは自由にパクっていただいて大丈夫です。
僕のコードの他にももっといい書き方はいくらでも存在します。
パクリつつ、適宜どんどん改良していっていただければと思います。
また、本記事の他に、Pythonで株価データを扱う記事については、記事が散在しているのでこちらにまとめました。
ご興味があればご参考ください!
Pythonで株価データを扱う方法まとめ【データの取得・分析・可視化等、なんでもできます】
続きを見る
ここまで読んでくださってありがとうございました。
【決定版】Python独学ロードマップ【完全初心者OK】
続きを見る
プログラミングの独学にUdemyをおすすめする理由!【僕はPythonを独学しました】