第二章:6 一行程式碼研發策略


Posted by nightqwq on 2021-12-11

練習版程式碼連結: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


這一節,我們成功用一行程式碼來撰寫策略。

下一節,我們延續這一節的內容,來試著撰寫布林通道突破的策略。


#加密貨幣 #Python







Related Posts

[tmp] Web Knowledge Checklist

[tmp] Web Knowledge Checklist

RegEx 妙用

RegEx 妙用

利用 JavaScript 實作簡易 TodoList

利用 JavaScript 實作簡易 TodoList


Comments