人工知能

株が上がるかどうかをNNでやってみた

ニューラルネットで株価予測

以前、参加したセミナーで株価の予測を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のプログラムをほぼそのままです。

kabu1.py
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や各証券会社のレーティング、決算情報などが外部パラメータとして考慮する必要があります。
次回は・・・気が向いたら・・別のパターンで検証します。