Coding Is My Life

코딩은 인생

파이썬

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

산기대 컴공 2021. 9. 18. 23:26
728x90

Envelope란?

n일의 이동평균선에 +m%,-m%를 뜻한다.

 

분석 내용

보통 20일 이동평균선을 사용하고 m은 트레이더의 성향에 따라 많이 다르나 가장 보편적으로 사용되는 10으로 두고 분석해보겠다.

하향 envelope선에 돌파 또는 지지할시 매수 하고 m%만큼 떨어지면 손절, m%만큼 상승하면 익절하도록 세팅해 두었다.

 

 

  코드

!pip install yfinance
import pandas as pd
import matplotlib.pyplot as plt
import bs4
import yfinance as yf
from urllib.request import urlopen # url의 소스코드를 긁어오는 기능

필요한 라이브러리들을 불러와 줬다.

 

# 종목코드 불러오기
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)

상장된 기업정보들을 크롤링 해주었다.

 

# 코스피 200 종목의 이름을 웹 크롤링함
import bs4
from urllib.request import urlopen # url의 소스코드를 긁어오는 기능
#//*[@id="tab_con1"]/div[3]/table/tbody/tr[1]/td/span[1]/em
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)

네이버 금융에서 코스피 200종목들의 이름을 크롤링 하였다. 크롤링하는 방법은 블로그 글에 자세하게 나와있다.

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
code

코스피 200종목들의 종목코드들을 불러왔다.

def envelope(N,ma): #엔벨로프 설정 함수 
  idx = ma.index
  plus = {}
  minus = {}
  for i in range(len(ma)):
    plus[idx[i]] = ma[i]+((ma[i]*N)/100)
    minus[idx[i]] = ma[i]-((ma[i]*N)/100)
  return plus,minus

ma 이동평균선만큼 N의 엔벨로프선을 만드는 함수이다.

 

벡테스팅 함수

# 벡테스팅 함수
import yfinance as yf
import matplotlib.pyplot as plt
def buy(price,cash,finance,Average_price):
  finance = cash/price
  Average_price  = price
  cash = cash%price
  return cash,finance,Average_price
def sell(price,cash,finance,Average_price):
  cash = finance*price+cash
  finance = 0
  Average_price = 0
  return cash,finance,Average_price
def backtesting(code,cash,N,min_percent):
  start_cash = cash
  finance = 0
  Average_price = 0
  data = yf.download(code)
  ma20 = data['Adj Close'].rolling(window = 20).mean()
  ma60 = data['Adj Close'].rolling(window = 60).mean()
  ma112 = data['Adj Close'].rolling(window = 112).mean()
  marker_buy = []
  marker_sell = []
  marker = []
  plus,minus = envelope(N,ma20)
  plus = pd.Series(plus)
  minus = pd.Series(minus)
  for i in range(1,len(data)):
    if data['Adj Close'][i-1]>minus[i-1] and data['Adj Close'][i]<=minus[i]:
      if finance == 0:
        cash,finance,Average_price = buy(data['Adj Close'][i],cash,finance,Average_price)
        line = []
        line.append(data.index[i])
        line.append(i)
        marker.append(line)
    if finance != 0 and Average_price+((Average_price*N)/100) <= data['Adj Close'][i]:
      cash,finance,Average_price = sell(data['Adj Close'][i],cash,finance,Average_price)
      line = []
      line.append(data.index[i])
      line.append(i)
      marker.append(line)
      print(cash)
    elif finance != 0 and Average_price-((Average_price*min_percent)/100)>=data['Adj Close'][i]:
      cash,finance,Average_price = sell(data['Adj Close'][i],cash,finance,Average_price)
      line = []
      line.append(data.index[i])
      line.append(i)
      marker.append(line)
      print(cash)
  '''
  fig = plt.figure(figsize = (50,20))
  fig = plt.plot(data['Adj Close'])
  fig = plt.plot(minus)
  fig = plt.plot(plus)
  win = 0
  lose = 0
  for i in range(0,len(marker)-1,2):
    start = marker[i]
    end = marker[i+1]
    if data['Adj Close'][start[1]]<data['Adj Close'][end[1]]:
      fig = plt.axvspan(start[0],end[0],color = 'blue',alpha = 0.1)
      win = win+1
    else:
      fig = plt.axvspan(start[0],end[0],color = 'red',alpha = 0.1)
      lose = lose+1
  plt.legend() 
  print(win,lose)
  '''
  print('백테스팅 총 수익률:',round(((cash-start_cash+(finance*data['Adj Close'][len(data)-1]))/start_cash)*100,2),'%')
  print('잔고:',round(cash+(finance*data['Adj Close'][len(data)-1]),2),'원')
  print('종목코드:',code)
  return round(((cash-start_cash+(finance*data['Adj Close'][-1]))/start_cash)*100)

주석 부분은 그래프가 그려지는 부분이다.

 

결과

-89, -86, -80, -79, -79, -79, -78, -77, -66, -65, -62, -61, -60, -59, -59, -58, -55, -49, -47, -44, -42, -41, -41, -38, -37, -34, -33, -33, -31, -31, -31, -30, -29, -28, -28, -23, -22, -22, -22, -21, -21, -20, -17, -17, -16, -16, -15, -15, -15, -14, -13, -12, -12, -11, -10, -9, -7, -6, -6, -6, -4, -3, -1, 0, 0, 0, 0, 1, 1, 1, 2, 2, 4, 5, 6, 6, 7, 8, 9, 9, 10, 14, 15, 15, 16, 17, 18, 18, 19, 22, 23, 26, 26, 26, 26, 29, 29, 30, 30, 31, 31, 32, 35, 36, 40, 40, 42, 43, 45, 46, 47, 47, 47, 48, 49, 50, 53, 55, 56, 57, 57, 58, 62, 64, 66, 70, 73, 82, 84, 92, 93, 93, 96, 97, 102, 103, 105, 105, 106, 107, 115, 115, 117, 123, 135, 147, 150, 152, 160, 174, 183, 188, 190, 190, 193, 195, 214, 215, 217, 237, 247, 250, 258, 264, 272, 281, 297, 304, 324, 335, 355, 374, 398, 438, 440, 472, 523, 532, 577, 624, 698, 1209, 1240,

 

수익 : 37

손실 : 63

결과가 너무 안좋았다. 하지만 분석중에 알아낸 사실이 하나 있었다. envelope를 거래량이 많은 상태에서 둘파하게 된다면 대부분 손실을 본다는 사실이었다. 하지만 거래량이 터지지 않고 하향돌파하면 곧바로 반등이 나오거나 일주일이내에 수익이 나오는것을 알 수 있었다. 다음 포스팅에서는 이번에 분석한 것을 반영해서 포스팅 해보겠다.

 

728x90