溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何利用平均趨向指數(shù)輔助MACD策略

發(fā)布時間:2021-12-31 11:58:34 來源:億速云 閱讀:96 作者:柒染 欄目:互聯(lián)網(wǎng)科技

如何利用平均趨向指數(shù)輔助MACD策略,相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。

前言

“趨勢是你的朋友”這是每一個交易者都耳熟能詳?shù)捏鹧?。但做過交易的朋友可能會有體會,趨勢總是在毫無預警地開始并突然結(jié)束。那么在CTA策略中,如何抓住趨勢并過濾震蕩行情,是許多主觀和量化交易者孜孜不倦的追求。在本節(jié)課程中,我們將以平均趨向指數(shù)(ADX)為濾網(wǎng),分析在它量化交易中的應用。

什么是平均趨向指數(shù)

平均趨向指數(shù)是衡量趨勢的技術(shù)工具,簡稱ADX(average directional indicator),它是由韋爾斯·懷爾德在1978年提出,與其他技術(shù)分析工具不同的是,ADX并不能判斷多空方向,更不能提示精確的買賣點位,它只是衡量當前趨勢的強弱。

如何利用平均趨向指數(shù)輔助MACD策略

ADX的默認周期參數(shù)是14,通常在K線圖的副圖中顯示。它的值是在0~100之間,數(shù)值越大說明上漲或下跌趨勢越強力,通常當ADX的值大于40時,說明趨勢強力,此時使用趨勢交易才具有最大的回報潛力;當ADX的值小于20時,說明趨勢疲軟,并警告交易者不要使用趨勢跟蹤交易策略。

ADX的計算方式

ADX的計算方式比較復雜,它涉及到了:價格正向移動距離(+DM)、價格負向移動距離(-DM)、真是波動幅度(TR)、正向方向性指數(shù)(+DI), 負向方向性指數(shù)(-DI)等很多中間變量:

計算動向變化

  • up:今天的最高價 – 昨天的最高價

  • down:昨天的最低價 – 今天的最低價

  • +DM:如果up大于max(down, 0),則+DM等于up,否則等于零

  • -DM:如果down大于max(up, 0),則-DM等于down,否則等于零

計算真實波幅

  • TR:max(今天最高價與今天最低價的差值,今天最高價與昨天收盤價差值的絕對值,今天最低價與昨天收盤價差值的絕對值)

計算動向指數(shù)

  • +DI(14):+DM(14)/TR(14)*100

  • -DI(14):-DM(14)/TR(14)*100

計算ADX

  • DX:((+DI14)- (-DI14)/(+DI14)+(-DI14))*100

  • ADX:MA(DX,14)

雖然ADX的計算比較復雜,但其邏輯還是比較清晰的:up和down分別代表了價格正向和負向移動距離;+DI和-DI分別代表用波動率修正后上漲和下跌趨勢。不管趨勢是上漲還是下跌,只要存在明顯的趨勢行情,那么+DI和-DI中總有一個是較大的,因此DX的值會隨著趨勢的強弱指示在0~100之間;最后ADX則是DX的14天平均線。

當+ DI高于-DI時,表明價格處于上升趨勢。 相反,當-DI高于+ DI時,價格處于下降趨勢。 交易者可以通過檢查同一時間點的ADX值來確定上升趨勢或下降趨勢的強度。

策略邏輯

在前幾節(jié)中,我們使用MACD指標創(chuàng)建了一個簡單的策略,雖然該策略在趨勢行情中表現(xiàn)還可以,但是在震蕩行情入不敷出,甚至在長期的震蕩行情中資金回撤比較大。因此我們將在本節(jié)中將之前的MACD策略加入ADX濾網(wǎng),我們來看下效果到底如何?

原策略邏輯

  • 多頭開倉:DIF大于零軸

  • 空頭開倉:DIF小于零軸

  • 多頭平倉:DIF向下突破DEA

  • 空頭平倉:DIF向上突破DEA

