読者です 読者をやめる 読者になる 読者になる

今日も窓辺でプログラム

外資系企業勤めのエンジニアが勉強した内容をまとめておくブログ

日経平均の終値が始値より上がるか下がるかを予測する ~株価予測(5)~

今回やること

日経平均の終値が、その日の始値に比べて「上がる」か「下がる」か「ほぼ変わらない」かを、TensorFlowを使用して予測してみたいと思います。

前回までの記事では、日経平均の終値が前日の終値と比べて上がるか下がるかを予測するモデルを作成し、7割程度の精度を達成していました。
前回記事:
隠れ層の数を調整してみる ~株価予測(4)~ - 今日も窓辺でプログラム

関連記事一覧:
株価予想 カテゴリーの記事一覧 - 今日も窓辺でプログラム

「上がる」「下がる」「変わらない」の基準

日経平均が始値から終値の間に大きく動くことはあまりない印象なのですが、実際どの程度変動すれば「上がる」や「下がる」と言えるのでしょうか。過去1000日のデータを見てみましょう。

StockDataクラスの修正

まずはマーケット情報をpandasのDataFrameに落とし込む部分を変更して、その日始値から終値まででどの程度変動したかを求めます。
下のような形で、始値から終値までの指標の変化率を求めます。

diff_data = closing_data / opening_data - 1

ソースコード全体はこちらにおいておきます。
https://github.com/kanoh-k/pred225/blob/d9945ee17d6c173df49118c29e36f0ef24455d13/stockdata.py

データを眺めて基準を決める

上記のファイルから取得したデータを眺めてみます。
日経平均の始値から終値の間の変動率を.describe()してみると、次のようになります。

import stockdata

s = stockdata.StockData()
open, close, diff, _ = s.get_daily_data()
df = diff["N225"]
df.describe()

count 1000.000000
mean -0.000270
std 0.010271
min -0.084600
25% -0.004846
50% 0.000000
75% 0.005277
max 0.057009
Name: N225, dtype: float64

分布も見てみるとこんな感じです。

df.hist(bins=100)

f:id:kanohk:20160818230632p:plain

では、実際にどの程度日経平均が動いたら「上がった」または「下がった」と分類するのがよいでしょうか。
試しに1%以上、上がったか下がった日数を数えてみると、こうなります。

threshold = 0.01
print("Up:", df.loc[df >= threshold].count())
print("Down:", df.loc[df <= -threshold].count())
print("Same:", df.loc[(-threshold < df) & (df < threshold)].count())

Up: 110
Down: 130
Same: 760

76%の日が1%未満の変化率に留まっています。いくつか値を試してみたのですが、基準を0.3%にしてみると、

Up: 341
Down: 325
Same: 334

となり、上がる、下がる、変わらないのクラス数がほぼ同数になります。しかし、日経平均が0.3%上がったり下がったりした程度で、利益が上げられるのでしょうか?

日経平均に連動したETFの値段はどのくらい変わるのか

今回対象とするETF

例えば、日経平均が「上がる」または「下がる」と予測した日は、それぞれ以下のETFを始値で買い終値で売る場合を考えてみます。

  • [上がる日]: NF日経レバレッジETF (1570)
  • [下がる日]: 日経ダブルインバース (1357)

どちらも2倍のレバレッジがかかっているETFです。日経平均が0.3%上下すると、この2つのETFの価格はどのように変動するのでしょうか。

そもそも1570や1357の仕組みって?

下記のページから1570の仕組みを見てみます。
ETFなら、野村のNEXT FUNDS|NEXT FUNDS 日経平均レバレッジ・インデックス連動型上場投信 《愛称》日経レバレッジ指数ETF(1570)

投資信託説明書の「ファンドが対象とする指数の値動きについて」という箇所に、以下のような記述があります。

日経平均レバレッジ・インデックスは、日々の騰落率が日経平均株価の騰落率の2倍として計算された指数です。したがって、以下の例に示すように、日経平均レバレッジ・インデックスの騰落率と日経平均株価の騰落率とは、2日以上離れた日との比較においては、一般に「2倍」とはなりませんので、十分ご留意ください。

http://nextfunds.jp/fund/pros_gen/Y1141570.pdf

具体例も織り交ぜて説明されていますが、その日のうちに買って売った場合は、日経平均の2倍の値動きをすると考えて問題なさそうです。

1357に関しても同様に下記のページから確認しましたが、その日のうちに買って売ってしまう場合は日経平均の-2倍の値動きと考えられそうです。
ETFなら、野村のNEXT FUNDS|NEXT FUNDS 日経平均ダブルインバース・インデックス連動型上場投信 《愛称》日経ダブルインバース指数ETF(1357)

的中するといくら儲かる?

「上がる」または「下がる」という予想が的中した場合、少なくとも投資金額の0.6%程度が儲かることになります。
例えば10万円分買って、600円程度です。実際にはここに手数料がかかります。僕が持っている証券口座だと、取引手数料と利益はこのようになります。(利益はそれ俺10、20、50、100万円分のETFを売買した場合の金額)

