일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- DataFrame
- 구현
- 우리FIS
- OpenAPI+
- 티스토리
- Windows
- multiprocessing
- HTML
- idxmin
- Python
- CSS
- 의사 클래스
- 파이썬
- Tistory
- pywinauto
- QueueHandler
- freeze_support
- 필기
- 웹크롤링
- 금결원
- 금융결제원
- idxmax
- pycharm
- 퀀트
- 코드블럭
- 멀티 로그인
- 진행 상황
- line number
- 하이라이트
- highlight.js
- Today
- Total
맨땅에 헤딩하는 사람
어닝 서프라이즈 특징주 예후 분석 | python 본문
어닝 서프라이즈 : 기업의 실적이 시장의 예상치를 훨씬 더 초과하는 현상, 반대말로 어닝 쇼크가 있다.
기업 실적 발표 시즌, 기업의 주가가 폭등하면 나오는 심심찮게 해당 기업이 어닝 서프라이즈였다는 것을 확인할 수 있다. '[특징주] OO, 어닝서프라이즈' 라는 뉴스 기사는 흔하다. 그렇다면 어닝 서프라이즈를 달성한 기업들의 예후는 어떨까. 어닝 서프라이즈를 달성한 기업을 장기투자 관점에서 가지고 간다면 수익을 볼 수 있을까. 해볼만한 가치가 있는 것이라 생각하고 직접 데이터를 확인해보았다.
특징주 웹크롤링
네이버 증권 사이트에 뉴스탭에서 '특징주 어닝 서프라이즈'라 검색하면 다음과 같은 결과를 얻을 수 있다.
'특징주'가 없는 뉴스기사들도 꽤 많은데 특징주를 굳이 붙여서 검색한 이유는 뉴스 제목에서 기업 이름을 추출할 때 수월하게 진행하기 위함이다. "<특징주> '어닝 서프라이즈' LG디스플레이 강세"와 같이 일반적인 형식을 벗어난 기사들도 있어서 이를 고려하기 위해 3단계에 걸쳐 문자열 패턴을 거쳐 기업명을 추출하도록 했다.
코드는 다음과 같다.
import requests
from bs4 import BeautifulSoup
import datetime
import re
dates = []
codes = []
titles = []
pat_1 = re.compile('[\]\)>]+[ ]*[\D]+[,]{1}') #[특징주]OO,...
pat_2 = re.compile('[\]\)>]+[ ]*[가-힣a-zA-Z&]+[ ]{1}') #[특징주]OO ...
pat_3 = re.compile("' [가-힣a-zA-Z&]+ ") # <특징주> '어닝 서프라이즈' OO
pat_sub = re.compile("[^가-힣a-zA-Z& ]")
for page_num in range(1,42,1):
url = 'https://finance.naver.com/news/news_search.nhn?'\
'rcdate=1&q=%C6%AF%C2%A1%C1%D6+%BE%EE%B4%D7+%BC%AD%C7%C1%B6%F3%C0%CC%C1%EE&'\
'x=9&y=15&sm=title.basic&pd=4&stDateStart=1997-01-01&stDateEnd=2019-12-31&'\
'page='+ str(page_num)
raw = requests.get(url).text
html = BeautifulSoup(raw, 'html.parser')
html_titles = html.select('.articleSubject')
html_dates = html.select('.wdate')
for html_title in html_titles:
title = html_title.text.strip()
code = pat_1.search(title)
if code is not None:
code = pat_sub.sub(' ', code.group()).strip()
codes.append(code)
continue
code = pat_2.search(title)
if code is not None:
code = pat_sub.sub(' ', code.group()).strip()
codes.append(code)
continue
code = pat_3.search(title)
if code is not None:
code = pat_sub.sub(' ', code.group()).strip()
codes.append(code)
continue
codes.append(code)
for html_date in html_dates:
date = datetime.datetime.strptime(html_date.text.strip()[:10], '%Y-%m-%d')
dates.append(date)
print('crowling done.')
with open('earning.txt', 'w') as file:
for idx in range(len(codes)):
file.write('{0} / {1}\n'.format(codes[idx], dates[idx]))
코드의 결과는 다음과 같다.
None은 위의 3가지 문자 패턴으로도 검출하지 못함을 의미한다. 지독한 변형이 아닐 수 없다. 내 경우는 2000년 1월 1일 부터 2019년 12월 31일까지를 대상으로 하였다.
기업 주가 증감률 산출
그림 2와 같이 추출된 기업명에서 중복된 날짜에 해당하는 것은 하나만 반영하고 기업들의 어닝 서프라이즈 일자 기준 130일(거래일 기준 약 6개월)의 예후를 비교하였다.
나의 경우는 키움증권 api를 사용하여 기업 주가를 일봉으로 모아놓은 DB가 있기 때문에 그 DB를 사용하여 증감률을 산출하였다. 종목별 예후, 그리고 종목들의 산술평균, 기하평균을 계산하여 정리하였다.
이 과정에서 자체 제작 라이브러리를 사용했기 때문에 소스 코드를 공개해봐야 의미가 없어보여 게시는 하지 않는다.
결과
산출방법 : 기사가 뜬 해당 날짜에 해당 기업의 주가 변동률을 130일 이후까지 계산 후 이에 대한 산술평균, 기하평균, 표준편차를 계산
데이터 개수 : 352 (뉴스 수, 몇몇 경우는 동일 기업의 다른 일자도 반영 되어있음)
데이터 기간 : 2003.01.01 - 2019.12.31
참고사항 : 2020.03.20 기준 시가총액 2000억 이상의 기업에 한정하여 계산
산술평균과 기하평균의 그래프는 다음과 같다.
각 평균은 쉽게 설명해서 다음 상황을 의미한다.
산술평균 : 해당되는 모든 주식을 한 번에 구입하였을 경우 수익률
기하평균 : 해당되는 모든 주식을 순차적으로 구입하였을 때 수익률
주가는 비율로 계산되기 때문에 기하평균이 산술평균보다 낮을 수 밖에 없다.
2-6%의 수익률도 안좋지만 표준편차의 그래프를 보면 더 암담함을 알 수 있다.
표준편차는 계속 우상향을 그린다. 즉, 각 종목의 변동성이 점점 심해진다는 의미이다. 즉, 어닝서프라이즈가 발생하는 모든 주식을 일정한 비율로 일정한 양을 사는 것은 불가능하기에 어느 정도 유효하다고 판단되는 어닝서프라이즈 주에 비중을 둬야하는데 그것이 꽝이라면 손실을 피하지 못하게 되고 말 것이다. 차라리 지수에 투자하는 것이 좀 더 높은 수익률을 거둘 수 있을 것이라 생각한다.
마치며
어닝 서프라이즈 기사가 뜬 직후 전날 대비 수익률도 한번 확인해보았다.
산술평균 : 1.037
기하평균 : 1.036
표준편차 : 0.047
이건 확실히 유의미한 상승이라고 볼 수 있다. 다만, 전날에 사는 것이 불가능하다면 이 수치는 아무 의미도 없다. 그리고 확실한 건, 어닝서프라이즈가 떴다고 무작정 사지 말아야한다는 것이다. 데이터가 말해준다.
'퀀트 > 구현' 카테고리의 다른 글
키움증권 Open API+ 구현 상 issue 해결 | python (0) | 2020.10.24 |
---|---|
키움증권 Open API+ 멀티 로그인 | python pywinauto (2) | 2020.08.23 |
WICS 섹터 기업 업종 json 포맷 웹크롤링 | python (2) | 2020.07.17 |
퀀트 주가 분석 및 자동매매 시스템 환경 구축 | python (1) | 2020.07.16 |
장전 시간외 거래에서 프로그램으로 빠르게 매수 주문 넣기 | python (0) | 2020.07.12 |