改進后的策略邏輯

  • 多頭開倉:DIF大于零軸,并且ADX大于20

  • 空頭開倉:DIF小于零軸,并且ADX大于20

  • 多頭平倉:DIF向下突破DEA,或者ADX下降

  • 空頭平倉:DIF向上突破DEA,或者ADX下降

我們在原策略邏輯基礎(chǔ)之上,對開倉和平倉分別加入ADX濾網(wǎng),控制在行情進入震蕩時期的開倉次數(shù)。在開倉的時候ADX的數(shù)值必須大于指定的數(shù)值;當開倉之后一旦ADX下降就平倉出局。整個策略邏輯就設(shè)計成一個嚴進寬出的模式,以此來控制震蕩時期的回撤幅度。

策略編寫

原始策略

# 回測配置
'''backtest
start: 2015-02-22 00:00:00
end: 2019-10-17 00:00:00
period: 1h
exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}]
'''


mp = 0  # 定義一個全局變量,用于控制虛擬持倉


# 判斷數(shù)組是否上升
def is_up(arr):
    arr_len = len(arr)
    if arr[arr_len - 1] > arr[arr_len - 2] and arr[arr_len - 2] > arr[arr_len - 3]:
        return True     

    
# 判斷數(shù)組是否下降
def is_down(arr):
    arr_len = len(arr)
    if arr[arr_len - 1] < arr[arr_len - 2] and arr[arr_len - 2] < arr[arr_len - 3]:
        return True

    
# 判斷兩根兩個數(shù)組是否金叉
def is_up_cross(arr1, arr2):
    if arr1[len(arr1) - 2] < arr2[len(arr2) - 2] and arr1[len(arr1) - 1] > arr2[len(arr2) - 1]:
        return True

# 判斷兩根兩個數(shù)組是否死叉
def is_down_cross(arr1, arr2):
    if arr1[len(arr1) - 2] > arr2[len(arr2) - 2] and arr1[len(arr1) - 1] < arr2[len(arr2) - 1]:
        return True    

    
# 程序主函數(shù)
def onTick():
    exchange.SetContractType("rb000")  # 訂閱期貨品種
    bar_arr = exchange.GetRecords()  # 獲取K線數(shù)組
    if len(bar_arr) < long + m + 1:  # 如果K線數(shù)組長度太小,就不能計算MACD,所以直接返回跳過
        return
    all_macd = TA.MACD(bar_arr, short, long, m)  # 計算MACD值,返回的是一個二維數(shù)組
    dif = all_macd[0]  # 獲取DIF的值,返回一個數(shù)組
    dif.pop()  # 刪除DIF數(shù)組最后一個元素
    dea = all_macd[1]  # 獲取DEA的值,返回一個數(shù)組
    dea.pop()  # 刪除DEA數(shù)組最后一個元素
    last_close = bar_arr[len(bar_arr) - 1]['Close']  # 獲取最新價格(賣價),用于開平倉
    global mp  # 全局變量,用于控制虛擬持倉
    
    # 開多單
    if mp == 0 and dif[len(dif) - 1] > 0:
        exchange.SetDirection("buy")  # 設(shè)置交易方向和類型
        exchange.Buy(last_close, 1)  # 開多單
        mp = 1  # 設(shè)置虛擬持倉的值,即有多單
    
    # 開空單
    if mp == 0 and dif[len(dif) - 1] < 0:
        exchange.SetDirection("sell")  # 設(shè)置交易方向和類型
        exchange.Sell(last_close - 1, 1)  # 開空單
        mp = -1  # 設(shè)置虛擬持倉的值,即有空單
        
    # 平多單
    if mp == 1 and is_down_cross(dif, dea):
        exchange.SetDirection("closebuy")  # 設(shè)置交易方向和類型
        exchange.Sell(last_close - 1, 1)  # 平多單
        mp = 0  # 設(shè)置虛擬持倉的值,即空倉
    
    # 平空單
    if mp == -1 and is_up_cross(dif, dea):
        exchange.SetDirection("closesell")  # 設(shè)置交易方向和類型
        exchange.Buy(last_close, 1)  # 平空單
        mp = 0  # 設(shè)置虛擬持倉的值,即空倉

        