取引金額 税込手数料 利益
10万円 150円 300円
20万円 199円 802円
50万円 293円 2414円
100万円 525円 4950円

大きな額をつぎ込むほど手数料が割安になっていくのでその分利益も出るのですが、あまりに大金をつぎ込む勇気はないので表にするのはこの程度までで…。
にしても数十万円を動かして、予想を当てても、得られるリターンは数千円程度なんですね。。そしてここにさらに税金がかかるという。。

東証の営業日数は年間245日程度らしいので、そのうち始値と終値が0.3%以上動く日が2/3の163日程度。
的中率が100%で、売買する日は100万円ぎりぎりの単元を売買すると、計算上は利益が少なくとも163*4950=806850円で1年間で元手が1.8倍以上になる計算になります。

実際は100%なんて無理で、予想を外して損失が出る日もあるのでこんなにうまくいくはずはないのですが、実際に運用できる日が待ち遠しいです。

TensorFlowで日経平均が寄り付き後に上がるか下がるか予測する

前回までと同じ手法で予測

ようやく本題です。前回までのスクリプトの、訓練データとテストデータを生成する箇所を次のように変更して、終値が当日の始値より「上がる」「下がる」「変わらない」という3つのラベル付けをします。

threshold = 0.003
closing_data["N225_up"] = 0
closing_data.ix[diff_data["N225"] >= threshold, "N225_up"] = 1
closing_data["N225_down"] = 0
closing_data.ix[diff_data["N225"] <= -threshold, "N225_down"] = 1
closing_data["N225_same"] = 0
closing_data.ix[(-threshold < diff_data["N225"]) & (diff_data["N225"] < threshold), "N225_same"] = 1

前回と同じ、終値の情報だけを使った場合の結果はこちら。
f:id:kanohk:20160819005350p:plain

前回の記事と同様、いくつかの隠れ層の組み合わせで試してみましたが、良い場合でもテストデータでの精度が45%程度です。ランダムの場合33%程度になるので、ランダムよりちょっと当たる、程度ですね…。

始値と寄り付き後の変化率も使って予測

終値だけではあまりうまくいかなかったので、とりあえず何も考えずに始値、寄り付き後の変化率も入力として入れてみます。
今までは9個だった入力が、3倍の27個になります。

結果はこんな感じです。ほぼ変わらず。
f:id:kanohk:20160819012549p:plain

当日の始値

このまま進めていってもダメそうです。どんなデータを使えば、寄り付き後に上がるか下がるかを予測できるでしょうか。
ぱっと思いついたのは、当日の始値の情報を使ってしまうというアイデアです。当日の始値の情報が出た瞬間に予測を出して、それに基づいて買えばほぼ始値で買えるのではないでしょうか。
試しに前日の終値から当日の始値までの変動率を計算して、その値と寄り付き後の変動率の相関係数を調べてみたところ、-0.53程度になりました。
つまり、寄りで上げすぎ/下げすぎたから戻す、というような動きが過去1000日間によく見られた、ということですね。

始値をそのまま追加してもうまくいかなさそうなので、前日の終値との変動率を入力に追加したいと思います。
実際の実装はこんな形です。(変数名はとりあえずjumpなんて名付けてますけど、実際株の用語ではなんて言うんでしょう。。)

jump_data = opening_data / closing_data.shift() - 1

全体の実装はgithubを参考にしてもらえればと思います。

この情報を追加して再度挑戦してみた結果がこちら。
f:id:kanohk:20160822123356p:plain
線が3本ありますが、イテレーション終了時(右端)で見て数値が低い順に隠れ層なし、1層、2層という構造です。
隠れ層2層の時に、55.3%の精度です。

このグラフに含まれているもの以外にも、層数やノードの数を調整して試してみましたが、この50-25の隠れ層2層パターンが一番精度が高かったです。
実験用スクリプトもGitHubにあげておきます。
https://github.com/kanoh-k/pred225/blob/d9945ee17d6c173df49118c29e36f0ef24455d13/eval.py

(2016/08/31追記:プログラムのデータを作成する部分にバグがあり、この数値は正しくないものであることが判明しました。)
(2016/9/20追記:正しい数値での記事を投稿しました(クリックで記事へ移動)

まとめと次回予告

今回は、日経平均が寄り付いてから終値までに、0.3%以上「上がる」か「下がる」か、もしくは「ほぼ変わらない」かの3つのどのパターンになるかを予測するためのモデルをTensorFlowで構築しました。
過去800日分のデータで学習させた結果、隠れ層が2層(50-25)の場合に精度が55.3%となることがわかりました。

直感的にはこの程度の精度では運用は厳しそうに思えますが、実際のところはどうなのか、次回記事でより詳しい分析とバックテストなどを実装して評価してみたいと思います。

次回記事:
モデルの評価とバックテスト ~株価予測(6)~ - 今日も窓辺でプログラム