機器學習 Python 做比特幣交易,如何找到好的特徵?增進模型的有效工具

這篇文章用機器學習實作能獲利的 BTCUSDT 交易模型,使用 Tunta 優化特徵,獲得更好的交易預測能力,會有機器學習範例講解。現在的機器學習,已經越來越複雜,一個能夠實戰的模型,最好是有數百甚至是上千個 features。然而這麼多 features,並不是常人用手工一個個產生出來的,必須要大量的仰賴自動化生成。例如像是 Numerai 平台,最近更新的 features 數量都已經破千了,代表更多的 features 確實會對於訓練模型有所幫助。

Numerai 提供股票的 features,由資料科學家(我們)訓練模型並產生結果,上傳後匯聚成最後的權重,來控制對沖基金的部位。我們沒辦法知道每檔股票的名稱,所以沒辦法用 Numerai 的 features 來做交易,但我們上傳到平台上,假如績效好的話,Numerai 會額外給我們加密貨幣 NMR 當作獎勵,雖然 Numerai 是很棒的練兵的地方,但是由於要用 Stake NMR 加密貨幣才能獲利,而且 NMR 的價格波動會導致獲利的風險偏高。所以還是自己做交易比較實在,想要機器學習自學,就看這篇吧!

那要怎麼樣產生出上千個 features 呢?好在用 Python 製作 features 是很簡單的,只要用常見的 Packages 像是 Talib 或 pandas_ta ,加上參數的變化,就可以隨機產生出很多的 features。但困難在於,做了好幾千個 features,究竟哪些是重要的呢?假如用了沒意義的 features,反而混淆訓練結果,造成模型的績效效果不好。

Tuneta 介紹

介紹給大家 Tuneta 這個工具可以幫我們最佳化技術指標的參數。它有以下幾個功能:

  1. 支援 Talib、Pandas_ta、finta,這三種不同的函式庫,有統一的接口,你再也不用擔心不同函式庫整合的問題。
  2. 針對每種技術指標,可以最佳化參數,讓產生出來的 feature 跟 lable 之間有最高的 correlation
  3. 並不是使用一般的 Pearson correlation coefficient 來判斷,而是使用一種叫做 distance correlation 的判斷機制,就算是非線性的關係也會被納入考慮。
  4. 使用 KNN 將搜尋的參數分群 Cluster,然後針對每一個 Cluster 找出中心點,這個作法可以找到參數高原。
  5. 產生每個 features 後,支援 sklearn 的 pipeline 格式,可以快速的引入當前的項目之中,點也不費力。

Tuneta 的效果

以下是 Tuneta 做機器學習例子,加入我自己的機器學習系統中,確實對於 Model 的判斷有顯著的增長,並且使用 feature importance 分析,這些 tuneta 產生的 feature 確實分數都滿高的:

機器學習 LightGBM 特徵重要性分析

機器學習深度學習,我覺得在做交易時比較少用到。比較常使用的是傳統 treebase 的模型,而非神經網路。我覺得這個 Package 的缺點在於,有時候我們會需要重複的指標當作 features,例如「sma(10)」和「sma(60)」,但是它只能幫我們產生出單個技術指標的最佳解。不過經過驗證,產生出來的 features,確實效果都還不錯!接下來我們就真的來建構一個模型吧!

實驗設計

機器學習python實作,我們使用 pandas_ta 的 default 參數,將所有 pandas_ta 的技術指標計算出來。另外對比 tuneta 優化後產生的技術指標,比較兩個模型的預測結果,並且用回測來驗證是否能真正幫助到獲利。

使用 colab 來建構統一的環境,方便大家還原實驗的結果。首先我們要先來下載 tuneta,但除了 tuneta 以外,還要有歷史資料,可以安裝 finlab-crypto 來獲得。

!pip install finlab-crypto -q
!wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
!tar -xzvf ta-lib-0.4.0-src.tar.gz
%cd ta-lib
!./configure --prefix=/usr
!make
!make install
!pip install Ta-Lib
!pip install -U tuneta
!pip uninstall numpy --yes
!pip install numpy

下載歷史資料和 feature 建構

安裝了所需的 Package ,就可以來下載歷史資料:

from finlab_crypto import crawler

ohlcv = crawler.get_all_binance('BTCUSDT', '4h')
ohlcv.head()
下載BTC歷史資料

