Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

唐奇安通道策略

通道策略

要講通道策略,直接看圖最快,下面是維基百科裡面的圖: img

從上圖可以看到,白色的線是股價走勢,上下有兩條黃色的線包覆中間的白色線,包圍的區間看起來就像是一個通道,所以叫做通道策略,上下兩條黃線則是稱為上下軌。

計算這兩條黃色線的方式有很多不同的方式,本篇介紹其中一種叫做唐奇安通道(Donchian Channel),唐奇安通道的上下軌計算方式為,上軌為過去一段時間內的最高價,下軌為過去一段時間內的最低價。

若股價超過上軌,可能表示多頭較強勢,所以產生買進訊號,若股價低於下軌,可能表示空頭較強勢,所以產生賣出訊號。至於這過去一段時間要採用多長的時間,會跟商品性質或是交易頻率比較有相關。

開始寫策略吧

寫唐奇安通道策略大概需要三個步驟:

  • 計算通道上下軌
  • 撰寫交易策略
  • 執行回測

計算通道上下軌

因為上下軌是用來買進賣出的指標,因此可以使用backtrader的Indicators,官網文件有非常詳細的介紹。下面程式碼是官網的範例,由於實在蠻複雜的,就一行一行來解釋:

from datetime import datetime
import yfinance as yf
import backtrader as bt


# 定義一個Indicator物件
class DonchianChannels(bt.Indicator):
    # 這個物件的別名,所以後面我們可以用DCH/DonchianChannel來呼叫這個指標
    alias = ('DCH', 'DonchianChannel',)
    
    # 三條線分別代表唐奇安通道中的 中軌(上軌加下軌再除以2)、上軌、下軌
    lines = ('dcm', 'dch', 'dcl',)  # dc middle, dc high, dc low
    
    # 軌道的計算方式:用過去20天的資料來計算,所以period是20,lookback的意思是要不要將今天的資料納入計算,由於唐奇安通道是取過去20天的最高或最低,所以一定不能涵蓋今天,不然永遠不會有訊號出現,所以要填-1(從前一天開始算20天)
    params = dict(
        period=20,
        lookback=-1,  # consider current bar or not
    )
    
    # 是否要將Indicators另外畫一張圖,然而通道線通常都是跟股價圖畫在同一張,才能看得出相對關係,所以這裡就填subplot=False
    plotinfo = dict(subplot=False)  # plot along with data
    
    # 繪圖設定,ls是line style,'--'代表虛線
    plotlines = dict(
        dcm=dict(ls='--'),  # dashed line
        dch=dict(_samecolor=True),  # use same color as prev line (dcm)
        dcl=dict(_samecolor=True),  # use same color as prev line (dch)
    )
    
    def __init__(self):
        # hi與lo是指每日股價的最高與最低價格
        hi, lo = self.data.high, self.data.low
        
        # 視需求決定是否要從前一天開始讀資料,上面已經定義lookback存在,所以這邊會直接從前一天的資料開始跑
        if self.p.lookback:  # move backwards as needed
            hi, lo = hi(self.p.lookback), lo(self.p.lookback)
        
        # 定義三條線的計算方式
        self.l.dch = bt.ind.Highest(hi, period=self.p.period)
        self.l.dcl = bt.ind.Lowest(lo, period=self.p.period)
        self.l.dcm = (self.l.dch + self.l.dcl) / 2.0  # avg of the above

撰寫交易策略

寫策略的部份就相對簡單很多,第一步把指標帶入,再來就產出訊號拉。

# 撰寫交易策略
class MyStrategy(bt.Strategy):
    def __init__(self):
        # DCH就是上面定義的 DonchianChannels的alias
        self.myind = DCH()

    def next(self):
        if self.data[0] > self.myind.dch[0]:
            self.buy()
        elif self.data[0] < self.myind.dcl[0]:
            self.sell()

執行回測

