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종목
결과는 참담했다. 보조지표 하나만 가지고는 좋은 수익률을 내지 못한다. 물론 분할 매수,분할 매도가 아닌 몰빵 전략이라서 그런 걸 수도 있지만 개별적으로 하나씩 차트를 분석한 결과 좋은 매수 타점들은 아니였다. 다른 보조지표들과 기법들을 고려해서 다시 한번해봐야겠다.
'파이썬' 카테고리의 다른 글
[Django Project][community 만들기 - 가상환경 설정하기] (0) | 2021.12.12 |
---|---|
[파이썬][보조지표 envelope로 업비트 코인 분석] (3) | 2021.10.13 |
[파이썬][보조지표 envelope를 이용한 코스피 200종목 분석] (0) | 2021.09.18 |
파이썬- 여러개 입력받기 (0) | 2020.10.10 |
파이썬- 리스트 정렬하기 (0) | 2020.10.10 |