本文重點概要
- 文章難度:★★★★★
- 結合基本面、籌碼面及技術面資料進行 LSTM 股價預測,並執行回測驗證績效
- 閱讀建議:本文使用 RNN 架構進行時間序列預測,需要對時間序列或是深度學習有基礎瞭解,可以參考【資料科學】LSTM,以便對於 LSTM 模型建置有更深的理解。
前言
在機器學習領域上,對於金融市場的衍生性商品之價格預測始終是一塊熱門領域,無數研究皆著眼於如何利用機器學習獲取市場的超額報酬。然而由於金融市場畢竟是人性的集合體,包含許多不規則與不確定因素,普通的機器學習模型如羅吉斯回歸、隨機森林和極限梯度提升等模型,似乎都無法有效捕捉過於複雜的市場規則,於是到了今日,隨著深度學習的蓬勃發展,越來越多時間序列相關的模型的出現,似乎能應用於未來股價的預測中。本文利用 LSTM 時間序列模型進行深度學習 LSTM 股價預測,使用前 5 日的開高低收成、每季 ROE、MOM(表示價格走勢的變化幅度,以及行情的趨動方向)及 RSI 指標預測隔日收盤價。
編輯環境及模組需求
本文使用 Mac OS 及 VS Code 作為編輯器
LSTM 模型建置
由於台股權值股較容易受到大戶進出或較難預測之市場波動影響,導致股價波動難以預期,因此本文選擇 2024 Q2 臺灣指數公司上市之中小型代表 300 指數(簡稱「中小型 300 指數」)頒布之前十大成分股中的第七位—2618(長榮航)作為目標股票。除此之外我們也另外挑了一檔市值較高的 8215(明基財)執行回測作為參考。
載入外部套件
import os import time import tejapi import talib as ta from talib import abstract import numpy as np import pandas as pd …
載入內部套件
ML_stock() 為我們編寫用以作事前資料處理的 class,執行載入 API_KEY、價量資料、基本面資料及技術指標等主要功能。最後設定模型的樣本起訖日。
*註:貼心提醒,在使用前請先至 config.ini 輸入自己的 API_KEY,這樣才能順利使用喔!
from initialize import ML_stock from select_1 import sample, column, feature ml_stock = ML_stock() ml_stock.ini() start = '2012-07-01' end = '2022-07-01' df = ml_stock.get_fundamental(start, end, [sample[1]], column) df = ml_stock.calculate_all_technical_indicators(df) preporc_data = ml_stock.preprocessing(df) data = preporc_data.drop(columns=['mdate', 'coid'])
可以看到我們只留下必要的特徵,留待下一步使用。
建立時間序列資料
先將所有資料標準化,定義訓練集的 window_size 為 5,也就是說每筆資料都是由當日與後五天的資料組成,並透過滑動窗口的方式迭代,所以每筆資料與上一筆資料都會有五日的重疊。
def create_dataset(df, window_size=5): df = data features = df[feature].values target = df['close'].shift(-1).values # y變量為隔日收盤價 target[-1] = target[-2] scaler = StandardScaler() features = scaler.fit_transform(features) t_scaler = StandardScaler() target = t_scaler.fit_transform(target.reshape(-1, 1)) X, y = [], [] for i in range(len(df) - window_size): X.append(features[i:i + window_size]) y.append(target[i + window_size]) return np.array(X), np.array(y), t_scaler
從上圖可以看到我們分別為應變數(開高低收等等)和自變數(隔日收盤價)建立三維矩陣,維度由左到右分別代表(資料筆數、天數、欄位數)。完成後我們再進行訓練集、驗證集和測試集的切割,以 8:1:1 比例分割。
建制模型
在建模部分,本文使用一個 LSTM 層和 3 個 Dense 層,中間穿插 Dropout 防止過擬合,最後一層是單個神經元的 Dense 層,用於輸出預測值。另外我們定義一個指數衰減的學習率變化,初始學習率為 0.001,每 10000 步學習率都會是原來的 0.9 倍,並呈階梯式下降。
再來使用 Adam Optimizer,套用前面的學習率設定,損失函數使用均方誤差(MSE),評估指標為平均絕對誤差(MAE)。
最後設定一個 Early Stopping 法,它會監控 val_loss,在10個 epoch 內都未改善則訓練將停止,防止過擬合。
model = Sequential([layers.Input((X_train.shape[1], X_train.shape[2])), layers.LSTM(64), layers.Dense(32, activation='relu'), Dropout(0.2), layers.Dense(32, activation='relu'), Dropout(0.2), layers.Dense(1) ]) lr_schedule = ExponentialDecay( 0.001, decay_steps=10000, decay_rate=0.9, staircase=True) model.compile(optimizer=Adam(learning_rate=lr_schedule), loss='mse', metrics=['mae']) early_stopping = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True)
可以看到大約在 25 個 epoch 後 training loss 就逐漸不再顯著降低,模型收斂速度快。
LSTM 股價預測結果評估
可以看到訓練集與驗證集表現都很不錯,畢竟是在 sample 內,不過在測試集 out sample 的後半段,在實際價格預測上與實際有些差距,漲跌走向則是有掌握到,可以讓我們回測驗證。
我們以同樣方法在 8215(明基材)上建模並繪出比對圖,可以看到模型在預測 8215 的 out sample 隔日收盤價上效果較佳,不過實際上效果如何,還是有待下一篇回測驗證。
LSTM 股價預測特徵重要性分析
在所有特徵上,我們發現每日股價變化還是模型主要的參考對象,而 MOM 與 RSI 指標則次之,比較有趣的是每季 ROE 並不受模型青睞,應該是由於資料頻率不如其他特徵頻繁,對於需要預測每日股價的模型來說,並不是那麼具參考性的特徵。
在 2618 獲得的觀察現象也可以在 8215 上發現,每季 ROE 並不能很好的被模型採用進行預測。
model.save(f'lstm_{sample[0]}.keras', include_optimizer = False)
最後我們將模型儲存成 .keras 檔案,以利下一步回測階段。
結論
本次以 LSTM 建構股價預測模型可以發現,單看圖表的話,LSTM 在股價預測上應該會有不俗的效果,但是在過往關於時間序列模型的研究上,模型的預測和實際數據都會存在一定的延遲性,在上面的圖中都可以看出第一天的上漲 / 下跌可能會在第二天才反映出來,雖然差異不明顯,但這個情況在實際回測上可能會導致來不及下單的問題,我們會在下一篇再做更多的分析。
溫馨提醒,本次分析僅供參考,不代表任何商品或投資上的建議。
【TQuant Lab回測系統】解決你的量化金融痛點
全方位提供交易回測所需工具
留言 0