ぷそさんのプログラミング研究所

【ソースコードあり】ディープラーニングAIで株価予測してみよう|Python

ぷそさん

株はやったことないけど、機械学習はかじってる…

大儲けできるのでは

プログラミング歴5年、株運用歴0ヶ月のぷそです。

機械学習を実際に運用してみたいと言うことで、株価の予測をしてみたいと思います。

目次

株価予測の概要

概要は以下の画像の通りです。

つまり、以下のような流れで運用していきます。

運用の流れ
  • 30日後に株価が上昇するか判断
  • 上昇する予想なら100株買う
  • 30日後に100株売る

ディープラーニングモデル作成

Pythonでモデルを作成していきます!

使う機械学習のモデルはLightGBMと呼ばれるものです。

他の手法での予測は以下の記事をご覧ください!

ランダムフォレストでの株価予測

あわせて読みたい
【ソースコードあり】Python|株価予測で学ぶランダムフォレストの使い方 この記事でわかること ランダムフォレストの実装方法(ソースコードつき) ランダムフォレストでの株価予測の方法 【ランダムフォレストによる株価予測の概要】 予測は...

ライブラリのインポート

まずはライブラリをインポートします。

ダウンロードしていない場合はpipなどでインストールしてください。

import lightgbm as lgb
import pandas as pd
import numpy as np
from pandas_datareader import data

説明変数の取得

機械学習には「説明変数」と「目的変数」と呼ばれるものがあります。

「説明変数」は、予想するために使うデータのこと

「目的変数」は、予想する値のことです。

まずは、説明変数として株価のいくつかの指標をダウンロードしてみたいと思います。

#説明変数の取得
fred_lst = ['NIKKEI225','SP500','NASDAQCOM']
df_fred = data.DataReader(fred_lst,'fred','2014-01-01', '2022-08-31').asfreq("D")
df_fred = df_fred.fillna(method='ffill')

とりあえず下の指標をダウンロードしています。

  • NASDAQ総合指数
  • S&P 500
  • 日経平均株価

このままでは値が使いにくいので、どれだけ上昇しているかを示す移動平均を求めます。

ここでは、1日〜30日の間の移動平均との違いを算出しています。

# 移動平均を算出する
fred_cols = df_fred.columns

for stock_name in df_fred.columns:
    for i in [1,5,10,15,20,25,30]:
        df_fred[stock_name + "_"+ str(i) + "days_diverge"] =\
        (df_fred[stock_name].rolling(i).mean() - df_fred[stock_name]) / df_fred[stock_name].rolling(i).mean()

# 各指数の列を削除する
df_fred = df_fred.drop(columns=fred_cols)

予測したい銘柄情報の取得

次に、予測する銘柄情報を取得します。

# CODEに予測したい企業の銘柄コードを入れる
CODE = 1111
CODE_name = str(CODE) + ".T"
df_target = data.DataReader(CODE_name,'yahoo', '2014-01-01', '2022-08-31')
df_target = pd.DataFrame(df_target).asfreq("D", method="ffill")

一行目のCODE=予測したい企業の銘柄コードを入れてください。

また、説明変数を増やすために以下の指標を追加します。

  • 始値と終値の差
  • 各指標(始値・終値・高値・安値)の変化率変化量
# 説明変数を作成
df_target['Body'] = df_target['Open'] - df_target['Close']
for ii in range(5):
    df_target["High_diff_per"+str(ii+1)] = df_target["High"].diff(ii+1) / df_target["High"]
    df_target["Low_diff_per"+str(ii+1)] = df_target["Low"].diff(ii+1) / df_target["Low"]
    df_target["Open_diff_per"+str(ii+1)] = df_target["Open"].diff(ii+1) / df_target["Open"]
    df_target["Close_diff_per"+str(ii+1)] = df_target["Adj Close"].diff(ii+1) / df_target["Adj Close"]
    
    df_target["High_diff"+str(ii+1)] = df_target["High"].diff(ii+1)
    df_target["Low_diff"+str(ii+1)] = df_target["Low"].diff(ii+1)
    df_target["Open_diff"+str(ii+1)] = df_target["Open"].diff(ii+1)
    df_target["Close_diff"+str(ii+1)] = df_target["Adj Close"].diff(ii+1)

目的変数の作成

最初にも説明した通り、「30日後に株価が上昇する」ことを予測するので、その変数を作ります。

予測の方法ですが、とりあえず5%上昇する時に上昇したと判断します。

