はじめに
今回はAIの手法のひとつである機械学習LSTMを使用して、3日後に株価がどれぐらい変化するか予想します。実装したサイトは以下のURLで公開しています。
AIによる株価予想 https://www.mhr-y.com/jp/ai-stock/
機械学習の予備知識なく作成しましたので、認識違いがある可能性があります。予めご了承ください。改善のアドバイスなどありましたらコメントください。
Pythonではじめる機械学習 ―scikit-learnで学ぶ特徴量エンジニアリングと機械学習の基礎
予想アルゴリズム
今回の予想アルゴリズムを示します。
基本的な考え方は以下の通りです。
最初に、過去の株価を取得しテクニカル指標を算出します。
次に、テクニカル指標の値と株価の上昇・下降の関係を学習します。
最後に、直近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シリーズ)
訓練データと学習データを作成する
次のステップとして、作成したテクニカル指標の値から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/
さいごに
今回はLSTMを使用して3日後の株価を予想しました。
今回の実装は以下のサイトを参考にしています。
https://note.com/happy_ice_cream/n/n0cae976e5c78
参考になれば幸いです。