使用 Pandas_ta 產生 features

接下來我們先用 pandas_ta 自動產生出預設的技術指標,當作對照組:

import pandas_ta as ta
ohlcv.ta.strategy("Momentum")

default_features = ohlcv.iloc[:, 11:]
ohlcv = ohlcv.iloc[:, :11]
default_features.head()
產生出 features

使用 Tuneta 產生 features

接下來我們用 tuneta 產生實驗組,眼尖的人會發現我是用 tta,也就是 talib 函式庫來產生 features,你也可以用 pta,也就是 pandas_ta 函式庫。但是在 colab 上要跑很久,所以我擅自改成 tta。在這邊實驗有點不完備,但留給大家自行發揮。

from tuneta.tune_ta import TuneTA

train_test_split = '2021-1-1'

X1, y1 = ohlcv.loc[:train_test_split].iloc[:-8], ohlcv.close.pct_change(-2).loc[:train_test_split].iloc[:-8]

tt = TuneTA(n_jobs=4, verbose=True)
tt.fit(X1, y1,
    indicators=['tta'],
    ranges=[(2, 30)],
    trials=100,
    early_stop=20,
)
tt.prune()
print(tt.report())

tt_features = tt.transform(ohlcv)
tt_features.tail()
tuneta 產生出來的 feature 和相關性分析

最後我們來比較兩種不同的 feature 做出來的效果。像是一般的方法訓練即可。

模型訓練

import lightgbm as lgb

# generate training data
X1_train, y1_train = default_features.loc[:train_test_split].iloc[:-8], ohlcv.close.pct_change(-2).loc[:train_test_split].iloc[:-8]
X2_train, y2_train = tt_features.loc[:train_test_split].iloc[:-8], ohlcv.close.pct_change(-2).loc[:train_test_split].iloc[:-8]

# train
model1 = lgb.LGBMRegressor()
model1.fit(X1_train, y1_train)

model2 = lgb.LGBMRegressor()
model2.fit(X2_train, y2_train)

# test and predict
X1_test, y1_test = default_features.loc[train_test_split:], ohlcv.close.pct_change(-2).loc[train_test_split:]
X2_test, y2_test = tt_features.loc[train_test_split:], ohlcv.close.pct_change(-2).loc[train_test_split:]

y1 = pd.Series(model1.predict(X1_test), X1_test.index)
y2 = pd.Series(model2.predict(X2_test), X2_test.index)

最後我們來看一下究竟效果如何,可以用真實報酬跟預測結果的相關性來比較,越高代表越好。下面的實驗中,我們可以看到對照組的模型 ( model2 ) 比實驗組好很多。

import pandas as pd

pd.DataFrame({'real': y1_test, 'pred': y1}).corr().iloc[1,0], pd.DataFrame({'real': y2_test, 'pred': y2}).corr().iloc[1,0]
(0.007258040702236883, 0.02274027435611208)

最後我們可以做一個簡單的回測,試試看用這兩個模型做交易,績效會有什麼不一樣。首先,要決定進場的時機,將模型預測的分布顯示出來:

模型預測分布

有了上圖,就可以設計進場時機,為預測結果大於 0.04 時進場8小時。接下來撰寫回測模擬:

y1_test[y1 > 0.04].add(1).cumprod().plot()
y2_test[y2 > 0.04].add(1).cumprod().plot()

上圖的回測結果中,綠色為實驗組,比對照組的報酬率顯著上升不少。

小節

由以上的實驗,可以證明對於 feature ,使用 Tuneta 參數優化是非常有效的。現在行情不好,大家可以趁現在默默耕耘,等時機到的時候,馬上就賺回來了!

FinLab - 韓承佑

嗨大家好,我是韓承佑,FinLab創辦人,畢業於巴黎薩克雷大學資工博士,目前擔任臺灣量化交易協會 學術顧問、台北商業大學 創新育成中心 創業技術顧問與上市科技公司 量化交易顧問。當初,我喜歡寫程式、無意間因為軟體比賽接觸Fintech,從此開始了財經跟程式的學習之路。我們成立 FinLab 量化投資部落格,用自己研發的軟體,對台灣股市做大量快速的實驗。希望可以在量化投資的路上,當大家的「武器製造商」!