본문 바로가기
개발일지

파이썬 투자 보조 지표 분석 / 전략 설계 - MACD

by kirion 2022. 11. 24.
728x90
반응형

투자 보조 지표 MACD

MACD

MACD란 단순 이동평균선은 추세 전환 신호가 늦게 나타난다는 단점을 해결하기 위해 나온 것이다. MACD는 추세전환 시점을 찾는 것보다는 추세 방향과 주가 움직임을 분석하는데 좋은 지표라 알려져 있다. 

MACD Oscillator란 MACD곡석과 Signal 곡선의 차이를 막대로 나타낸 것. 0을 중심으로 차이가 클 수 록 매수, 매도세가 강함을 의미한다..

MACD 계산방법

MACD : 단기 지수이동 평균(12일) - 장기 지수 이동 평균(26일)

Signal : N일의 MACD 지수이동평균(9일)

MACD Oscillator : MACD - Signal

해석

단기 이동평균 선이 장기 이동평균선으로 회귀하려는 특성을 활용해 표현한 지표이다. 

MACD선과 Signal선이 크로스를 이루는 시점도 추세를 파악하기에 좋다.

 

전략

  • MACD선이 Signal선을 상향 돌파(골든크로스) - 상승추세 전환
  • MACD선이 Signal선을 하향 돌파(데드크로스) - 하락추세 전환
  • MACD Oscillator 막대의 최하점 - 매수시점
  • MACD Oscillator 막대의 최고점 - 매도시점

고점 저점 신호 분석(다이버전스)

  • 주가 상승, MACD 하락 : 고점
  • 주가 하락, MACD 상승 : 저점

파이썬 구현

import ta
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import FinanceDataReader as fdr
import copy
df_krx = fdr.StockListing('KRX')

kospi_data = df_krx[(df_krx["Market"]=="KOSPI") & (~df_krx["Sector"].isna())]

target = kospi_data[kospi_data["Name"]=="KT&G"]

price_data = fdr.DataReader("033780","2020","2022-11-17")

언제나처럼 KT&G를 대상으로 구현해보자.

 

macd = ta.trend.MACD(price_data['Close']).macd()
macd_signal = ta.trend.MACD(price_data['Close']).macd_signal()
macd_o = macd - macd_signal

ta 패키지에 macd 계산하는 함수가 있다. 계산 방식이 워낙 간단해서 패키지를 안 쓰고도 구현 가능하다.

 

macd = price_data['Close'].ewm(span = 12).mean() - price_data['Close'].ewm(span = 26).mean()
macd_signal = macd.ewm(span= 9).mean()
macd_o = macd - macd_signal

지수이동 평균으로 계산하면 위와 같다. ta 패키지로 계산한 값과 똑같은 값이 나온다.

 

 

 

macd, macd signal, macd oscillator를 같은 그래프에 그려보자.

두 가지 방식이 있다. x축의 날짜를 살려서 그리는 것과, 주말의 공백이 있어 bar그래프의 표현이 이상한 경우 index를 숫자로 바꿔서 촘촘하게 그리는 방법이 있다. 

보기에 편한 대로 시각화하면 된다.

 

price_data_tmp = price_data[price_data.index>"2022"].copy()

fig, ax1 = plt.subplots(figsize = (14,7)) 
ax1.set_ylabel('Price') 
ax1.plot(price_data_tmp["Close"],color = "black",alpha = 0.7)
ax2 = ax1.twinx() 
ax2.set_ylabel('Index') 

ax2.plot(price_data_tmp["macd"],color = "blue",alpha = 0.5)
ax2.plot(price_data_tmp["macd_sig"],color = "red",alpha = 0.5)
ax2.bar(price_data_tmp.index,price_data_tmp["macd_o"],color = "red",alpha = 0.5)
ax2.legend(["macd","macd_sig","macd_o"],loc = "upper left")
plt.title(target["Name"].values[0])

plt.show()

price_data_tmp["row_index"] = np.arange(0,price_data_tmp.shape[0],1)
price_data_tmp.reset_index(drop=True,inplace=True)

fig, ax1 = plt.subplots(figsize = (14,7)) 
ax1.set_ylabel('Price') 
ax1.plot(price_data_tmp["Close"],color = "black",alpha = 0.7)
ax2 = ax1.twinx() 
ax2.set_ylabel('Index') 

ax2.plot(price_data_tmp["macd"],color = "blue",alpha = 0.5)
ax2.plot(price_data_tmp["macd_sig"],color = "red",alpha = 0.5)
ax2.bar(price_data_tmp.index,price_data_tmp["macd_o"],color = "red",alpha = 0.5)
ax2.legend(["macd","macd_sig","macd_o"],loc = "upper left")
plt.title(target["Name"].values[0])

plt.show()

macd가 signal선을 돌파하는 지점이 여러 보인다. 조회하는 종목이 지속 상승하고 있어 macd지표가 매력적으로 보이는 듯싶다.

 

