文件
開啟 Studio

教學

機器學習

本頁內容6

這一頁帶你用機器學習選股:合併特徵 → 產生標籤 → 訓練模型 → 回測。finlab.ml 負責把資料整理成模型吃得下的格式,並把 qlib 的 LightGBM、XGBoost、CatBoost 等模型包成一致的用法。

安裝

安裝 FinLab 的 Qlib 相依套件(包含 TA-Lib 與支援平台上的模型函式庫):

pip install 'finlab[qlib]'

finlab[qlib] 已包含 LightGBM、XGBoost、CatBoost 等模型函式庫;PyTorch 在支援的平台上也會一起安裝。

單獨安裝或更新模型函式庫

四個步驟完成 ML 選股

合併特徵

finlab.ml.feature.combine() 把多個來源的特徵(技術面、基本面、自訂)合成一張表,並用 resample 重新取樣。下面把股價淨值比和本益比合成一組每週的特徵:

from finlab import data
from finlab.ml import feature as mlf

features = mlf.combine(
    {
        'pb': data.get('price_earning_ratio:股價淨值比'),
        'pe': data.get('price_earning_ratio:本益比'),
    },
    resample='W',
)

features.head()
pbpe
(Timestamp('2010-01-04 00:00:00'), '1101')1.4718.85
(Timestamp('2010-01-04 00:00:00'), '1102')1.4414.58
(Timestamp('2010-01-04 00:00:00'), '1103')0.7940.89
(Timestamp('2010-01-04 00:00:00'), '1104')0.9273.6

結果的索引是(datetime, instrument):每個日期、每檔股票一列,每個特徵一欄。

產生標籤

標籤是模型要預測的答案,例如每檔股票下一週的報酬。finlab.ml.label 的函式吃特徵的索引,回傳索引相同的 Series,可以和特徵逐列配對。resample 要和 combine() 用的一樣,日期才對得上:

from finlab.ml import label as mll

labels = mll.return_percentage(features.index, resample='W', period=1)

其他標籤(當沖報酬、MAE/MFE、超額報酬)見下方換一種標籤。

切分資料並訓練模型

用日期切出訓練集與測試集:2020 年前的資料拿來訓練,之後的資料拿來預測。只用特徵和標籤都齊全的列訓練:

import finlab.ml.qlib as q

complete = features.notna().all(axis=1) & labels.notna()
is_train = features.index.get_level_values('datetime') < '2020-01-01'
X_train = features[complete & is_train]
y_train = labels[complete & is_train]
X_test = features[~is_train]

model = q.LGBModel()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)

model.predict() 回傳一張日期 × 股票的預測值表。

回測

挑出每期預測值最高的 50 檔,用 sim 回測,算出策略的報酬與風險指標:

from finlab.backtest import sim

position = y_pred.is_largest(50)

sim(position, resample='4W')

加入技術指標特徵

finlab.ml.feature 提供 ta_names 和 ta 兩個函式,產生 TA-Lib 技術指標特徵。

產生指標名稱:ta_names

ta_names 產生一組 TA-Lib 指標名稱,每個名稱對應一組參數設定。

  • n:每個指標隨機產生的參數組數。n=10 表示每個 TA-Lib 指標最多有 10 組不同參數;沒有參數的指標只出現一次。
from finlab.ml import feature as mlf

mlf.ta_names(n=1)
['talib.HT_DCPERIOD__real__',
 'talib.HT_DCPHASE__real__',
 'talib.HT_PHASOR__quadrature__',
 'talib.HT_PHASOR__inphase__',
 'talib.HT_SINE__sine__',
 'talib.HT_SINE__leadsine__'
 ...
 ]

計算指標值:ta

ta 根據 ta_names 產生的名稱列表,計算對應的指標值。

  • resample:選填,把算出來的指標值重新取樣到指定頻率。
from finlab.ml import feature as mlf