cerebro = bt.Cerebro()
cerebro.addstrategy(MyStrategy)
cerebro.broker.setcash(1000)
cerebro.broker.setcommission(commission=0.001)

data = bt.feeds.PandasData(
    dataname=yf.download("AAPL", "2019-01-01", "2019-12-31", auto_adjust=True)
)

cerebro.adddata(data)
print('Starting Value: %.2f' % cerebro.broker.getvalue())
cerebro.run()
print('Ending Value: %.2f' % cerebro.broker.getvalue())
cerebro.plot()
from datetime import datetime
import yfinance as yf
import backtrader as bt

# 定義一個Indicator物件
class DonchianChannels(bt.Indicator):
    # 這個物件的別名,所以後面我們可以用DCH/DonchianChannel來呼叫這個指標
    alias = (
        "DCH",
        "DonchianChannel",
    )

    # 三條線分別代表唐奇安通道中的 中軌(上軌加下軌再除以2)、上軌、下軌
    lines = (
        "dcm",
        "dch",
        "dcl",
    )  # dc middle, dc high, dc low

    # 軌道的計算方式:用過去20天的資料來計算,所以period是20,lookback的意思是要不要將今天的資料納入計算,由於唐奇安通道是取過去20天的最高或最低,所以一定不能涵蓋今天,不然永遠不會有訊號出現,所以要填-1(從前一天開始算20天)
    params = dict(period=20, lookback=-1,)  # consider current bar or not

    # 是否要將Indicators另外畫一張圖,然而通道線通常都是跟股價圖畫在同一張,才能看得出相對關係,所以這裡就填subplot=False
    plotinfo = dict(subplot=False)  # plot along with data

    # 繪圖設定,ls是line style,'--'代表虛線
    plotlines = dict(
        dcm=dict(ls="--"),  # dashed line
        dch=dict(_samecolor=True),  # use same color as prev line (dcm)
        dcl=dict(_samecolor=True),  # use same color as prev line (dch)
    )

    def __init__(self):
        # hi與lo是指每日股價的最高與最低價格
        hi, lo = self.data.high, self.data.low

        # 視需求決定是否要從前一天開始讀資料,上面已經定義lookback存在,所以這邊會直接從前一天的資料開始跑
        if self.p.lookback:  # move backwards as needed
            hi, lo = hi(self.p.lookback), lo(self.p.lookback)

        # 定義三條線的計算方式
        self.l.dch = bt.ind.Highest(hi, period=self.p.period)
        self.l.dcl = bt.ind.Lowest(lo, period=self.p.period)
        self.l.dcm = (self.l.dch + self.l.dcl) / 2.0  # avg of the above


# 撰寫交易策略
class MyStrategy(bt.Strategy):
    def __init__(self):
        # DCH就是上面定義的 DonchianChannels的alias
        self.myind = DCH()

    def next(self):
        if self.data[0] > self.myind.dch[0]:
            self.buy()
        elif self.data[0] < self.myind.dcl[0]:
            self.sell()


# 執行回測
cerebro = bt.Cerebro()
cerebro.addstrategy(MyStrategy)
cerebro.broker.setcash(1000)
cerebro.broker.setcommission(commission=0.001)

data = bt.feeds.PandasData(
    dataname=yf.download("AAPL", "2019-01-01", "2019-12-31", auto_adjust=True)
)

cerebro.adddata(data)
print("Starting Value: %.2f" % cerebro.broker.getvalue())
cerebro.run()
print("Ending Value: %.2f" % cerebro.broker.getvalue())
cerebro.plot()

回測2019年的結果(過去績效僅供參考,不保證未來能夠持續獲利): Starting Value: 1000.00 Ending Value: 1400.97 img

從上圖可以看得出來,因為2019年AAPL股價一直上漲的關係,很容易突破前20日的高點,導致綠色的三角形比紅色三角形多。

本篇總結 這篇就簡單的寫了一下用Backtrader回測唐奇安通道策略,又對這個框架多瞭解一些,覺得bt的功能真的超多,好用好用!