#目的変数を決定
# 30日後に1.05倍になる(5%上昇)
day = 30
MAX_th = 1.05 

# 上がるときflag=1、上がらないときflag=0
df_target['MEAN'] = df_target["Adj Close"].rolling(day).mean().shift(-day)
df_target['MEAN_per'] = df_target['MEAN'] / df_target["Adj Close"]
df_target['flag'] = np.where(df_target['MEAN_per'] > 1.00, 1, 0)

# 未来指標は削除
df_target = df_target.drop(columns=['MEAN','MEAN_per'])

データの整理

まずは、これまでに作成したデータを結合します。

df = pd.merge(df_target, df_fred, how='left', left_index=True, right_index=True)
df = df.fillna(method='ffill')
df_ = df["2016-01-01":]

次に、モデルを学習データテストデータに分たいと思います。

今回は、2018年までを学習データ、2019年以降をテストデータしたいと思います。

df_train = df_[:"2018"]
df_test = df_["2019":]

モデルに入れるためにデータの整理をします。

X_train = df_train.drop(["flag"], axis=1)
X_test = df_test.drop(["flag"], axis=1)

y_train = df_train["flag"]
y_test = df_test["flag"]

#モデルに入れるのはnumpyである必要がある
X_train = np.array(X_train, dtype = 'float64')
X_test = np.array(X_test, dtype = 'float64')

ディープラーニングモデル作成

ここまででデータは完成しているので、いよいよ学習させます。

#LightGBM
params = {
            'objective': 'binary',
            'metric': 'auc',
            'boosting_type': 'gbdt',
        }

lgb_train = lgb.Dataset(X_train, y_train)
lgb.test  = lgb.Dataset(X_test, y_test)
gbm = lgb.train(params, lgb_train)

このように、たった数行で学習させることができます。

結果の確認

早速、結果を見てみたいと思います。

# 予測値と実値との比較
df_result = pd.DataFrame()
df_result["Act"] = y_test
df_result["Pred"] = gbm.predict(X_test)

結果を見るとこのようになっていると思います。

print(df_result)

            Act      Pred
Date                     
2019-01-01    1  0.997103
2019-01-02    1  0.997747
2019-01-03    1  0.997264
2019-01-04    1  0.006099
2019-01-05    1  0.006974
...         ...       ...
2022-08-27    0  0.000722
2022-08-28    0  0.000603
2022-08-29    0  0.001459
2022-08-30    0  0.001987
2022-08-31    0  0.001491

このように結果は確率表記されているので、四捨五入してわかりやすくします。

df_result['Pred_binary'] = np.round(df_result['Pred'])

print(df_result)

            Act      Pred  Pred_binary
Date                                  
2019-01-01    1  0.997103          1.0
2019-01-02    1  0.997747          1.0
2019-01-03    1  0.997264          1.0
2019-01-04    1  0.006099          0.0
2019-01-05    1  0.006974          0.0
...         ...       ...          ...
2022-08-27    0  0.000722          0.0
2022-08-28    0  0.000603          0.0
2022-08-29    0  0.001459          0.0
2022-08-30    0  0.001987          0.0
2022-08-31    0  0.001491          0.0

これを混合行列と呼ばれる表で表すとこうなります。

予想した値
10
実際の値1145655
062477

注目するのは、「1」と予想したときの結果です。

「1」と予想した時、実際に1だったのは145回実際は0だったのが62回となっています。

つまり、62回の購入時には株価が5%以上上がっていないということになります。

適合率という指標では、70%となります。

これだけでは分かりにくいので、この結果を株運用シミュレーションでみていきたいと思います。

運用シミュレーション

株購入の条件

株を購入する条件は冒頭でも説明した通りです。

運用の流れ
  • 30日後に株価が上昇するか判断
  • 上昇する予想なら100株買う
  • 30日後に100株売る

また、運用するための条件は以下のように設定しています。

運用の方法
  • 元金は100万円
  • 購入するタイミングで100株買えない場合はスルー
  • 購入するのは平日のみ

シミュレーション結果

まずは、運用シミュレーションのキャッシュフローを見たいと思います。

2つの企業でシミュレーションしています!

3年分のキャッシュフロー①

3年分のキャッシュフロー1

3年分のキャッシュフロー②

3年分のキャッシュフロー2

グラフの見方としては、資金が減っているのは株を購入しているタイミングで、その30日後に売却しているので資金が増えています。

