LoginSignup
200
287

More than 5 years have passed since last update.

株価予測WEBアプリを作ってみた(Python,Django,Heroku)

Last updated at Posted at 2018-08-11

はじめに

PythonでLSTMモデルを作成し、株価予測アルゴリズムを開発しました。
それをDjangoを用いてWEBアプリ化し、Herokuにデプロイしました。

株価予測WEBアプリ

色々と省きますが、WEBアプリができるまでを順に説明したいと思います。

開発環境は以下です。

  • Windows8.1 Pro
  • Python 3.6.5
  • Django 2.0.7

本記事の構成は以下です。

No. 項目
1 PythonによるLSTMモデルの構築と株価予測
2   DjangoによるWebアプリケーションの作成
3 HerokuへWebアプリケーションをデプロイ

1.PythonによるLSTMモデルの構築と株価予測

ここでは、Pythonを用いて、
- 株価データのスクレイピング
- LSTMモデルの定義
- LSTMモデルの学習
- 株価予測
を行っています。

stock_predict_nikkei.py
#def LSTM(NAME,epoch,s_date,e_date,batch):
from . import brand_list
from . import read_nikkei

def LSTM(input):
        ############
        #---LSTM---#
        ############

        ############
        ###1.importing Libraies and getting stock data
        import pandas as pd

        import datetime as dt
        import numpy as np
        import pandas_datareader.data as web
        import matplotlib.pyplot as plt
        import chainer

        #start = dt.date(2011,1,1)
        #end = dt.date(2018,7,1)
        #start = s_date
        #end = e_date
        start = input[2]
        end = input[3]
        print(start)
        print(end)

        #AMZN:Amazon、AAPL:Apple、GOOGL:Google、ACN:アクセンチュア、
        #AFL:アフラック、DIS:ディズニー、FB:Facebook、NVDA:NVIDIA
        #df_org= web.DataReader('NVDA',"morningstar",start,end)
        #df_org= web.DataReader(NAME,"morningstar",start,end)
        #df_org= web.DataReader(input[0],"morningstar",start,end)
        df_org = read_nikkei.get_jstock(input[0],start=pd.Timestamp(start),end=pd.Timestamp(end))
        df_org = df_org.drop('Adj Close',axis=1)


        #翌日のOpen値入力
        df_add = df_org['Open'].shift(-1)
        #最終日は当日のOpen値入力(これしないとNANになる)
        df_add[len(df_org)-1] = df_add[len(df_org)-2] 

        #翌日のOpen値入力
        df_org = pd.concat([df_org,df_add], axis=1)

        #カラム更新
        df_org.columns = ['Open', 'High','Low', 'Close', 'Volume','Open-1']

        ############
        #2.setting data

        from sklearn.preprocessing import MinMaxScaler
        x_scaler = MinMaxScaler(feature_range=(0, 1))
        x2_scaler = MinMaxScaler(feature_range=(0, 1))
        x3_scaler = MinMaxScaler(feature_range=(0, 1))
        t_scaler = MinMaxScaler(feature_range=(0, 1))


        df_x = x_scaler.fit_transform(np.array(df_org['Open-1']).reshape(-1,1)).astype(np.float32)
        df_x2 = x2_scaler.fit_transform(np.array(df_org['Close']).reshape(-1,1)).astype(np.float32)
        df_x3 = x3_scaler.fit_transform(np.array(df_org['High']).reshape(-1,1)).astype(np.float32)
        df_t = t_scaler.fit_transform(np.array(df_org['Close']).reshape(-1,1)).astype(np.float32)

        #訓練データと教師データへの分割

        x,x2,x3,t = [],[],[],[]

        N = len(df_org)
        M = 30
        for n in range(M,N):
            _x = df_x[n-M:n]
            _x2 = df_x2[n-M:n]
            _x3 = df_x3[n-M:n]
            _t = df_t[n]
            x.append(_x)
            x2.append(_x2)
            x3.append(_x3)
            t.append(_t)

        #trainデータの割合
        ratio_train_test = input[5]
        #testデータの個数
        n_test = 1
        #testデータ数を個数で決めるか割合で決めるかのSW
        SW = -1

        #例:x[1]は初日からM日分の(標準化された)Closeデータ、t[1]はM+1日目のCloseデータ
        x = np.array(x, dtype = np.float32)
        x2 = np.array(x2, dtype = np.float32)
        x3 = np.array(x3, dtype = np.float32)
        t = np.array(t, dtype = np.float32).reshape(len(t),1)

        #x = np.c_[x,x2]

        if SW == 1:
            n_train = int(len(x) * ratio_train_test)
        elif SW == -1:
            n_train = len(x)-n_test
        else:
            pass

        dataset = list(zip(x, t))
        train, test = chainer.datasets.split_dataset(dataset,n_train)

        ############
        #3.making models
        # chainerと必要なパッケージをインポート
        import chainer.links as L
        import chainer.functions as F
        from chainer import Chain, Variable, datasets, optimizers
        from chainer import report, training
        from chainer.training import extensions
        import chainer.cuda

        # ニューラルネットワークモデルを作成
        class RNN(Chain):
            def __init__(self, n_units, n_output):
                super().__init__()
                with self.init_scope():
                    self.l1 = L.LSTM(None, n_units)
                    self.l2 = L.Linear(None, n_output)

            def reset_state(self):
                self.l1.reset_state()


            def __call__(self, x, t):
                y = self.predict(x)
                loss = F.mean_squared_error(y, t)
                report({'loss':loss},self)
                return loss

            def predict(self, x):
                #if train:
                    #h1 = F.dropout(self.l1(x),ratio = 0.5)
                #else:
                h1 = self.l1(x)
                return self.l2(h1)

        ## LSTMUpdaterを作る。
        class LSTMUpdater(training.StandardUpdater):
            def __init__(self, data_iter, optimizer, device=None):
                super(LSTMUpdater,self).__init__(data_iter, optimizer, device=None)
                self.device = device

            def update_core(self):
                data_iter = self.get_iterator("main")
                optimizer = self.get_optimizer("main")

                batch = data_iter.__next__()
                x_batch, t_batch = chainer.dataset.concat_examples(batch, self.device)

                optimizer.target.reset_state()           #追加
                optimizer.target.cleargrads()
                loss = optimizer.target(x_batch, t_batch)
                loss.backward()
                loss.unchain_backward()                  #追記
                optimizer.update() 

        ############
        #4.setting hyperparameters

        # 乱数のシードを固定 (再現性の確保)
        np.random.seed(1)

        # モデルの宣言
        model = RNN(30, 1)

        # GPU対応
        #chainer.cuda.get_device(0).use()
        #model.to_gpu()                 

        # Optimizer
        optimizer = optimizers.Adam()
        optimizer.setup(model)

        # Iterator
        batchsize = input[4] #ミニバッチのサイズ
        train_iter = chainer.iterators.SerialIterator(train, batchsize)
        test_iter = chainer.iterators.SerialIterator(test, batchsize, repeat=False, shuffle=False)

        # Updater <- LSTM用にカスタマイズ
        updater = LSTMUpdater(train_iter, optimizer,device = -1)

        # Trainerとそのextensions
        #epoch = 100
        epoch = input[1]
        trainer = training.Trainer(updater, (epoch, 'epoch'), out='result')

        # 評価データで評価
        trainer.extend(extensions.Evaluator(test_iter, model,device = -1))

        # 学習結果の途中を表示する
        trainer.extend(extensions.LogReport(trigger=(1, 'epoch')))

        # 1エポックごとに、trainデータに対するlossと、testデータに対するlossを出力させる
        trainer.extend(extensions.PrintReport(['epoch', 'main/loss', 'validation/main/loss', 'elapsed_time']), trigger=(1, 'epoch'))


        ############
        #5.training

        trainer.run()


        ############
        #6.predict stock price


        x_,x2_,x3_ = [],[],[]

        _x = df_x[N-M:N]
        _x2 = df_x2[N-M:N]
        _x3 = df_x3[N-M:N]

        x_.append(_x)
        x2_.append(_x2)
        x3_.append(_x3)

        #例:x[1]は初日からM日分の(標準化された)Closeデータ、t[1]はM+1日目のCloseデータ
        x_ = np.array(x_, dtype = np.float32)
        x2_ = np.array(x2_, dtype = np.float32)
        x3_ = np.array(x3_, dtype = np.float32)

        #x_ = np.c_[x_,x2_]

        if SW == 1:
            n_train = int(len(x) * ratio_train_test)
        elif SW == -1:
            n_train = len(x)-n_test
        else:
            pass

        train_x, test_x = x[:n_train], x[n_train:]
        train_t, test_t = t[:n_train], t[n_train:]

        train_t = t_scaler.inverse_transform(train_t)

        #図表示
        plt.clf()
        plt.plot(train_t, label = 'actual', color='blue')  # 実測値
        plt.legend()

        plt.savefig('C:\\Users\\Owner\\Desktop\\Django\\mySite\\static\\fig.png')

        # 検証データ
        model.reset_state()
        test_y = model.predict(Variable(x_)).data

        test_y = t_scaler.inverse_transform(test_y)


        test_t = t_scaler.inverse_transform(test_t)


        return test_y[0][0],test_t[0][0]

2.DjangoによるWebアプリケーションの作成

編集中

3.HerokuへWebアプリケーションをデプロイ

編集中

詳細は、今後書いていきます!

質問・ご指摘あればぜひ。

また、株価予測アプリは情報提供を目的としており、株価予測アプリに従って投資した結果に関しましては一切責任をもちません。利用に関しては自己責任でお願いします。

200
287
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
200
287