AIで3日後の株価を予測してみる

はじめに

今回はAIの手法のひとつである機械学習LSTMを使用して、3日後に株価がどれぐらい変化するか予想します。実装したサイトは以下のURLで公開しています。

AIによる株価予想 https://www.mhr-y.com/jp/ai-stock/

機械学習の予備知識なく作成しましたので、認識違いがある可能性があります。予めご了承ください。改善のアドバイスなどありましたらコメントください。

Pythonではじめる機械学習 ―scikit-learnで学ぶ特徴量エンジニアリングと機械学習の基礎

Pythonではじめる機械学習 ―scikit-learnで学ぶ特徴量エンジニアリングと機械学習の基礎

Andreas C. Muller, Sarah Guido
3,627円(09/19 02:26時点)
Amazonの情報を掲載しています

予想アルゴリズム

今回の予想アルゴリズムを示します。

基本的な考え方は以下の通りです。

最初に、過去の株価を取得しテクニカル指標を算出します。

次に、テクニカル指標の値と株価の上昇・下降の関係を学習します。

最後に、直近10日の値動きを入力して、から3日後の株価がどれぐらいの確立で変更するのかを予想します。

入力データを準備する

まず、入力されたティッカーシンボルの過去180日分の日足データを pandas_datareader を使用して yahoo.com から取得します。

# 引数で予想対象のティッカーシンボルを指定する
code = argv[1]
today = date.today()
ago = today - relativedelta(days=180)

#データの取得
 dataはpandas.DataFrame型
data = pdr.get_data_yahoo(code, start=ago, end=today, progress=False)

次に、取得した株価データのうちClose (終値)に対して以下のテクニカル指標を計算します。

  • 単純移動平均(SMA):7、14、24
  • 移動平均乖離率(MAD):7、14、24
  • MACD:短期EMA12、長期EMA26、MACDシグナル9
  • RSI:14
  • ボリンジャーバンド:20
data = sma(data,7)
data = sma(data,14)
data = sma(data,24)
data = macd(data)
data = rsi(data,14)
data = sigma(data,20)
def sma(df, window):
   df['SMA' +str(window)] = df['Close'].rolling(window=window).mean()
   df['Moving_average_divergence' +str(window)] = 100.0 *(df['Close'] -df['SMA' +str(window)]) /df['SMA' +str(window)]
   return df

def macd(df):
   FastEMA_period = 12
   SlowEMA_period = 26
   SignalSMA_period = 9
   df['MACD'] = df['Close'].ewm(span=FastEMA_period).mean() -df['Close'].ewm(span=SlowEMA_period).mean()
   df['Signal'] = df['MACD'].rolling(SignalSMA_period).mean()
   return df

def rsi(df, window):
   df_diff = df['Close'].diff(1)
   df_up, df_down = df_diff.copy(), df_diff.copy()
   df_up[df_up <0] = 0
   df_down[df_down >0] = 0
   df_down = df_down *-1
   df_up_sma = df_up.rolling(window=window,center=False).mean()
   df_down_sma = df_down.rolling(window=window,center=False).mean()
   df['RSI'+str(window)] = 100.0 *(df_up_sma /(df_up_sma +df_down_sma))
   return df

def sigma(df, window):
   df_mean = df['Close'].rolling(window=window).mean()
   df_std = df['Close'].rolling(window=window).std()
   df['sigma' +str(window)] = (df['Close'] -df_mean) /df_std
   return df

続いて、テクニカル指標の各値のスケールがまちまちなので正規化する。正規化はすべての要素から平均値を引き、標準偏差で割ることで求められる。

# 標準化する数値を指定
use_cols = ['SMA7', 'Moving_average_divergence7',
            'SMA14', 'Moving_average_divergence14',
            'SMA24', 'Moving_average_divergence24',
            'MACD', 'RSI14', 'sigma20']

# 指定した数値を正規化
n_df = mean_norm(data[use_cols])
# 正規化
def mean_norm(df_input):
   return df_input.apply(lambda x: (x -x.mean()) /x.std(), axis=0)
解釈可能なAI 機械学習モデルの解釈手法を実践的に理解する (Compass Booksシリーズ)

解釈可能なAI 機械学習モデルの解釈手法を実践的に理解する (Compass Booksシリーズ)

Ajay Thampi
4,883円(09/18 11:23時点)
発売日: 2023/09/19
Amazonの情報を掲載しています

訓練データと学習データを作成する

次のステップとして、作成したテクニカル指標の値からn_prev日分ずつデータを抜き出します。

抜き出したデータを学習用データとして、そのn_prev日分のデータの最後の終値から3日後の終値がどれくらい上昇、下落したのかを正解データとします。

# docx にn_prev日分の学習用データ
# docy に実際に株価がどれくらい上昇、下落したのかの正解データ
docx, docy = [],[]   
n_prev = 10 # 学習対象の日数
n_df = n_df[25:] # 標準化したpd.DataFrameの最初の25行をスキップする。これは上で24日単純移動平均などのデータを入れてるが、計算の都合上最初の24日分にはデータなしとなっているので、最初の25日を削って全部のデータがきちんとそろっている状態にする

