練習版程式碼連結:https://colab.research.google.com/drive/1A76V9clhV1lmyavClJNJtqmMUqHB6RTP?usp=sharing
上一節:我們成功將 filter 打包重複再利用。
這一節,我們挑戰用一行程式碼研發交易策略。
a. 使用 Talib 製作策略
把開頭兩格儲存格的程式碼跑完後,於「MACD Strategy」開始,導入 talib:
import talib
接下來移動到「Apply Talib function」這邊,輸入:
talib.MACD(ohlcv.close)
如圖,總共產生三條時間序列。
我們只需要最後一條時間序列就夠了,所以後面在接上「[2]」(0、1、2):
把上述程式碼傳到一個叫做 macdhist 的變數裡面之後,輸入以下程式碼把 MACD 指標和歷史收盤價格畫出來:
(藍色為 MACD,橘色為歷史價格)
由圖可以看出,當價格上漲時,MACD 就會變高,我們希望如果 MACD 如果突破 0 的話,就進行入場。
假如輸入「talib.get_functions()」的話,就會看到多達 158 種的技術指標,有興趣可以從中挑選一些來回測看看,測試哪種報酬率比較高。
在下方的儲存格裏有寫黃金交叉跟死亡交叉策略,我們在這個儲存格的最下方開始撰寫 MACD 策略。
先回到繪製 MACD 跟價格的那個儲存格裏,在第一行的 MACD 裡面撰寫他的三個參數,以便產生不同的 MACD:
macdhist = talib.MACD(ohlcv.close, fastperiod = 12, slowperiod = 26, signalperiod = 9)[2]
macdhist.loc['2021 - 11'].plot()
ohlcv.close.loc['2021 - 11'].plot(secondary_y = True)
先把第一行複製起來,來到下方有撰寫交叉策略的儲存個這邊,建立一個函式,在函式裏把那段程式碼貼上:
import numbers
from finlab_crypto import Strategy
def crossover(s1, s2):
if isinstance(s2, numbers.Number):
return (s1 > s2) & (s1.shift() < s2)
return (s1 > s2) & (s1.shift() < s2.shift())
def crossunder(s1, s2):
if isinstance(s2, numbers.Number):
return (s1 < s2) & (s1.shift() > s2)
return (s1 < s2) & (s1.shift() > s2.shift())
def macd_strategy(ohlc):
macdhist = talib.MACD(ohlcv.close, fastperiod = 12, slowperiod = 26, signalperiod = 9)[2]
有了 MACD 之後,開始撰寫進出場點。
上面有講到,我們希望 MACD 穿越 0 的時候進場,所以進場點可以這樣寫(寫在 macdhist 這個變數裡面):
entries = crossover(macdhist, 0)
我們利用上面寫好的黃金交叉函數來幫助撰寫進場點。
出場點則是跌破 0 的時候:
之後撰寫可用來視覺化的 figures 巢狀字典,在建構返回值來返回進出場點和 figures:
figures = {'figures':{'macdhist':macdhist}}
return entries, exits, figures
然後於 macd_strategy 這個函式上方放置一個裝飾器,在於最底下列印出回測可視化圖表,最後修改參數位置,於是整個程式碼看起來像這樣:
import numbers
from finlab_crypto import Strategy
def crossover(s1, s2):
if isinstance(s2, numbers.Number):
return (s1 > s2) & (s1.shift() < s2)
return (s1 > s2) & (s1.shift() < s2.shift())
def crossunder(s1, s2):
if isinstance(s2, numbers.Number):
return (s1 < s2) & (s1.shift() > s2)
return (s1 < s2) & (s1.shift() > s2.shift())
@Strategy(fastperiod = 12, slowperiod = 26, signalperiod = 9)
def macd_strategy(ohlcv):
macdhist = talib.MACD(ohlcv.close,
fastperiod = macd_strategy.fastperiod,
slowperiod = macd_strategy.slowperiod,
signalperiod = macd_strategy.signalperiod)[2]
entries = crossover(macdhist, 0)
exits = crossunder(macdhist, 0)
figures = {'figures':{'macdhist':macdhist}}
return entries, exits, figures
macd_strategy.backtest(ohlcv, variables = None, freq = '1h', plot = True)
(可以參考前面的文章設置 variables 的值)
相信大家一定能感受到,明明只是一個簡單的策略,卻需要寫這麼多行程式碼,真的很麻煩。
於是,我們來試著只用一行來撰寫策略。
b. 使用 Talib 撰寫一行策略
先移步到「Talib Wrapper」並導入 TalibStrategy:
from finlab_crypto.talib_strategy import TalibStrategy
接下來的程式碼其實與上面的策略程式碼極其類似:
from finlab_crypto.talib_strategy import TalibStrategy
def entry_func(ohlcv, macd):
return crossover(macd.macdhist, 0)
def exit_func(ohlcv, macd):
return crossunder(macd.macdhist, 0)
macd_strategy = TalibStrategy('MACD', entry_func, exit_func)
macd_strategy.backtest(ohlcv, variables = None, freq = '1h', plot = True)
圖上畫線的程式碼就是我們的「一行策略」。
我們成功利用更少的程式碼,做出與上面的策略一模一樣的結果。
如果想連上面兩個 def 函式都要省略的話,就要使用 Python 的 lambda 語法:
macd_strategy = TalibStrategy(
'MACD',
lambda ohlcv, macd: crossover(macd.macdhist, 0),
lambda ohlcv, macd: crossunder(macd.macdhist, 0),
)
macd_strategy.backtest(ohlcv, variables = None, freq = '1h', plot = True)
跑出來的結果也完全相同。
關於 lambda 語法,可以參考 W3Schools 的介紹:https://www.w3schools.com/python/python_lambda.asp
良葛格的文章也非常不錯:https://openhome.cc/Gossip/Python/LambdaExpression.html
這一節,我們成功用一行程式碼來撰寫策略。
下一節,我們延續這一節的內容,來試著撰寫布林通道突破的策略。