Coding Is My Life

코딩은 인생

파이썬

[파이썬][보조지표 MACD를 활용한 코스피 200 종목 분석]

산기대 컴공 2021. 9. 18. 22:46
728x90

MACD란?

MACD 곡선 = 단기지수이동평균-장기지수이동평균

Signal 곡선 = n일의 MACD 지수이동평균

 

보통 단기지수이동평균는 12일 장기지수이동평균은 26일을 사용한다. 그리고 Signal곡선의 n은 9일을 일반적으로 사용한다.

분석 내용

이번 분석에서는 차트 분석에서 자주 언급이 되는 MACD에 대한 매매를 분석할 것이다.

-MACD 곡선이 Signal 곡선을 상향 돌파시 : 매수  

-MACD 곡선이 Signal 곡선을 하향 돌파시 : 매도

위 두 내용을 가지고 코스피 200 종목들을 크롤링해서 백테스팅해서 각 종목에 대한 수익률을 분석 할 것이다.

개발환경은 Google colab를 이용하였다

코드

# 사용할 라이브러리
!pip install yfinance
import pandas as pd
import matplotlib.pyplot as plt
import bs4
import yfinance as yf
from urllib.request import urlopen
# 종목코드 불러오기
stock_code = pd.read_html('http://kind.krx.co.kr/corpgeneral/corpList.do?method=download', header=0)[0]
stock_code = stock_code[['회사명','종목코드']]
# rename(columns = {'원래 이름' : '바꿀 이름'}) 칼럼 이름 바꾸기
stock_code = stock_code.rename(columns = {'회사명':'company','종목코드':'code'})
# 종목코드가 6자리이기 때문에 6자리를 맞춰주기 위해 설정해줌 
stock_code.code = stock_code.code.map('{:06d}'.format) #6자리가 아닌 수를 앞에 0으로 채우기 위함
stock_code.tail(3)

http://kind.krx.co.kr/corpgeneral/corpList.do?method=download에서 read_html를 사용하여 상장되어있는 기업들의 정보를 가져왔다.

 

stock_code.code = stock_code.code.map('{:06d}'.format) #6자리가 아닌 수를 앞에 0으로 채우기 위함 

기업 정보중 종목코드에서 6자리가 아닌 수에 대해서 앞에 0을 채워주는 작업, 종목코드는 모두 6자리로 통일되어있기 때문에(나중에 크롤링 할때)

# 코스피 200 종목의 이름을 웹 크롤링함
import bs4
from urllib.request import urlopen # url의 소스코드를 긁어오는 기능
company_name = []
for i in range(1,21):
  page = i
  url = 'https://finance.naver.com/sise/entryJongmok.nhn?&page={page}'.format(page = page)
  source = urlopen(url).read()
  source = bs4.BeautifulSoup(source,'lxml')
  source = source.find_all('a',target = '_parent')
  for j in range(len(source)):
    name = source[j].text
    company_name.append(name)

https://finance.naver.com/sise/sise_index.naver?code=KPI200에서 편입종목 상위부분의 이름 부분을 크롤링해왔다. 

code = []
for i in company_name:
  for j in range(len(stock_code)):
    if stock_code['company'][j] == i:
      code.append(stock_code['code'][j])
      break

상장종목중에 코스피 200에 속하는 종목의 종목코드를 가져왔다.

 

백테스팅 함수

def buy(money,Average_cost,amount,price):
  amount = money/price
  money = money%price
  Average_cost = price
  return money,Average_cost,amount
def sell(money,Average_cost,amount,price):
  money = price*amount
  amount = 0
  Average_cost = 0
  return money,Average_cost,amount
