EXCELSIOR

6. Pandas와 Plotly를 이용한 MACD 차트 그리기 본문

Python/주식 분석

6. Pandas와 Plotly를 이용한 MACD 차트 그리기

Excelsior-JH 2017. 12. 3. 18:17

Pandas와 Plotly를 이용한 MACD 차트 그리기


이전에 포스팅한 5. Pandas를 이용한 Naver금융에서 주식데이터 가져오기는 Naver금융에서 주식데이터를 수집하는 방법에 대해 알아보았다.
이번 포스팅에서는 수집한 주식 데이터를 가지고 주식 분석에서 필수 보조 지표라고 할 수 있는 MACD를 Python의 pandas 모듈을 이용하여 구현해 보도록 한다.

1. MACD 란?

MACD는 Moving Average Convergence Divergence의 약어로써, 이동평균선(MA)이 수렴과 발산을 반복한다 는 원리를 이용해 단기이동평균선(12)과 장기이동평균선(26) 사이의 관계를 보여주는 Gerald Appel이 개발한 지표다. MACD에서 단기이동평균으로는 12일, 장기이동평균으로는 26일을 사용하고, MACD의 9일 이동평균선 Signal이라고 하고, MACD와 Signal의 차이를 Oscillator라고한다.

  • MACD: 단기이동평균(12)와 장기이동평균선(26)의 차이값
    • 보통 주식HTS에서는 이값을 파라미터 값으로써 조정할 수 있게 되어있다. 우리나라 주식시장에 맞는 5일과 20일로 대체해서 사용하기도 한다.
  • Signal: MACD의 9일 이동평균값
    • 일반적으로 9일을 설정하여 MACD의 값들을 완충 및 일반화 하는 역할을 한다.
  • Oscillator: MACD값과 Signal값의 차이
    • MACD의 값이 Signal값보다 클때는 양의 막대, 작을 때는 음의 막대가 그려진다.

1) MACD 공식

  • MACD: MACD = { EMA }_{ 12 } - { EMA }_{ 26 } ({ EMA }_{ n }: n일간의 지수이동평균선)
  • Signal: Signal=\frac { \sum _{ t=1 }^{ n }{ { MACD }_{ t } } }{ n } (일반적으로 n=9로 설정)
  • Oscillator: Oscillator=MACD-Signal

2) MACD를 이용한 주식분석 - 참고 : 앤트하우스

  • MACD선이 0값을 상향돌파 할 경우: 아래의 그림처럼 MACD선이 0을 상향돌파 할 경우는 단기이동평균선이 장기이동평균선 위에 있는 정배열을 의미한다. \rightarrow 매수 포지션 (상승추세 전환)
  • MACD선이 0값을 하향돌파 할 경우: 아래의 그림처럼 MACD선이 0을 하향돌파 할 경우는 단기이동평균선이 장기이동평균선 아래에 있는 역배열을 의미한다. \rightarrow 매도 포지션 (하락추세 전환)
  • MACD선이 Signal선을 상향돌파 할 경우: Oscillator가 (+)로 전환된다. \rightarrow 매수 포지션
  • MACD선이 Signal선을 하향돌파 할 경우: Oscillator가 (-)로 전환된다. \rightarrow 매도 포지션


2. pandas를 이용해 MACD 구현하기

위의 내용에서 MACD가 무엇이며 어떻게 활용하는지에 대해 알아보았다. 이제 부터는 python pandas모듈을 이용하여 MACD를 직접 구현해 보도록 한다.

1) pandas.read_html()을 이용해 krx에서 종목코드 가져오기

네이버금융에서 원하는 종목의 주식데이터를 가져오기 위해 먼저 코스피(KOSPI)과 코스닥(KOSDAQ)의 종목코드가 필요하다. 한국거래소(krx)에서는 주식시장에 상장된 기업들에 대해 종목코드를 제공한다. pandas모듈의 pandas.read_html()을 이용해 종목코드를 가져올 수 있다. pandas.read_html()은 HTML에서 <table></table>태그를 찾아 자동으로 DataFrame형식으로 만들어준다. 아래의 소스코드를 통해 주식의 종목코드를 가져올 수 있다.

import pandas as pd

code_df = pd.read_html('http://kind.krx.co.kr/corpgeneral/corpList.do?method=download&searchType=13', header=0)[0]

# 종목코드가 6자리이기 때문에 6자리를 맞춰주기 위해 설정해줌
code_df.종목코드 = code_df.종목코드.map('{:06d}'.format)

# 우리가 필요한 것은 회사명과 종목코드이기 때문에 필요없는 column들은 제외해준다.
code_df = code_df[['회사명', '종목코드']]

# 한글로된 컬럼명을 영어로 바꿔준다.
code_df = code_df.rename(columns={'회사명': 'name', '종목코드': 'code'})
code_df.head()

head()함수를 통해 상위 5개의 코드를 확인할 수 있다.

N0.namecode
0BYC001460
1CJCGV
2CJ씨푸드011150
3DSR제강069730
4KB금융105560


2) Naver금융에서 일자별 주식데이터 가져오기