mlf.ta(
    [
        'talib.HT_DCPERIOD__real__',
        'talib.HT_DCPHASE__real__',
        'talib.HT_PHASOR__quadrature__',
    ],
    resample='W',
)
talib.HT_DCPERIOD__real__talib.HT_DCPHASE__real__
(Timestamp('2024-04-07 00:00:00'), '9951')23.4372122.135
(Timestamp('2024-04-07 00:00:00'), '9955')18.441668.0654
(Timestamp('2024-04-07 00:00:00'), '9958')30.1035-10.7866
(Timestamp('2024-04-07 00:00:00'), '9960')17.502594.0009
(Timestamp('2024-04-07 00:00:00'), '9962')23.293190.0781

resample='W' 會把日期移到每週的標籤日(星期日),每檔股票每週一列。

合成一組技術指標特徵

把 ta() 的結果交給 combine()。下面從 RSI、MACD、ATR 各隨機產生 3 種參數配置:

from finlab.ml import feature as mlf

# RSI、MACD、ATR 各隨機產生 3 種參數配置
names = [
    name
    for name in mlf.ta_names(n=3)
    if name.startswith(('talib.RSI__', 'talib.MACD__', 'talib.ATR__'))
]
technical = mlf.combine({'talib': mlf.ta(names)}, resample='W')

結果的索引同樣是(datetime, instrument),每個指標輸出一欄,欄名如 talib.RSI__real__timeperiod__37__、talib.MACD__macdsignal__fastperiod__48__slowperiod__104__signalperiod__36__。指標用目前設定的市場與股票池的股價計算。

換一種標籤

finlab.ml.label 提供多種報酬與風險標籤:

函式標籤內容resampleperiod
daytrading_percentage下一個交易日從開盤到收盤的報酬(當沖)有,預設 'D'無
return_percentage未來 N 期的報酬,用於分析中長期表現有有
maximum_adverse_excursionMAE:持有期內的最大不利變動目前不支援有
maximum_favorable_excursionMFE:持有期內的最大有利變動目前不支援有
excess_over_median相對同期全市場報酬「中位數」的超額報酬有有
excess_over_mean相對同期全市場報酬「均值」的超額報酬有有
  • resample:需與 combine 的 resample 一致,以對齊時間。
  • period:計算未來 N 期的變化,一期的長度由 resample 定義。
from finlab.ml import label as mll

label = mll.return_percentage(features.index, resample='W', period=1)
label = mll.maximum_adverse_excursion(features.index, period=1)
label = mll.maximum_favorable_excursion(features.index, period=1)
label = mll.excess_over_median(features.index, resample='W', period=1)
label = mll.excess_over_mean(features.index, resample='W', period=1)

當沖報酬的例子(特徵是日資料,用預設的 resample):

from finlab.ml import feature as mlf
from finlab.ml import label as mll

feature = mlf.combine(...)
label = mll.daytrading_percentage(feature.index)
datetime    instrument
2007-04-23  0015          0.000000
            0050          0.003454
            0051          0.004874
            0052          0.006510
            01001T        0.001509
dtype: float64

請確保 index 與市場設定正確;標籤可直接搭配特徵用於模型訓練。

換一個模型

WrapperModel 將 LightGBM、XGBoost、CatBoost、線性模型、TabNet、DNN 等模型封裝成統一的 fit / predict 介面,讓你專注在特徵與策略,不必陷入模型細節。每個模型的用法都一樣,只要換掉建立模型的那一行:

import finlab.ml.qlib as q

model = q.XGBModel()  # 換成下表任一個
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
模型封裝的模型
LGBModelLightGBM
XGBModelXGBoost
DEnsmbleModel雙重集成模型
CatBoostModelCatBoost
LinearModel線性模型
TabnetModelTabNet
DNNModel深度神經網絡

一次試多個模型:get_models

get_models() 取得可用模型的清單,方便進行多模型試驗:

import finlab.ml.qlib as q

# 獲取所有可用的模型
models = q.get_models()

# 列印出所有模型的名稱
print(list(models.keys()))

# 選擇一個模型進行實例化,例如 LightGBM
model = models['LGBModel']()

# 假設已經準備好了訓練數據和測試數據 X_train, y_train, X_test
model.fit(X_train, y_train)

# 使用訓練好的模型進行預測
y_pred = model.predict(X_test)

下一步

↑↓ 選擇 Enter 開啟 Esc 關閉