2019年から2022年にかけて右肩上がりに上昇していることがわかると思います。

結果としては、上の画像では2022年8月には140万円ほどになっているため40万円の収益になります。

下の画像でも僅かに利益が出ていることがわかると思います!

そのため、そこそこの精度で予測できていることがわかります!

コード全文

今回使用したコードはこちらです。

import lightgbm as lgb
import pandas as pd
import numpy as np
from pandas_datareader import data

#説明変数の取得
fred_lst = ['NIKKEI225','SP500','NASDAQCOM']
df_fred = data.DataReader(fred_lst,'fred','2014-01-01', '2022-08-31').asfreq("D")
df_fred = df_fred.fillna(method='ffill')
fred_cols = df_fred.columns

# 各指数の移動平均との乖離率を算出する
for stock_name in df_fred.columns:
    for i in [1,5,10,15,20,25,30]:
        df_fred[stock_name + "_"+ str(i) + "days_diverge"] =\
        (df_fred[stock_name].rolling(i).mean() - df_fred[stock_name]) / df_fred[stock_name].rolling(i).mean()

# 各指数の列を削除する
df_fred = df_fred.drop(columns=fred_cols)

# 株価の取得
CODE = "自分で入力"
CODE_name = str(CODE) + ".T"
df_target = data.DataReader(CODE_name,'yahoo', '2014-01-01', '2022-08-31')
df_target = pd.DataFrame(df_target).asfreq("D", method="ffill")

# 説明変数を作成
df_target['Body'] = df_target['Open'] - df_target['Close']
for ii in range(5):
    df_target["High_diff_per"+str(ii+1)] = df_target["High"].diff(ii+1) / df_target["High"]
    df_target["Low_diff_per"+str(ii+1)] = df_target["Low"].diff(ii+1) / df_target["Low"]
    df_target["Open_diff_per"+str(ii+1)] = df_target["Open"].diff(ii+1) / df_target["Open"]
    df_target["Close_diff_per"+str(ii+1)] = df_target["Adj Close"].diff(ii+1) / df_target["Adj Close"]
    
    df_target["High_diff"+str(ii+1)] = df_target["High"].diff(ii+1)
    df_target["Low_diff"+str(ii+1)] = df_target["Low"].diff(ii+1)
    df_target["Open_diff"+str(ii+1)] = df_target["Open"].diff(ii+1)
    df_target["Close_diff"+str(ii+1)] = df_target["Adj Close"].diff(ii+1)

#目的指標を決定
# 30日後に1.05倍になる(5%上昇)
day = 30
MAX_th = 1.05 

# 上がるときflag=1、上がらないときflag=0
df_target['MEAN'] = df_target["Adj Close"].rolling(day).mean().shift(-day)
df_target['MEAN_per'] = df_target['MEAN'] / df_target["Adj Close"]
df_target['flag'] = np.where(df_target['MEAN_per'] > 1.00, 1, 0)

# 未来指標は削除
df_target = df_target.drop(columns=['MEAN','MEAN_per'])

df = pd.merge(df_target, df_fred, how='left', left_index=True, right_index=True)
df = df.fillna(method='ffill')
df_ = df["2016-01-01":]
df_train = df_[:"2018"]
df_test = df_["2019":]

X_train = df_train.drop(["flag"], axis=1)
X_test = df_test.drop(["flag"], axis=1)
COLS = X_train.columns

y_train = df_train["flag"]
y_test = df_test["flag"]

#モデルに入れるのはnumpyである必要がある
X_train = np.array(X_train, dtype = 'float64')
X_test = np.array(X_test, dtype = 'float64')

#LightGBM
params = {
            'objective': 'binary',
            'metric': 'auc',
            'boosting_type': 'gbdt',
        }

lgb_train = lgb.Dataset(X_train, y_train)
lgb.test  = lgb.Dataset(X_test, y_test)
gbm = lgb.train(params, lgb_train)

# 予測値と実測値の取得
df_result = pd.DataFrame()
df_result["Act"] = y_test
df_result["Pred"] = gbm.predict(X_test)
df_result['Pred_binary'] = np.round(df_result['Pred'])
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

このブログでは,PythonやLaTeXの使い方などを紹介しています!
仕事でも趣味でもプログラミングをしています。
ブログは2022年8月にスタートしました。
【経歴】東京大学大学院修了→大手IT企業勤務

コメント

コメントする

目次