def main():
    while True:
        onTick()
        Sleep(1000)

根據(jù)上面更改的策略邏輯,我們可以直接在原始策略的基礎(chǔ)之上把ADX濾網(wǎng)加入進去,雖然ADX的計算方法比較復雜,但可以借助talib庫只需要幾行代碼就可以把ADX的值計算出來。因為計算ADX需要用帶talib,而計算talib庫又需要用到numpy.array數(shù)據(jù)類型,所以我們需要在代碼開頭導入talib庫和numpy庫。

import talib
import numpy as np

在使用talib庫計算ADX的時候,一共需要4個參數(shù):最高價、最低價、收盤價、周期參數(shù)。所以我們還需要寫一個get_data函數(shù),這個函數(shù)的目的是從K線數(shù)組中提取出最高價、最低價、收盤價。

# 把K線數(shù)組轉(zhuǎn)換成最高價、最低價、收盤價數(shù)組,用于轉(zhuǎn)換為numpy.array類型數(shù)據(jù)
def get_data(bars):
    arr = [[], [], []]
    for i in bars:
        arr[0].append(i['High'])
        arr[1].append(i['Low'])
        arr[2].append(i['Close'])
    return arr

然后我們使用numpy庫把普通的數(shù)組轉(zhuǎn)換為numpy.array類型數(shù)據(jù),最后使用talib庫就可以計算出ADX的值,具體的寫法可以看下面代碼中的注釋:

np_arr = np.array(get_data(bar_arr)) # 把列表轉(zhuǎn)換為numpy.array類型數(shù)據(jù),用于計算ADX的值
adx = talib.ADX(np_arr[0], np_arr[1], np_arr[2], 20);  # 計算ADX的值

在策略邏輯中,需要判斷ADX的大小和是否上升下降。判斷大小很簡單,只需要把ADX具體某一天的值提取出來就可以了,跟判斷MACD一樣,我們只取倒數(shù)第二根K線的ADX值;但判斷時候上升下降則需要只取倒數(shù)第二根和第三根K線的ADX值。

adx1 = adx_arr[len(adx_arr) - 2]  # 倒數(shù)第二根K線的ADX值
adx2 = adx_arr[len(adx_arr) - 3]  # 倒數(shù)第三根K線的ADX值

最后修改下單邏輯:

# 開多單
if mp == 0 and dif[len(dif) - 1] > 0 and adx1 > 40:
    exchange.SetDirection("buy")  # 設(shè)置交易方向和類型
    exchange.Buy(last_close, 1)  # 開多單
    mp = 1  # 設(shè)置虛擬持倉的值,即有多單

# 開空單
if mp == 0 and dif[len(dif) - 1] < 0 and adx1 > 40:
    exchange.SetDirection("sell")  # 設(shè)置交易方向和類型
    exchange.Sell(last_close - 1, 1)  # 開空單
    mp = -1  # 設(shè)置虛擬持倉的值,即有空單
    
# 平多單
if mp == 1 and (is_down_cross(dif, dea) or adx1 < adx2):
    exchange.SetDirection("closebuy")  # 設(shè)置交易方向和類型
    exchange.Sell(last_close - 1, 1)  # 平多單
    mp = 0  # 設(shè)置虛擬持倉的值,即空倉

# 平空單
if mp == -1 and (is_up_cross(dif, dea) or adx1 < adx2):
    exchange.SetDirection("closesell")  # 設(shè)置交易方向和類型
    exchange.Buy(last_close, 1)  # 平空單
    mp = 0  # 設(shè)置虛擬持倉的值,即空倉

完整策略代碼

# 回測配置
'''backtest
start: 2015-02-22 00:00:00
end: 2019-10-17 00:00:00
period: 1h
exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}]
'''

# 導入庫
import talib
import numpy as np


mp = 0  # 定義一個全局變量,用于控制虛擬持倉


