熟悉股市的朋友,肯定了解 MACD 這個指標。當然,更多人了解的是一些通用的規則 MACD 金叉,即 DIFF 由下向上突破 DEA,為買入信號; MACD 死叉,即 DIFF 由上向下突破 DEA,為賣出信號……作為一個量化人員,不但要知道這些,而且需要知道緣由和具體的應用。今天這一期,主講 MACD。
MACD,全名是moving average convergence/divergence,中文簡稱平滑異同移動平均線,或移動平均聚散指標,或指數平滑移動平均線。(還是簡稱比較好記啊!)它是 Geral Appel 於 1979 年提出的指標,運用快速(短期)和慢速(長期)移動平均線及其聚合與分離的征兆,加以雙重平滑運算。而根據移動平均線原理發展出來的 MACD,一則去除了移動平均線頻繁發出假信號的缺陷,二則保留了移動平均線的最大效果。因此,MACD 指標具有均線趨勢性、穩重性、安定性等特點,是用來研判買賣股票的時機,預測股票價格漲跌的技術分析指標 。“快”指短時期的 EMA(EMA,全稱 Exponential Moving Average,中文簡稱指數移動平均),而“慢”則指長時期的 EMA。具體計算公式如下:
(1) 首先,計算 EMA 的平滑系數平滑系數=2÷(周期單位數+1 )如:12 日 EMA 的平滑系數=2÷(12+1)=0.1538;
26 日 EMA 平滑系數為=2÷27=0.0741
(2) 然后,計算指數平均值(EMA)
今天的指數平均值=平滑系數×(今天收盤指數-昨天的指數平均值)+昨天的指數平均值。
依公式可計算出 12 日 EMA:
12 日 EMA=2÷13×(今天收盤指數一昨天的指數平均值)+昨天的指數平均值。
=(2÷13)×今天收盤指數+(11÷13)×昨天的指數平均值。
同理,26 日 EMA 亦可計算出:
26 日 EMA=(2÷27)×今天收盤指數+(25÷27)×昨天的指數平均值。
(3) 計算離差值(DIF)
DIF=今日 EMA(12)-今日 EMA(26)
(4) 最后,計算 DIF 的 9 日 EMA
根據離差值計算其 9 日的 EMA,即離差平均值,是所求的 MACD 值。為了不與指標原名相混淆,此值又名 DEA 或 DEM(有時會成為 signal)。計算出的 DIF 和 DEA 的數值均為正值或負值。
今日 DEA =前一日 DEA×8/10+今日 DIF×2/10
為何是 12 日,26 日,9 日呢?因為 12 日和 26 日,剛好可以包好 2 周和 1 個月的數據。考慮到現在的交易日為 5 日,那為何不是 10 日,22 日,8 日呢?這個我真的不好解釋了,我倒是搜到了一篇 paper 關於這個日期設置的問題,參考:http://www.forexabode.com/forexschool/technical-indicators/macd/。文章指出日期的設置有一定歷史問題,同時沿用至今有很多事實依據證實日期選擇的合理性和可靠性。既然如此,我們也遵循 12 日,26 日和 9 日的日期設定。一般情況下,我們不僅能看到 DIF 和 DEA 這兩條不同顏色的曲線,還能看到紅綠的柱狀圖。其實,柱狀圖是 MACD,其中 MACD =(DIF-DEA)*2,通常繪制成圍繞零軸線波動的柱形圖,紅色代表 DIF 大於 DEA,綠色代表 DIF 小於 DEA。
MACD 的運用有如下基本原則:
1.DIF、DEA 均為正,DIF 向上突破 DEA,買入信號參考。
2.DIF、DEA 均為負,DIF 向下跌破 DEA,賣出信號參考。
3.DIF 線與 K 線發生背離,行情可能出現反轉信號。
4.DIF、DEA 的值從正數變成負數,或者從負數變成正數並不是交易信號,因為它們落后於市場。
簡單地對應市場上的說法如下:
- MACD 金叉: DIF 由下向上突破 DEA,為買入信號。
- MACD 死叉: DIF 由上向下突破 DEA,為賣出信號。
針對這兩條的說法,我需要提出 MACD 具有一定的滯后情況,即比市場的反應要慢。因為 MACD 是一個中長期的指標,而不是個短期指標,不適合短期漲跌浮動太大的證券。
接下來,3 種說法更靠譜些:
3. MACD 柱狀圖為紅,即 DIF 與 DEA 均為正值,即都在零軸線以上時,市場趨勢屬多頭市場,若此時 DIF 向上繼續突破 DEA,即紅色柱狀越來越長,可作買入信號,該出手就出手。
4. MACD 柱狀圖為綠,即 DIF 與 DEA 均為負值,即都在零軸線以下時,市場趨勢屬空頭市場,若此時 DIF 向下繼續跌破 DEA,即綠色柱狀越來越長,可作賣出信號,該割肉就割肉。
5. 當 DEA 線與 K 線趨勢發生背離時為反轉信號。
下面,我用 python 程序調用 baostock(baostock 是免費證券數據的 python 接口,具體信息參考:www.baostock.com)實現 MACD 計算,MACD 金叉和死叉提示的功能。
import baostock as bs
import pandas as pd
import talib as ta
import matplotlib.pyplot as plt
def computeMACD(code, startdate, enddate):
login_result = bs.login(user_id='anonymous', password='123456')
print(login_result)
# 獲取股票日 K 線數據
rs = bs.query_history_k_data(code,
"date,code,close,tradeStatus",
start_date=startdate,
end_date=enddate,
frequency="d", adjustflag="3")
# 打印結果集
result_list = []
while (rs.error_code == '0') & rs.next():
# 獲取一條記錄,將記錄合並在一起
result_list.append(rs.get_row_data())
df = pd.DataFrame(result_list, columns=rs.fields)
# 剔除停盤數據
df2 = df[df['tradeStatus'] == '1']
# 獲取 dif,dea,hist,它們的數據類似是 tuple,且跟 df2 的 date 日期一一對應
# 記住了 dif,dea,hist 前 33 個為 Nan,所以推薦用於計算的數據量一般為你所求日期之間數據量的 3 倍
# 這里計算的 hist 就是 dif-dea,而很多證券商計算的 MACD=hist*2=(difdea)*2
dif, dea, hist = ta.MACD(df2['close'].astype(float).values, fastperiod=12, slowperiod=26, signalperiod=9)
df3 = pd.DataFrame({'dif': dif[33:], 'dea': dea[33:], 'hist':hist[33:]},index=df2['date'][33:], columns=['dif', 'dea','hist'])
df3.plot(title='MACD')
plt.show()
# 尋找 MACD 金叉和死叉
datenumber = int(df3.shape[0])
for i in range(datenumber - 1):
if ((df3.iloc[i, 0] <= df3.iloc[i, 1]) & (df3.iloc[i + 1, 0] >= df3.iloc[i + 1, 1])):
print("MACD 金叉的日期:" + df3.index[i + 1])
if ((df3.iloc[i, 0] >= df3.iloc[i, 1]) & (df3.iloc[i + 1, 0] <=df3.iloc[i + 1, 1])):
print("MACD 死叉的日期:" + df3.index[i + 1])
bs.logout()
return (dif, dea, hist)
if __name__ == '__main__':
code = 'sh.600000'
startdate = '2017-03-01'
enddate = '2017-12-01'
(dif, dea, hist) = computeMACD(code, startdate, enddate)
運行結果如下:
MACD 金叉的日期:2017-05-02
MACD 死叉的日期:2017-05-09
MACD 金叉的日期:2017-05-12
MACD 死叉的日期:2017-05-25
MACD 金叉的日期:2017-06-21
MACD 死叉的日期:2017-08-03
MACD 金叉的日期:2017-08-28
MACD 死叉的日期:2017-09-27
MACD 金叉的日期:2017-10-09
MACD 死叉的日期:2017-10-23
MACD 金叉的日期:2017-11-13
MACD 死叉的日期:2017-11-16
MACD 金叉的日期:2017-11-17
觀看代碼可知,我通過 TA-LIB 計算出 MACD 線,並且畫折線圖,打印出 MACD 金叉和死叉的提示日期。
在這里,需要注意以下幾點:
1.TA-LIB 計 算 MACD,結果的前 33 個值為 NAN;
2.輸入的數據量盡量足夠大(推薦是你真實計算 MACD 的數據量的 3 倍),例如,你需要計算 2017-04-01 到 2017-05-01 的 MACD,那么你需要輸入的數據日期應該是 2017-0201 到 2017-05-01;3.MACD 的金叉和死叉提示日期可能在真實金叉和死叉日期之后,也就是可能會延后一日。至於利用 MACD 進行交易的具體策略實現,是要依靠你們自己。
網上有很多很多關於利用 MACD 的買賣策略,我只是提醒一下真正靠譜實用的策略一般不會公開(別人不會將賺錢的方法告訴你),而那些公開的策略一般都不怎么能賺錢,重要 的是你自己不斷摸索出屬於你自己對市場和個股的判斷方法。正所謂“臨淵羡魚,不如退而結網”。
以上轉自博客XXX
以下轉自博客:https://blog.csdn.net/chenxiao17301/article/details/100143614
具體內容看博客就行了,這里copy一份python的計算代碼
def calculateEMA(period, closeArray, emaArray=[]):
length = len(closeArray)
nanCounter = np.count_nonzero(np.isnan(closeArray))
if not emaArray:
emaArray.extend(np.tile([np.nan], (nanCounter + period - 1)))
firstema = np.mean(closeArray[nanCounter:nanCounter + period - 1])
emaArray.append(firstema)
for i in range(nanCounter + period, length):
ema = (2 * closeArray[i] + (period - 1) * emaArray[-1]) / (period + 1)
emaArray.append(ema)
return np.array(emaArray)
def calculateMACD(closeArray, shortPeriod=12, longPeriod=26, signalPeriod=9):
ema12 = calculateEMA(shortPeriod, closeArray, [])
ema26 = calculateEMA(longPeriod, closeArray, [])
diff = ema12 - ema26
dea = calculateEMA(signalPeriod, diff, [])
macd = (diff - dea)*2
fast_values = diff # 快線
slow_values = dea # 慢線
diff_values = macd # macd
# return fast_values, slow_values, diff_values # 返回所有的快慢線和macd值
return fast_values[-1], slow_values[-1], diff_values[-1] # 返回最新的快慢線和macd值
# return round(fast_values[-1],5), round(slow_values[-1],5), round(diff_values[-1],5)
def getMACD():
data = RequestUtil.sendRequest_GET(UrlConstant.Get_K_Line)
closeArray = [float(i[4]) for i in data]
closeArray.reverse()
return calculateMACD(closeArray)