用Python投資加密貨幣:實做回測策略 (Part 4)

接下來我們廢話不多說,結合前一篇的買賣訊號,來建構一個加密貨幣的策略吧!

thumbnail 1 4

複習前幾篇用Python投資加密貨幣相關的知識

這篇文章,將接續著之前的單元,假如還沒看過前面的部分,可以參考以下的連結喔!

  1. 為什麼要投資加密貨幣
  2. 加密貨幣爬蟲
  3. 策略訊號建立

這篇我寫的比較仔細一點,所以文章稍長,但程式碼很短,先給大家聞香一下

result 1 2


想知道怎麼做出來,要看到最後喔!

將上一篇的程式碼統整,我們可以得到:

signal_long = (sma1 > sma2) & (sma1.shift() < sma2.shift())
signal_short = (sma1 < sma2) & (sma1.shift() > sma2.shift())

接下來,我們將 signal_long 跟 signal_short 整合在一起,這邊的 signal_long 跟 signal_short,是進場訊號,一個做多、一個是做空時間序列,當訊號為 True 時代表入場。

多空訊號結合

接下來為了配合 backtesting 函式庫,我們想將 signal_long 跟 signal_short 合併起來,產生一個翻轉策略:
當 signal_long 為 True 時,不論目前有什麼部位,都翻多
當 signal_short 為 True 時,不論目前什麼部位,一律翻空
我們想要做出一個新的訊號 叫做 signal,其做多訊號為 1,做空訊號為 -1 ,維持不變則為0。

可以用以下的寫法,首先copy signal_long 序列,並且將 signal_short 為 True 的部分改成 -1,這樣就可以了!

# combine long and short signal
signal = signal_long.copy()
signal[signal_short] = -1
signal 1 1

完整總和來說,我們目前已經有以下的程式碼:

from finlab import crypto

# geth the historical price
df = crypto.get_all_binance('BTCUSDT', '4h')

# calculate moving averages
sma1 = df.Close.rolling(20).mean()
sma2 = df.Close.rolling(60).mean()

# create long and short signal
signal_long = (sma1 > sma2) & (sma1.shift() < sma2.shift())
signal_short = (sma1 < sma2) & (sma1.shift() > sma2.shift())

# combine long and short signal
signal = signal_long.copy()
signal[signal_short] = -1

接下來我們直接比對一下,回測的程式碼,橘色部分比較特別,會逐一介紹。

code 1


(先不急著抄寫,文末會附上完整代碼)

首先,上圖中第一二行,我們將 Backtest 和 SignalStrategy 匯入,Backtest 是一個幫我們回測的 interface,而 SignalStrategy 是一個 class,我們可以繼承 SignalStrategy (第5行),就能把剛剛的訊號 signal 匯入來回測,這邊會用到物件導向的概念,可以參考:
w3c提供的簡單 python 物件導向教學

有了一個strategy空殼,接下來就可以實做內部功能了!

第7行中,我們覆寫一個parent 方法,叫做 init,在 init 這個方法中,我們可以計算回測要用的訊號,這個方法會在回測開始前執行一次,所以當我們先把訊號計算好,這樣回測的時候就不用計算,速度上會比較快!

init中大部分的程式碼,跟我們開頭所述的非常雷同,有幾點不一樣而已:

首先,在第8行中,parent class 會先執行他的 init,你可以想像,父母先吃飯,小孩再吃飯的道理!

super().init()

然後,第11行,也做了一點修正,從原本的:

# 原本的
df = crypto.get_all_binance('BTCUSDT', '4h')

變成:

# 新的
close = pd.Series(self.data.Close)

我們可以用 self.data.Close ,來獲取「開高低收」的歷史價格,這是繼承 SignalStrategy 附加的功能,可以讓程式碼中的「策略」跟「價格」解耦,讓策略不只交易 BTCUSDT,還能交易其他加密貨幣,甚至是股票!

最後12~21行,都跟之前一樣,所以就略過囉!

最後的24行,就是將我們產生的 signal 給匯入:

elf.set_signal(signal)

這樣子 SignalStrategy 裡面就會根據 signal,來進行翻多翻空的交易囉!

上述 1~26 行,都是一個策略藍圖,我們只是規劃,並沒有真正執行這些程式碼,所以我們還要額外家三行,建構出規劃好的策略,並且回測、統計回測結果:

bt = Backtest(df, Strategy)
bt.run()
bt.plot()
result 2 2

執行後會顯示出非常詳細的買賣點,這個就是所謂 窮人版 python 版的 multicharts 了吧!不過看起來策略的 performnace 不太好,賺不到什麼 $$,所以下一個單元,我們就來使用內建的 optimize 方法,找尋最優的均線交叉策略!優化後的績效,先給大家聞香一下!

opt

點我進入下一個單元:策略優化

以下是完整的程式碼:
另外也可以參考完整的 colab notebook 範例

from finlab import crypto
from backtesting import Backtest
from backtesting.lib import SignalStrategy
import pandas as pd

df = crypto.get_all_binance('BTCUSDT', '4h')

class Strategy(SignalStrategy):
    
    def init(self):
        super().init()
        
        # Precompute the two moving averages
        close = pd.Series(self.data.Close)
        sma1 = close.rolling(20).mean()
        sma2 = close.rolling(60).mean()
        
        # Precompute signal
        signal_long = (sma1 > sma2) & (sma1.shift() < sma2.shift())
        signal_short = (sma1 < sma2) & (sma1.shift() > sma2.shift())
        
        signal = signal_long
        signal[signal_short] = -1
        
        self.set_signal(signal)
        
        
    def next(self):
        super().next()

bt = Backtest(df, Strategy)
bt.run()
bt.plot()

如果喜歡我們的文章,也歡迎參考我們最新募資的線上課程「用 Python 理財:打造加密貨幣實戰策略」,在線上課程中,我們會更有系統、更完整地教您如何從無到有,打造10種加密貨幣實戰策略,並且能夠自動化雲端交易!有興趣的話,可以點此觀看課程介紹影片喔!

FinLab - 韓承佑

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