이제 네이버금융에서 원하는 종목의 일자 데이터를 가져와 보도록 하자. 여기서는 신라젠(215600) 의 일자 데이터를 가져온다. 아래의 소스코드는 특정 종목뿐만 아니라 사용자가 원하는 종목의 일자데이터를 가져올 수 있도록 get_url이라는 함수를 만들어 줬다. Naver금융에서 주식데이터를 가져오는 방법에 대해 자세히 알고 싶다면 5. Pandas를 이용한 Naver금융에서 주식데이터 가져오기를 참고하면 된다.


# 종목 이름을 입력하면 종목에 해당하는 코드를 불러와
# 네이버 금융(http://finance.naver.com)에 넣어줌
def get_url(item_name, code_df):
    code = code_df.query("name=='{}'".format(item_name))['code'].to_string(index=False)
    url = 'http://finance.naver.com/item/sise_day.nhn?code={code}'.format(code=code)
    
    print("요청 URL = {}".format(url))
    return url
    

# 신라젠의 일자데이터 url 가져오기
item_name='신라젠'
url = get_url(item_name, code_df)

# 일자 데이터를 담을 df라는 DataFrame 정의
df = pd.DataFrame()

# 1페이지에서 20페이지의 데이터만 가져오기
for page in range(1, 21):
    pg_url = '{url}&page={page}'.format(url=url, page=page)
    df = df.append(pd.read_html(pg_url, header=0)[0], ignore_index=True)

# df.dropna()를 이용해 결측값 있는 행 제거
df = df.dropna()

# 상위 5개 데이터 확인하기
df.head()

아래의 소스코드는 추후에 데이터 분석에서 편하게 하기위해 추가적으로 처리해 준 코드이다.

# 한글로 된 컬럼명을 영어로 바꿔줌
df = df.rename(columns= {'날짜': 'date', '종가': 'close', '전일비': 'diff', 
                         '시가': 'open', '고가': 'high', '저가': 'low', '거래량': 'volume'})

# 데이터의 타입을 int형으로 바꿔줌
df[['close', 'diff', 'open', 'high', 'low', 'volume']] \
    = df[['close', 'diff', 'open', 'high', 'low', 'volume']].astype(int)

# 컬럼명 'date'의 타입을 date로 바꿔줌
df['date'] = pd.to_datetime(df['date'])

# 일자(date)를 기준으로 오름차순 정렬
df = df.sort_values(by=['date'], ascending=True)

# 상위 5개 데이터 확인
df.head()


3) MACD 지표 구현하기

MACD를 구현하기 위해 필요한 데이터들을 수집하였으면, 이제 MACD를 구현해보도록 한다. 아래의 소스코드는 MACD를 get_macd()라는 함수로 구현하였다.
입력값으로 DataFrame, 단기(short=12), 장기(long=26), Signal을 구할때 사용할 일자(t=9)를 입력값으로 받으며, MACD 지표들이 추가된 DataFrame을 리턴(return)해준다.

def get_macd(df, short=12, long=26, t=9):
    
    # 입력받은 값이 dataframe이라는 것을 정의해줌
    df = pd.DataFrame(df)
    
    # MACD 관련 수식
    ma_12 = df.close.ewm(span=12).mean() # 단기(12) EMA(지수이동평균)
    ma_26 = df.close.ewm(span=26).mean() # 장기(26) EMA
    macd = ma_12 - ma_26 # MACD
    macds = macd.ewm(span=9).mean() # Signal
    macdo = macd - macds # Oscillator

    df = df.assign(macd=macd, macds=macds, macdo=macdo).dropna()
    
    return df

위의 코드에서 구현한 get_macd()를 이용해 아래의 코드를 입력하면 DataFrame에 macd의 지표 macd, macds, macdo 가 포함되어 있는것을 확인할 수 있다.

df = get_macd(df)
# 상위 5개 데이터 확인
df.head()


3. plotly를 이용해 MACD 차트 그리기

마지막으로 plotly를 이용하여 MACD 차트를 그려보도록 한다. plotly에 대한 설명은 이전 포스팅인 4. Plotly를 이용한 캔들차트-Candlestick chart 그리기를 참고하면 된다.
아래의 소스코드를 통해 MACD 차트를 그릴 수 있다.

from plotly import tools
import plotly.offline as offline 
import plotly.graph_objs as go

macd = go.Scatter(
                x=df.date,
                y=df['macd'],
                name="MACD")

signal = go.Scatter(
                x=df.date,
                y=df['macds'],
                name="Signal")

oscillator = go.Bar(
                x=df.date,
                y=df['macdo'],
                name="oscillator")

trade_volume = go.Bar(
                x=df.date,
                y=df['volume'],
                name="volume")


data = [macd, signal, oscillator]

# data = [celltrion]
layout = go.Layout(title='{} MACD 그래프'.format(item_name))

fig = tools.make_subplots(rows=2, cols=1, shared_xaxes=True)

for trace in data:
    fig.append_trace(trace, 1,1)

fig.append_trace(trade_volume, 2,1)
# fig = go.Figure(data=data, layout=layout)

offline.iplot(fig)


Comments