# 把K線數(shù)組轉(zhuǎn)換成最高價、最低價、收盤價數(shù)組,用于轉(zhuǎn)換為numpy.array類型數(shù)據(jù)
def get_data(bars):
    arr = [[], [], []]
    for i in bars:
        arr[0].append(i['High'])
        arr[1].append(i['Low'])
        arr[2].append(i['Close'])
    return arr


# 判斷兩根兩個數(shù)組是否金叉
def is_up_cross(arr1, arr2):
    if arr1[len(arr1) - 2] < arr2[len(arr2) - 2] and arr1[len(arr1) - 1] > arr2[len(arr2) - 1]:
        return True

# 判斷兩根兩個數(shù)組是否死叉
def is_down_cross(arr1, arr2):
    if arr1[len(arr1) - 2] > arr2[len(arr2) - 2] and arr1[len(arr1) - 1] < arr2[len(arr2) - 1]:
        return True    

    
# 程序主函數(shù)
def onTick():
    exchange.SetContractType("rb000")  # 訂閱期貨品種
    bar_arr = exchange.GetRecords()  # 獲取K線數(shù)組
    if len(bar_arr) < long + m + 1:  # 如果K線數(shù)組長度太小,就不能計算MACD,所以直接返回跳過
        return
    all_macd = TA.MACD(bar_arr, short, long, m)  # 計算MACD值,返回的是一個二維數(shù)組
    dif = all_macd[0]  # 獲取DIF的值,返回一個數(shù)組
    dif.pop()  # 刪除DIF數(shù)組最后一個元素
    dea = all_macd[1]  # 獲取DEA的值,返回一個數(shù)組
    dea.pop()  # 刪除DEA數(shù)組最后一個元素
    
    np_arr = np.array(get_data(bar_arr)) # 把列表轉(zhuǎn)換為numpy.array類型數(shù)據(jù),用于計算ADX的值
    adx_arr = talib.ADX(np_arr[0], np_arr[1], np_arr[2], 20);  # 計算ADX的值
    adx1 = adx_arr[len(adx_arr) - 2]  # 倒數(shù)第二根K線的ADX值
    adx2 = adx_arr[len(adx_arr) - 3]  # 倒數(shù)第三根K線的ADX值
    
    last_close = bar_arr[len(bar_arr) - 1]['Close']  # 獲取最新價格(賣價),用于開平倉
    global mp  # 全局變量,用于控制虛擬持倉
    
    # 開多單
    if mp == 0 and dif[len(dif) - 1] > 0 and adx1 > 40:
        exchange.SetDirection("buy")  # 設(shè)置交易方向和類型
        exchange.Buy(last_close, 1)  # 開多單
        mp = 1  # 設(shè)置虛擬持倉的值,即有多單
    
    # 開空單
    if mp == 0 and dif[len(dif) - 1] < 0 and adx1 > 40:
        exchange.SetDirection("sell")  # 設(shè)置交易方向和類型
        exchange.Sell(last_close - 1, 1)  # 開空單
        mp = -1  # 設(shè)置虛擬持倉的值,即有空單
        
    # 平多單
    if mp == 1 and (is_down_cross(dif, dea) or adx1 < adx2):
        exchange.SetDirection("closebuy")  # 設(shè)置交易方向和類型
        exchange.Sell(last_close - 1, 1)  # 平多單
        mp = 0  # 設(shè)置虛擬持倉的值,即空倉
    
    # 平空單
    if mp == -1 and (is_up_cross(dif, dea) or adx1 < adx2):
        exchange.SetDirection("closesell")  # 設(shè)置交易方向和類型
        exchange.Buy(last_close, 1)  # 平空單
        mp = 0  # 設(shè)置虛擬持倉的值,即空倉

        
def main():
    while True:
        onTick()
        Sleep(1000)

以上貼出本節(jié)已經(jīng)改進過的策略完整源代碼,或者你也可以到 https://www.fmz.com/strategy/174672 發(fā)明者量化官網(wǎng)的策略中復制下載,無需配置直接在線回測。

看完上述內(nèi)容,你們掌握如何利用平均趨向指數(shù)輔助MACD策略的方法了嗎?如果還想學到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI