Table of Contents
在第一篇文章—利用 TQuant Lab 驗證深度學習 LSTM 股價預測成效(一),我們利用預測數據與實際數據的比對,對於訓練好的兩個模型(2618、8615 兩檔股票)有初步的成效評估,效果是不錯的,詳細分析可以點擊以上連結了解更多,篇幅原因就不贅述。
因此在第二篇文章,我們希望不要只是紙上談兵,將模型套用在 out sample 的資料,並根據預測結果決定進場點,實測看看效果是不是也如預期的好。
本文使用 Mac OS 及 VS Code 作為編輯器
我們的兩個模型的樣本內資料都是自 2012-07-01 至 2021-07-01 ,因此此次的回測起訖日會從 2021-01-01 至 2024-06-30,以避開訓練期間。
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、價量資料、基本面資料及技術指標等主要功能。最後設定回測的樣本起訖日。
另外我們設置 model
變數,將訓練好的模型載入以待使用。
*註:貼心提醒,在使用前請先至 config.ini 輸入自己的 API_KEY,這樣才能順利使用喔!
ml_stock = ML_stock()
ml_stock.ini()
model = load_model(f'lstm_{sample[1]}.keras')
start = '2021-01-01'
end = '2024-06-30'
os.environ['mdate'] = start + ' ' + end
os.environ['ticker'] = ' '.join([sample[1]]) + ' ' + 'IR0001'
!zipline ingest -b tquant
接下來我們只留下必要的特徵,完成資料前處理。
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'])
與訓練時一樣,我們將資料轉換成時間序列資料,具體流程可以閱讀上一篇說明。轉換好之後,便使用 predict
函數套用模型進行預測。
prediction = model.predict(X)
可以看到我們以 2022 過去十年的資料所訓練的 LSTM 模型套用在 2022 年之後的股價的預測表現也與實際上大致相符,除了在預測驗證資料就會出現的漲跌幅跟不上以外,基本上沒有問題。
CustomDataset
可以將資料庫中的內容導入 Pipeline 中,方便後續回測使用。於本範例我們用以將上述 Pred 欄位紀錄的預測數值資訊導入 Pipeline。擷取部分程式碼如下:
from zipline.pipeline.data.dataset import Column, DataSet
from zipline.pipeline.domain import TW_EQUITIES
class CustomDataset(DataSet):
pred = Column(float)
domain = TW_EQUITIES
Pipeline
函式由於 LSTM 模型只是做了對隔日收盤價的預測,具體該如何進場、進場時機及條件為何,還需要我們做更精細的設定,為此需要設計客製化因子。
Custom Factor
CustomFactor
可以讓使用者自行設計所需的客製化因子,於本次案例我們用以處理:
Return
)AverageTrueRange
)def make_pipeline():
pred = CustomDataset.pred.latest
price = TWEquityPricing.close.latest
returns = Return(inputs=[TWEquityPricing.close])
returns_pred = Return()
ATR = AverageTrueRange(inputs = [TWEquityPricing.high,
TWEquityPricing.low,
TWEquityPricing.close])
return Pipeline(
columns = {
'price': price,
'pred': pred,
'return': returns,
'return_pred': returns_pred,
'atr': ATR.ATR,
},
screen = ~StaticAssets([benchmark_asset])
)
pipeline_result = engine.run_pipeline(make_pipeline(), start_dt, end_dt)
pipeline_result
initialize
函式initialize()
函式用於定義交易開始前的每日交易環境,與此例中我們設置:
context.stop_loss
變數,將回測中的止損點紀錄context.last_price
變數,記錄最後買賣價格,跟蹤止損handle_data
函式handle_data()
為構建策略的重要函式,會在回測開始後每天被呼叫,主要任務為設定交易策略、下單與紀錄交易資訊。
關於本策略的交易詳細規則請至:backtest_2618.ipynb / backtest_8215.ipynb
if return_pred < 0 and cash_position >= 0 and returns < 0:
order_percent(i , 0.48)
buy = True
record(
**{
f'buy_{sym}':buy
}
)
context.stop_loss = price - atr * 1.25
本次範例利用 return_pred
紀錄預測股價、returns
為真實股價走向,若兩者走勢為正向,則進行入場。出場則是以停利和跟蹤止損並行。本策略只回測長部位的單向入場,有興趣者可以再嘗試多空並行的策略。
analyze
函式
協助我們繪製自訂圖表,本次我們用到 analyze
()
來觀察預測股價和實際股價的差異、策略進出場情形和資金運用情況。analyze
()
關於本策略的交易詳細規則請至:backtest_2618.ipynb / backtest_8215.ipynb
from zipline import run_algorithm
start = '2021-01-01'
end = '2024-06-28'
start_dt = pd.Timestamp(start, tz = 'UTC')
end_dt = pd.Timestamp(end, tz = 'UTC')
results = run_algorithm(
start = start_dt,
end = end_dt,
initialize = initialize,
bundle = 'tquant',
analyze = analyze,
capital_base = 1e6,
handle_data = handle_data,
custom_loader=custom_loader
)
results
使用 run_algorithm()
執行上述設定的策略,設置交易期間為 start_dt
(2021-01-01) 到 end_dt
(2024-06-28),導入 custom_loader,使用資料集 tquant,初始資金為一百萬元。其中輸出的 results
為每日績效與交易的明細表。
上面兩張圖顯示策略獲得良好的績效,其中 2618 的回測全程超越大盤,而 8215 的績效則是在領先大盤後被大盤稍稍追過。
*注:圖中第二小圖為預測股價和實際股價的差異,藍線為預測股價,紅線則為實際股價,紅色三角標記為買進,綠色三角標記為賣出。
import pyfolio as pf
returns, positions, transactions = pf.utils.extract_rets_pos_txn_from_zipline(results)
benchmark_rets = results['benchmark_return']
pf.tears.create_full_tear_sheet(returns=returns,
positions=positions,
transactions=transactions,
benchmark_rets=benchmark_rets
)
在以上兩檔股票的回測中,我們可以看到以 LSTM 股價預測策略進行回測的績效會有不錯的成果,兩檔回測的夏普率都超過 0.5,Alpha 值也都在一個不錯的水準。比較特別的是 2618 這檔回測,40 個月來年化報酬率來到 29.6%,累積報酬率更來到接近 138%,績效相當的好。
更詳細的來看看策略本身的特性,由於策略的基礎是以隔日收盤價為目標進行買入,因此我們可以發現到報酬率曲線相當近似於實際股價的曲線,換句話說就是漲的時候策略會漲,跌的時候策略也會跌,因此止損與止盈的控制就非常重要,需要特別注意。
另外我們在撰寫策略時,有發現到「return_pred
紀錄預測股價、returns
為真實股價走向,若兩者走勢為正向,則進行入場。」這件事不全然可以套用在所有模型上,可能對於某些檔股票而言,走勢同為負向時,抑或是正 / 負得更多時再進行入場才會獲得更高的收益,否則績效的變化是很大的。
之所以會導致此原因,我們推測是由於時間序列模型在預測上的延遲性,這個延遲性會導致我們在買多時可能會有不小心買在高點(因為高點在前一天就出現了,模型第二天才反映出來)導致成本過高,或是賣在低點(低點在前一天就出現,模型同樣是第二天才反映,導致績效變差),因此這項策略會更需要我們多去調整策略參數,找到最優解。
歡迎投資朋友參考,之後也會持續介紹使用 TEJ 資料庫來建構各式指標,並回測指標績效,所以歡迎對各種交易回測有興趣的讀者,選購 TQuant Lab 的相關方案,用高品質的資料庫,建構出適合自己的交易策略。
溫馨提醒,本次分析僅供參考,不代表任何商品或投資上的建議。
電子報訂閱