<あらすじ>
「買われすぎ」や「売られすぎ」といった相場の勢いを表す過熱感
その過熱感を数値で判断できるRSIについて検証しました。
TOPIX500銘柄の過去5年分のデータを使って
RSIの買いサインの数日後に、株価が上がっているのかを調査します。
<結論>
・RSIの使い方次第で確実に勝率を上げられる
・投資タイミングの判断材料として有効である
きっかけ
最初にテクニカル分析の初歩である「単純移動平均線のゴールデンクロス」について
次に株価の変化に敏感な「MACD」について検証してきました。
・【5年分データ分析】ゴールデンクロスの数日後に株価は上がっているのか
・【5年分データ分析】MACDの買いサインから上がる確率を検証しました
結果だけ述べると、
・単純移動平均線のゴールデンクロスは役に立たない
・MACDは買いサインとして有効である
という結果が得られました。
MACDの有効性を確認しましたが、他のテクニカル手法と組み合わせて精度を上げたいです。
MACDには過熱感がわからないという特徴があります。
過熱感とは「買われすぎ」や「売られすぎ」といった相場の勢いのことです。
MACDは2つの移動平均線の差であり上限/下限がないため、過熱感が読み取れないのです。
その過熱感を表す指標としてRSI(Relative Strength Index)がよく使用されます。
ということで、今回は「RSI」について5年分のデータを使って検証したいと思います。
※ MACDとRSIの組み合わせは次回を予定
RSI(アール・エス・アイ)
株価が10日間も上昇し続けると、多くの投資家は心理的に「かなり買われただろう...そろそろ下がりそうだ」、逆に10日間売られていたなら「かなり売られた・・・そろそろ上昇するだろう」と考えたくなるものです。
しかし「買われすぎ」「売られすぎ」と言っても、どこまでが買われすぎ/どこまでが売られすぎなのか明確な基準がありません。
そこで登場するのがRSIで、買われすぎ/売られすぎを数値で判断できる指標です。
簡単にRSIの内容を紹介すると
算出方法は次式です。($n$には14日が使用されることが多い)
RSI[%] = \frac{A}{A+B} \times 100\\
A=n日間の値上がり幅の平均\\
B=n日間の値下がり幅の平均\\
RSIは0~100%の値をとり、一般的に
70%以上:買われすぎ
30%以下:売られすぎ
とされています。
詳しくはこちらなどをご参照ください。
RSIを買いタイミングの判断に使用する場合は、値が小さくなった(売られすぎ)ときです。
RSIの買いサイン
RSIが小さくなった期間の中でも、どのタイミングで購入するか決める必要があります。
今回は以下の2パターンを採用します。
① 基準値を下回ったとき
② 基準値を下から上に突き抜けたとき
TOPIX500銘柄の過去5年分のデータを使って
RSIの買いサインの数日後に、株価が上がっているのかを検証します。
検証方法
大まかな流れはTOPIX500銘柄を対象に5年分のデータからRSIの買いサインを見つけ、その数日後に株価が上がっているのかを調査します。また、買いサインの基準値を変化させて結果を比較します。
今回は数日後に上昇している確率に加えて
買いサインから何%株価が変動したのかを表す、株価の変化率(変動率)の分布も求めました。
一旦、検証パラメータを羅列しますが、後ほど例を使って説明します。
【検証期間】
2015年1月1日~2020年1月29日の約5年間
【対象銘柄】
TOPIX500銘柄
【RSIの設定期間】
- 9日
- 14日(最も使われる)
- 22日
- 42日
【株価の上昇を確認する日】
- 1日後
- 3日後
- 5日後
- 10日後
【基準値】
<基準値を下回ったとき>
- 30%
- 25%
- 20%
<基準値を下から上に突き抜けたとき> - 30%
- 25%
- 20%
例
RSIの買いサインが生じた日から見て、数日後に上昇してるかを確認します。
▼検証方法の概要(基準値:30%を下回ったとき)
▼検証方法の概要(基準値:30%を下から上に突き抜けたとき)
上の例では基準値を30%としましたが、基準値を20,25,30%の3通りで検証します。
実際にトヨタ自動車のデータを使って、買いサインに「基準値:30%を下回ったとき」を使った場合を説明します。
見やすさのために、2018年1月~2021年1月の約3年分のデータを用いました。
赤丸はRSIが30%を下回った日を示しています。
この時の株価から1,3,5,10日後に上がっているのかを調べます。
▼RSI(設定期間:14日,基準値:30%)の買いサイン
買いサインから1,3,5,10日後に株価がどれだけ変動したか(変化率)を求め、分布図も作成します。
基準値を変更した場合や、買いサインに「基準値を下から上に突き抜けたとき」を使用した場合も基本的に同じです。
検証結果
ここでは1,3,5,10日後に上昇している確率を全通りと、分布図を一部記載します。
残りの結果は記事の最後にまとめて記載します。
使用するデータは前述の通りTOPIX500銘柄の5年間です。
【RSIの設定期間】
- 9日
- 14日(最も使われる)
- 22日
- 42日
【基準値】
<基準値を下回ったとき>
- 30%
- 25%
- 20%
<基準値を下から上に突き抜けたとき> - 30%
- 25%
- 20%
早速ですが結果を表にまとめました。
上昇確率が55%以上の場合に太字となっています。
▼基準値を下回ったとき
▼基準値を下から上に突き抜けたとき
【表からわかること】
・基準値が小さくなるほど上昇する確率が上がる
・RSIの設定期間が長いほど上昇する確率が上がる
・基準値を「下回ったとき」よりも「下から上に突き抜けたとき」の方が上昇する確率が高い
注意点:基準値が低い/設定期間が長い場合、そもそも買いサインの総数が少ない
次に株価の変化率(買いサインから何%株価が変動したか)の分布をいくつか示します。
青が上昇,赤が下落を表します。
▼5日後の株価の変化率分布(RSIの設定期間:22日,基準値:30%を下回ったとき)
▼5日後の株価の変化率分布(RSIの設定期間:22日,基準値:25%を下から上に突き抜けたとき)
▼5日後の株価の変化率分布(RSIの設定期間:22日,基準値:20%を下から上に突き抜けたとき)
ここでは比較のために、5日後の株価の変化率/RSIの設定期間を22日の分布図を載せました。
【分布図からわかること】
・買いサインの基準を厳しく(基準値を小さく)すると、買いサインの総数は少なくなる
・買いサインの基準を厳しくすると分布の山が右に移動するだけでなく形も変わる(山の右肩が上昇)
⇒ 上昇する確率が上がる、かつ、大きな上昇が見込める
まとめ
「買われすぎ」や「売られすぎ」といった相場の勢いを表す過熱感
その過熱感を数値で判断できるRSIについて検証しました。
個人的には以下の2つが面白いと感じました。
・基準値を「下回ったとき」よりも「下から上に突き抜けたとき」の方が上昇する確率が高い
・買いサインの基準を厳しくすると分布の山が右に移動するだけでなく形も変わる
・基準値を「下回ったとき」よりも「下から上に突き抜けたとき」の方が上昇する確率が高い
これは逆張りよりも順張りの方が上昇する確率が高いことを意味しています。
逆張り:株価が下落している最中に買うこと
順張り:株価が上昇している最中に買うこと
RSIが下がっているときは、売られすぎ(=株価が下落している)であるため
基準値を「下回ったとき」は逆張り、「下から上に突き抜けたとき」は順張りに当たるからです。
・買いサインの基準を厳しくすると分布の山が右に移動するだけでなく形も変わる
これは分布図の山が同じ形のまま右に動いて、株価が上昇する確率が上がるのではなく
変化率10%あたりの数が増加して、山が右肩上がりになっているのです。
大きな上昇が見込めることを意味しています。
買いサインの発生頻度は多くはありませんが
RSIを投資タイミングの判断材料として有効であることを確認できました。
次は
RSIとMACDとの組み合わせによって、精度が上がるのかを検証してみたいと思います。
また、過熱感を表す指標として「ストキャスティクス」「移動平均線乖離率」などがあります。
RSIの検証結果がなかなか面白かったので、この2つも検証してみたいです。
変化率の分布結果の一覧
数が多く全てを載せきれないため
以下の変化率の分布を記載します。
【検証期間】
2015年1月1日~2020年1月29日の約5年間
【対象銘柄】
TOPIX500銘柄
【RSIの設定期間】
- 9日
- 14日(最も使われる)
- 22日
- 42日
【株価の上昇を確認する日】
- 1日後
- 3日後
- 5日後
- 10日後
【基準値】
<基準値を下回ったとき>
- 30%
<基準値を下から上に突き抜けたとき> - 30%
- 25%
▼基準値30%を下回ったとき(設定期間:9,14日)
▼基準値30%を下回ったとき(設定期間:22,42日)
▼基準値30%を下から上に突き抜けたとき(設定期間:9,14日)
▼基準値30%を下から上に突き抜けたとき(設定期間:22,42日)
▼基準値25%を下から上に突き抜けたとき(設定期間:9,14日)
▼基準値25%を下から上に突き抜けたとき(設定期間:22,42日)
検証プログラム
自作の関数や株価データの取得は後日、別の記事にまとめる予定です。
import trade_package as tp # 株価分析用に自作した関数をまとめたもの
import pandas as pd
import matplotlib.pyplot as plt
from math import ceil
# 銘柄コードの読み込み
stocks = tp.get.topix500()
# resultデータフレーム作成
day = [1,3,5,10] # 株価を確認する日(〇日後の株価)
col=["buy_sign_count"]
period = [9,14,22,42] # RSIの設定期間
for d in day:
col.append("roc_d"+str(d)+"_plus")
result = pd.DataFrame(data=0,index=range(len(period)),columns=col)
# rocマップのデータフレーム
col=[]
for p in period:
for d in day:
col.append("roc_p"+str(p)+"_d"+str(d))
index=[]
# 分布図の設定(-40~40%を2%間隔)
for i in range(-42,42,2):
if(i==40):
index.append(str(i)+"~")
elif(i==-42):
index.append("~"+str(i+2))
else:
index.append(str(i)+"~"+str(i+2))
roc_map = pd.DataFrame(data=0,index=index,columns=col)
for code in stocks.code:
print(code)
# 用意した株価データの読み込み
read_data = tp.get.price(code)
for p in range(len(period)):
data = read_data.copy()
# RSIを計算
tp.tech.rsi(data, period=period[p])
data["buy_sign"] = False
# タイミングを取得
point = 20
for i in range(len(data.index)-1):
# 下回ったとき
# if(data.rsi[i]>point and data.rsi[i+1]<=point):
# data["buy_sign"].iat[i+1] = True
# 下から上へ突破したとき
if(data.rsi[i]<point and data.rsi[i+1]>=point):
data["buy_sign"].iat[i+1] = True
# 〇日後に上昇しているか確認
for bs in data.index[data.buy_sign]:
for d in day:
if(len(data.Close[:bs])+d<=len(data.Close)):
data.at[bs,"roc_d"+str(d)] = (data.Close[len(data.Close[:bs])+d-1]-data.Close[bs])/data.Close[bs]*100
else:
# 〇日後の株価がない場合は最新の株価
data.at[bs,"roc_d"+str(d)] = (data.Close[-1]-data.Close[bs])/data.Close[bs]*100
# 分布に振り分け
roc_index = 20+ceil(data.at[bs,"roc_d"+str(d)]/2)
if(roc_index<0):
roc_index=0
elif(roc_index>41):
roc_index=41
roc_map.at[index[roc_index],"roc_p"+str(period[p])+"_d"+str(d)] += 1
# 上昇した数をカウント/roc分布を画像出力
for p in range(len(period)):
result["buy_sign_count"].iat[p] = sum(roc_map.iloc[:,p*len(day)])
for d in range(len(day)):
result["roc_d"+str(day[d])+"_plus"].iat[p]=sum(roc_map.iloc[21:,p*len(day)+d])
# roc分布を画像出力
fig = plt.figure(figsize=(16, 12))
ax = fig.add_subplot(111)
bar_list = ax.bar(roc_map.index,roc_map["roc_p"+str(period[p])+"_d"+str(day[d])], width=1, color="#8ac6d1")
[bar_list[i].set_color("#ffb6b9") for i in range(21)]
ax.set_xticklabels(roc_map.index,rotation=90)
ax.tick_params(labelsize=20)
ax.grid(axis="y",c="lightgray")
title = "RSI (period="+str(period[p])+", x day later="+str(day[d])+")"
ax.set_title(title,fontsize=24)
ax.set_xlabel("Rate of Change [%]", fontsize=24)
ax.set_ylabel("counts", fontsize=24)
fig.savefig(title+".png", bbox_inches='tight')
print(result)