def backtesting(code):
  data = yf.download(code)
  data = data[-224:]
  data['ma12'] = data['Close'].ewm(span = 12).mean()
  data['ma26'] = data['Close'].ewm(span = 26).mean()
  data['MACD'] = data['ma12']-data['ma26']
  data['signal'] = data['MACD'].ewm(span = 9).mean()
  money,Average_cost,amount = 1000000,0,0
  marker = []
  for i in range(1,len(data)):
    if data['MACD'][i-1]<data['signal'][i-1] and data['MACD'][i]>=data['signal'][i]:
      if amount == 0:
        money,Average_cost,amount = buy(money,Average_cost,amount,data['Close'][i])
        line = []
        line.append(data.index[i])
        line.append(i)
        marker.append(line)
    if amount != 0:
      if data['MACD'][i-1]>data['signal'][i-1] and data['MACD'][i]<=data['signal'][i]:
        money,Average_cost,amount = sell(money,Average_cost,amount,data['Close'][i])
        line = []
        line.append(data.index[i])
        line.append(i)
        marker.append(line)
  '''
  fig = plt.figure(figsize = (30,8))
  fig = plt.plot(data['Close'])
  for i in range(0,len(marker)-1,2):
    start = marker[i]
    end = marker[i+1]
    if data['Close'][start[1]]<data['Close'][end[1]]:
      fig = plt.axvspan(start[0],end[0],color = 'blue',alpha = 0.1)
    else:
      fig = plt.axvspan(start[0],end[0],color = 'red',alpha = 0.1)

  plt.legend()
  fig2 = plt.figure(figsize = (30,3))
  fig2 = plt.plot(data['MACD'],label = 'gray')
  fig2 = plt.plot(data['signal'],label = 'orange')
  fig2 = plt.legend()
  '''
  print("초기 자산 : 1000000, 남은 자산 :",money+Average_cost*amount)
  print("수익률 :",round(((money+(Average_cost*amount))-1000000)/1000000*100,2),"%")
  return round(((money+(Average_cost*amount))-1000000)/1000000*100,2)

백테스팅 라이브러리도 있었으나 별로 어려울것 같지 않고 유연하게 수정하기 위해서 직접 만들어 보았다.

주석 처리가된 부분은 매수 매도 시점을 그래프로 표현한 부분이다. 개별적으로 한 종목씩 분석할때 사용했으나 코스피 200종목을 분석하는데 일일이 그래프를 보지 않고 처리하는 속도도 느려지기 떄문에 코스피 200종목을 전부 백테스팅할 때는 사용하지 않았다. 코드는 굉장히 간단하다. 상향 돌파시 매수,하향 돌파시 매도 그리고 buy,sell 함수를 만들어서 사고팔때 변수들을 계속 업데이트했다.

 결과

수익률은 다음과 같았다.

-55, -47, -36, -34, -32, -32, -30, -29, -28, -27, -26, -26, -24, -24, -22, -21, -20, -16, -16, -15, -14, -14, -14, -13, -13, -13, -12, -6, -6, -5, -5, -5, -5, -4, -4, -4, -3, -3, -2, -1, -1, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 16, 17, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, 21, 21, 22, 23, 24, 24, 24, 25, 25, 25, 26, 26, 27, 28, 28, 29, 29, 31, 32, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 39, 39, 41, 41, 41, 42, 42, 43, 44, 44, 44, 45, 45, 46, 47, 48, 48, 48, 48, 48, 49, 51, 56, 57, 59, 59, 60, 62, 64, 65, 66, 69, 69, 69, 70, 75, 75, 81, 84, 86, 86, 93, 105, 112, 113, 129, 130, 138, 187, 254, 285,

 

손실 : 44종목

수익 : 56종목

결과는 참담했다. 보조지표 하나만 가지고는 좋은 수익률을 내지 못한다. 물론 분할 매수,분할 매도가 아닌 몰빵 전략이라서 그런 걸 수도 있지만 개별적으로 하나씩 차트를 분석한 결과 좋은 매수 타점들은 아니였다. 다른 보조지표들과 기법들을 고려해서 다시 한번해봐야겠다.

728x90