ニューラルネットで株価予測
以前、参加したセミナーで株価の予測をNNでできないんですか?と講師に質問していた方がいた。
なるほど・・・。確かにうまくやればすごく簡単にお金儲けができるかもしれないが・・・。
その時、講師の方は「無理でしょ~。」株はもっと複雑です。
と話をしていたので、だよなぁ。と。
そんなに簡単にできるのならば、簡単に大金持ちになれます。
先に前もって言っておくと、これを読んでも株価予測はできませんので注意です!(笑)
仕様の確定
株価の予測のため、基本的に前日に明日の株の上下がわかればいいとします。
(つまり、予測したい日の前日にその日の終値よりも高いか低いかを識別できることを目標)
ということで、まずは簡単なモデルを用いて考えてみます。
株価にはテクニカル、ファンダメンタルなど様々な分析ができますが、ここではとりあえずおいて置いて・・・。
単純に、前日の始値、高値、安値、終値をインプットに使用するとどうなるか?
という単純なモデルにします。
学習データの準備
まず、学習に用いるデータを準備します。
ちょうど手元にトヨタの株価のデータがちょうど約1年分ありましたのでそれを利用します。
日付 | 前日の始値 | 前日の高値 | 前日の安値 | 前日の終値 | プラスor マイナス(1は+、0は-) |
---|---|---|---|---|---|
2017/11/02 | 7020 | 7068 | 6997 | 7038 | 1 |
2017/11/01 | 7030 | 7030 | 6975 | 6990 | 1 |
2017/10/30 | 7050 | 7079 | 7045 | 7077 | 0 |
とこんな感じのデータを作ります。
見方は11月2日の結果はプラス(前日の1日の終値よりも2日のほうが高かった)
という感じで見ます。
プログラムの準備
次に肝心のプログラムですが、様々なものがありますがまずは簡単な3層を利用します。
本来であれば、これは時系列データの回帰で求めてもいいのですが・・・
今回は問題をわかりやすくするために、プラス、マイナスの2分類の分類問題とします。
また、時系列データなので本来はRNNやLSTMなどを使ってもいいのですが、それはまた後日。
今回はこんなプログラムにしました。
Chainerのirisのプログラムをほぼそのままです。
import chainer
import chainer.functions as F
import chainer.links as L
from chainer import training, datasets
from chainer.training import extensions
import numpy as np
def load_data():
X=[]
Y=[]
with open('/testdata1.csv','r') as f:
for line in f:
row=[]
line = line.strip().replace('"','')
l = line.split(",")
row.append(int(l[1]))
row.append(int(l[2]))
row.append(int(l[3]))
row.append(int(l[4]))
X.append(row)
Y.append(l[5])
return X,Y
def main():
X,Y=load_data()
X = np.array(X, dtype=np.float32)
Y = np.array(Y, dtype=np.int32)
X = X.astype(np.float32)
Y = Y.flatten().astype(np.int32)
#print(X)
#print(Y)
train ,test= datasets.split_dataset_random(chainer.datasets.TupleDataset(X,Y),100)
train_iter = chainer.iterators.SerialIterator(train, 10)
test_iter = chainer.iterators.SerialIterator(test, 1,repeat=False, shuffle=False)
class KabuModel(chainer.Chain):
def __init__(self):
super(KabuModel,self).__init__(
l1 = L.Linear(4,1000),
l2 = L.Linear(1000,1000),
l3 = L.Linear(1000,2))
def __call__(self,x):
h = F.relu(self.l1(x))
h = F.relu(self.l2(h))
return self.l3(h)
model = L.Classifier(KabuModel())
optimizer = chainer.optimizers.Adam()
optimizer.setup(model)
updater = training.StandardUpdater(train_iter, optimizer, device=-1)
trainer = training.Trainer(updater, (30, 'epoch'), out="result")
trainer.extend(extensions.Evaluator(test_iter, model, device=-1))
trainer.extend(extensions.LogReport())
trainer.extend(extensions.PrintReport( ['epoch', 'main/loss', 'validation/main/loss', 'main/accuracy', 'validation/main/accuracy']))
trainer.extend(extensions.ProgressBar())
trainer.run()
if __name__ == '__main__':
main()
細かい説明は省きますが、Xをインプットデータ、yをアウトプットデータとして、学習をします。
結果
結果は以下のようになりました。
まあ、見てわかるのは順調に学習はできていますが、精度があまり高くない点です。
30回やっていますが、もっと多く2000回やったときの結果も載せます。
epoch main/loss validation/main/loss main/accuracy validation/main/accuracy
1 11323.4 8326.75 0.48 0.510101
2 6413.91 2665.92 0.42 0.510101
3 2709.79 466.734 0.5 0.489899
4 1938.42 2758.51 0.5 0.489899
5 1629.61 1354.55 0.52 0.489899
6 739.961 74.1983 0.54 0.510101
7 254.996 334.927 0.58 0.510101
8 568.101 353.19 0.46 0.489899
9 602.133 724.024 0.52 0.510101
10 680.98 60.0471 0.38 0.484848
total [################..................................] 33.33%
this epoch [..................................................] 0.00%
100 iter, 10 epoch / 30 epochs
inf iters/sec. Estimated time to finish: 0:00:00.
11 301.522 166.854 0.52 0.489899
12 231.172 502.074 0.52 0.489899
13 864.398 48.4156 0.42 0.510101
14 235.177 8.35184 0.52 0.474747
15 417.425 346.087 0.43 0.489899
16 261.545 117.069 0.56 0.510101
17 431.089 300.204 0.5 0.489899
18 310.728 104.957 0.54 0.510101
19 230.926 461.814 0.46 0.489899
20 301.013 606.533 0.51 0.510101
total [#################################.................] 66.67%
this epoch [..................................................] 0.00%
200 iter, 20 epoch / 30 epochs
22.701 iters/sec. Estimated time to finish: 0:00:04.405044.
21 248.632 20.7976 0.54 0.489899
22 523.341 582.338 0.44 0.510101
23 418.881 270.688 0.5 0.510101
24 146.064 33.7938 0.48 0.484848
25 266.867 23.2631 0.46 0.510101
26 479.64 270.411 0.4 0.489899
27 260.155 86.4615 0.52 0.510101
28 328.31 509.05 0.46 0.510101
29 455.381 638.868 0.46 0.510101
30 213.381 297.25 0.54 0.489899
total [##################################################] 100.00%
this epoch [..................................................] 0.00%
300 iter, 30 epoch / 30 epochs
22.994 iters/sec. Estimated time to finish: 0:00:00.
1993 0.692367 0.694012 0.52 0.510101
1994 0.692358 0.694009 0.52 0.510101
1995 0.692391 0.69402 0.52 0.510101
1996 0.692366 0.694009 0.52 0.510101
1997 0.692523 0.693978 0.52 0.510101
1998 0.692399 0.694009 0.52 0.510101
1999 0.692381 0.694001 0.52 0.510101
2000 0.692375 0.694008 0.52 0.510101
total [##################################################] 100.00%
this epoch [..................................................] 0.00%
20000 iter, 2000 epoch / 2000 epochs
17.557 iters/sec. Estimated time to finish: 0:00:00.
だいたい50%程度の精度しかありません。
ということは普通の確率と一緒です。
ということで、まずはこれでは株価の予測はできません。
では、精度を上げるにはどうしたらいいか?
- インプットデータ
- アルゴリズム
この2つを変える必要があります。
まず、インプットデータに関しては、見てわかる通り簡単なものしかしれていません。
株価というものは複雑なため、移動平均、ボリンジャーバンド、ピボットなど様々な数値が存在します。
その中のデータというのは時系列の要素を多く含んでいます。
それらのデータを活用する必要があります。
次に使用アルゴリズムですが、今回はデータとしては連続性を扱っていません。
株価とは時系列の要素が強いため、使用するアルゴリズムそれらを意図してあるRNNやLSTMを用いるべきです。
また株の分析にはこられのほかに大事な群集心理というものが存在しています。
具体的には何かの情報を得て、売買するということが多く存在しているからです。
twitterや各証券会社のレーティング、決算情報などが外部パラメータとして考慮する必要があります。
次回は・・・気が向いたら・・別のパターンで検証します。