macd지표도 천정과 바닥이 없어 벡테스팅을 돌려보기 어렵다. 자동으로 테스트해보기 위해 단순히 0선 돌파, oscillator 0 돌파 등의 방법을 적용해 볼 수 있겠지만, 결국 추세를 따라가지 못한다는 단점 때문에 정확한 테스트가 어려워 보인다.

 

그나저나.. KT&G의 랠리는 언제까지 이어질까. 주가가 계속 오르는데 Oscillator는 음수이다. 오실레이터가 음수라는 것은 저점 쪽에 가깝다고 하는데.. 

 


한 가지 아이디어를 낸 것이 MACD Oscillator를 수정지표이다. Oscillator가 12일 선과 26일 선의 차이를 나타내는 것이데, 이 차이값을 이용해 RSI처럼 0~100사이로 계량해보면 어떨까 싶다.

delta = price_data["Close"].diff()
price_data_tmp = price_data[price_data.index>"2022"]
price_data_tmp.reset_index(drop = True, inplace = True)

delta = price_data_tmp["Close"].diff()

fig, ax1 = plt.subplots(figsize = (14,7)) 
ax1.set_ylabel('Index') 

ax1.bar(price_data_tmp.index,delta,color = "red",alpha = 0.5)
ax1.bar(price_data_tmp.index,price_data_tmp["macd_o"],color = "blue",alpha = 0.5)
ax1.legend(["Close_diff","Macd_O"],loc = "upper left")
plt.title(target["Name"].values[0])
plt.show()

종가 차이와 Oscillator

RSI를 계산하기 위한 기초 값이 당일 종가와 전일 종가의 차이 값이다. 

마찬가지로 오실레이터도 12일선과 26일선의 차이 값이라는 점에 착안해 계산을 위한 기초 값을 오실레이터를 사용해 0~100사이로 만들어봤다.

 

delta = price_data["macd_o"]
ups, downs = delta.copy(),delta.copy()
period = 14
ups[ups < 0] = 0 
downs[downs > 0] = 0 
AU = ups.ewm(com = period-1, min_periods = period).mean() 
AD = downs.abs().ewm(com = period-1, min_periods = period).mean()
MACD_OI = 100 - (100/(1 + AU/AD))

RSI와 계산식은 동일하다. 기초값만 Macd Oscillator로 바뀐다고 생각하면 된다.

 

fig, ax1 = plt.subplots(figsize = (14,7)) 
ax1.set_ylabel('Price') 
ax1.plot(price_data["Close"],color = "black",alpha = 0.7)

ax2 = ax1.twinx() 
ax2.set_ylabel('Index') 
ax2.plot(price_data["rsi"],color = "red",alpha = 0.5)
ax2.plot(price_data["MACD_OI"],color = "blue",alpha = 0.5)
ax2.plot(price_data["lower"],alpha = 0.5)
ax2.plot(price_data["upper"],alpha = 0.5)
ax2.legend(["rsi","macd_oi"],loc = "upper left")
plt.title(target["Name"].values[0])
plt.show()

RSI, MACD_OI

RSI와 비교해 추세가 좀 더 명확하게 나타난다. 지수이동평균으로 완만한 곡선이된 값을 사용해서 더 완만하게 표현된 것 같다. 매매 시그널의 주기가 짧지만 포인트를 잘 잡는 것 같다. 

fig, ax1 = plt.subplots(figsize = (14,7)) 
ax1.set_ylabel('MACD_O_Index') 
ax1.plot(price_data["MACD_OI"],color = "blue",alpha = 0.5)
ax1.legend(["MACD_O_index"],loc = "upper right")

ax2 = ax1.twinx() 
ax2.set_ylabel('MACD_O') 
ax2.bar(price_data.index,price_data["macd_o"],color = "black",alpha = 0.5)
ax2.legend(["macd_o"],loc = "upper left")
plt.title(target["Name"].values[0])

plt.show()

MACD_OI, MACD_O

MACD 오실레이터와 비교해도 의미하는 바를 명확하게 알 수 있다. 생각보다 괜찮은 지표가 만들어 진 것 같다.

 

벡테스팅하기에는 신호가 자주 조는 것 같아서 80, 20선을 기준으로 일 별 매매 시그널을 뽑아봤다.

2022.11.15 - [개발일지] - 8. 투자지표를 활용한 매매 시점 모니터링 - 전략 설계 참고

관련 글은 위의 글을 참고하면 된다.

 

매매 시그널 합계
매수
매도

일 별 매매 시그널 총합과 TIGER KOSPI와 비교한 그래프이다. 

매수와 매도 시그널 횟수가 비슷하다. 또한 시그널이 꽤 빈번하게 발생하는 것을 볼 수 있다. 매매 기준선을 조정해야할 것 같다. 주가 하락 전에 매수 신호가 강하게 난 시점이 있는데(22년6월) 그 후 주가가 내려간다. 너무 완화된 조건(80,20)으로 설정해서 거짓된 매수 신호가 많이 나온 것 같다. 다른 지표와 동시에 쓰면 좋을 것이다. 

MADC_O의 개량 지표도 활용 가능성을 확인했으니 참고해봐야겠다.

 

728x90
반응형

댓글