# ループ処理をn_dfの行マイナス13回分繰り返す
for i in range(len(n_df) -13): 
       docx.append(n_df.iloc[i:i+n_prev][use_cols].values)
       docy.append(100.0 *(data.iloc[i+13]['Close'] -data.iloc[i+10]['Close']) /data.iloc[i+10]['Close'])

arrayX = np.array(docx) # 各テクニカル指標の値
arrayY = np.array(docy) # 3日の株価の変化率

つぎに株価の変化率をカテゴリします。3日後の株価が-2.5%以上下落している場合は-3、-0.5%下落から0.5%上昇の範囲であれば0といった具合に7つに分類します。

さらにワンホットエンコーダーにかけることで、7つのカテゴリを7列の行列に変換します。

# 変化率を7つのカテゴリに分ける
arrayY[arrayY <= -2.5] = -3
arrayY[(arrayY > -2.5) & (arrayY <= -1.5)] = -2
arrayY[(arrayY > -1.5) & (arrayY <= -0.5)] = -1
arrayY[(arrayY > -0.5) & (arrayY < 0.5)] = 0
arrayY[(arrayY >= 0.5) & (arrayY < 1.5)] = 1
arrayY[(arrayY >= 1.5) & (arrayY < 2.5)] = 2
arrayY[arrayY >= 2.5] = 3

# 7つのカテゴリーに分けた数字をワンホットエンコーダーにかける
enc = sp.OneHotEncoder(sparse_output=False)
arrayY = enc.fit_transform(arrayY.reshape(-1,1))

作ったデータの内、90%を学習用データに、残りの10%をテストデータにします。

ntrn = round(len(arrayX) *(1 -0.1)) # 90%が学習用、残り10%がテストデータ
ntrn = int(ntrn)

# X_trainが訓練データ、y_trainがその正解データ
# X_testがテストデータ、y_testがテストの正解データ
X_train, y_train = arrayX[0:ntrn], arrayY[0:ntrn]
X_test, y_test = arrayX[ntrn:], arrayY[ntrn:]

機械学習モデルの構築と学習

model.compileでモデルを構築します。

機械学習モデルとして、LSTM(Long Short-Term Memory : 長・短期記憶)という時系列データに基づく分類、処理、予測に適している人工回帰型ニューラルネットワーク(RNN)アーキテクチャを使用します。

hidden_dimは隠れ層を指定する変数で、隠れ層を多くすると計算時間が多くなるが、学習がより柔軟に行えます。

input_shapeには (10,9) と指定しています。入力データがデータ数10日分、9個のテクニカル指標の行列で出来ているのでこの数字です。

Dropout(0.2)で上からの計算の流れを意図的に20%無効にしてしまいます。学習のやり過ぎで未知のデータに対する予測能力の低下を防ぐ効果があります。

Dense(7)で出力を7つの数字にしています。正解データが7つのカテゴリなので、7次元のデータが出力されるようにします。

Activation(‘softmax’)で自身の最後に出力した7次元のデータの合計を1になるように変換します。株価の7つのカテゴリの変化率の合計が100%になるようにします。

最適化アルゴリズムにAdamと学習率を指定します。

hidden_dim = 128
model = Sequential()
model.add(LSTM(hidden_dim, input_shape=(10,9), stateful=False, return_sequences=False))
model.add(Dropout(0.2)) 
model.add(Dense(7)) 
model.add(Activation('softmax'))
opt = keras.optimizers.Adam(learning_rate=0.0001)
model.compile(optimizer=opt ,loss='categorical_crossentropy',metrics=['accuracy'])

model.fit で構築したモデルに学習させます。epochsで学習の回数を指定します。

epochs = 100
verbose = 0
history = model.fit(X_train, y_train, batch_size=128, epochs=epochs, verbose=verbose, validation_split=0.2, validation_data=(X_test, y_test))

予想を出力

構築したモデルに直近10日分のテクニカル指標を入力すると、モデルが7つのカテゴリごとの確率を出力してくれます。

predict = model.predict(n_df.iloc[-10:][use_cols].values.reshape(1,10,9), verbose=verbose)

columns =['~ -2.5%', '-2.5% ~ -1.5%', '-1.5% ~ -0.5%', '-0.5% ~ 0.5%', '0.5% ~ 1.5%', '1.5% ~ 2.5%', '2.5% ~ ']
pred = pd.DataFrame(predict, columns=columns)

実際の出力は以下のURLで試せます。

AIによる株価予想 https://www.mhr-y.com/jp/ai-stock/

機械学習のエッセンス 実装しながら学ぶPython、数学、アルゴリズム

機械学習のエッセンス 実装しながら学ぶPython、数学、アルゴリズム

加藤 公一
3,018円(09/19 02:26時点)
発売日: 2018/09/20
Amazonの情報を掲載しています

さいごに

今回はLSTMを使用して3日後の株価を予想しました。

今回の実装は以下のサイトを参考にしています。

https://note.com/happy_ice_cream/n/n0cae976e5c78

参考になれば幸いです。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です