Skip to content

Instantly share code, notes, and snippets.

@verystrongjoe
Created March 9, 2017 00:04
Show Gist options
  • Save verystrongjoe/a91a7d046e58d994b2644f9ced8c23e3 to your computer and use it in GitHub Desktop.
Save verystrongjoe/a91a7d046e58d994b2644f9ced8c23e3 to your computer and use it in GitHub Desktop.
주식 회복 탄력성 지수 구하는 모듈
from bs4 import BeautifulSoup
import requests
import urllib
import datetime, time
from prettytable import PrettyTable
## resilience 주식의 회복 탄력성을 계산해주는 로직
class Resilience :
# 1~ 513 페이지를 네비게이션하면서 1996년도에서 오늘까지의 일일 종가 데이터를 가져온다.
domainUrl = 'http://finance.naver.com/item/sise_day.nhn?code='
pageUrl = '&page='
threshold_DroppedPersent = 5
threshold_MaxDayToCountupRecoveryTime = 1000
def main(self, code):
prices = Resilience.getPricesFromWeb(self, code)
dropPrices = Resilience.getDropBadlyList(self,prices)
dropPrices = Resilience.calculateDaysToBeRecovered(self,prices,dropPrices)
Resilience.printRecoveryReport(self,dropPrices)
newsList = Resilience.getNewsList(self,code)
dropPrices = Resilience.appendRelatedNewsOnDroppedDay(self,dropPrices,newsList)
Resilience.printResultWithNews(self,dropPrices)
def getPricesFromWeb(self, code):
# last page 구하는 로직 구현
last_page_index = 50
list = []
for page in range(1, last_page_index):
url = Resilience.domainUrl + code + str(Resilience.pageUrl) + str(page)
source_code = requests.get(url, timeout=None)
soup = BeautifulSoup(source_code.text, 'lxml')
tableSoup = soup.find('table', attrs={'class', 'type2'})
trSoup = tableSoup.find_all('tr')
i = 0
rowcount = 0;
for tr in trSoup:
i = i + 1
if i > 2 and i < 16 and i <= len(tr):
if i == 8 or i == 9 or i == 10:
continue
j = 0
dic = {}
for td in tr:
j = j + 1
if j == 2:
date_str = str(td.span.text)
date_str = date_str.replace(".", "")
dic['date'] = datetime.date(int(date_str[0:4]), int(date_str[4:6]), int(date_str[6:8]))
if j == 4:
price = str(td.span.text)
dic['price'] = int(price.replace(',', ''))
if j == 6:
change = str(td.span.text).strip()
if change != '0':
if td.img['src'].endswith('ico_up.gif') or td.img['src'].endswith('ico_up2.gif'):
dic['change'] = int(change.replace(',', ''))
else:
dic['change'] = -1 * int(change.replace(',', ''))
else:
dic['change'] = 0
list.append(dic)
return list
def getDropBadlyList(self, list):
# 하루 등락률이 10프로 하락하는 지점을 찾는다. 하락을 했다면 그날의 시가를 가지고 향후 언제 그 가격을 넘어서는지를 찾을 것이다.
# 전날 종가를 기준으로 등락률을 매기는게 맞는데 그냥 당일 종가와 등락 가격을 가지고 퍼센티지를 계산함.
drop_badly_list = []
for day in list :
#print(day['date'] + " : " + str(day['price']) + " : " + str(day['change']))
percent = ( day['price'] + day['change'] ) / day['price'] * 100 - 100
#print(day['date'] + " : " + str(percent))
if percent < -1 * Resilience.threshold_DroppedPersent :
drop_badly_list.append(day)
# 그래서 우선 list를 filter해서 가지고 있고 그 시가를 가지고 있는 list를 만들 것이다. 그리고 이 filtered_list를 가지고 다시 원래의 list
return drop_badly_list
# 우선 특정 % 이상 떨어진 일자들을 얻고 각각 일자에 대해 전날 종가 가격으로의 회복 기간이 얼마 소요되었는지 하고 그것에 대한 평균도 구하도록 한다.
# threshold 한계값 정해서 이 값을 넘을 경우는 실제 계산에서 배제를 하도록 한다. : 추가 기능
def calculateDaysToBeRecovered(self, list, drop_badly_list):
# 날짜 오름차순으로 변경
list.reverse()
recovery = []
for drop_day in drop_badly_list:
change = drop_day['change']
yesterdayPrice = drop_day['price']
d = drop_day['date']
counting = 0
isCounting = False
element = {}
for day in list:
if day['date'] == d:
isCounting = True
yesterdayPrice -= change
theDay = d
if isCounting:
if yesterdayPrice < day['price']:
break
else:
counting = counting + 1
# print(day['date'],day['price'])
element['theDay'] = theDay
element['counting'] = counting
element['yesterdayPrice'] = yesterdayPrice
recovery.append(element)
return recovery
def printRecoveryReport(self, recovery):
t = PrettyTable(['5% 이상 떨어진 일자','회복하는데 걸린 일수', '회복해야하는 주가'])
for ele in recovery:
t.add_row([ele['theDay'], ele['counting'], ele['yesterdayPrice']])
print(t)
# for ele in recovery :
# print('----------------------------')
# print('5% 이상 떨어진 일자 : ', ele['theDay'])
# print('회복하는데 걸린 일수 : ', ele['counting'])
# print('회복해야하는 주가 : ', ele['yesterdayPrice'])
sum = 0
for ele in recovery :
sum = sum + ele['counting']
print('The average of days to recover is ' , sum/len(recovery))
def getNewsList(self, code):
# 그다음 이시기에 어떤 뉴스가 있었는지를 찾기 위해서 네이버 증권의 뉴스데이터를 이용한다.
news_domain = 'http://finance.naver.com/item/news_news.nhn?code='+ code
news_domain_with_pageNo = 'http://finance.naver.com/item/news_news.nhn?code=' + code + '&page='
source_code = requests.get(news_domain, timeout=None)
soup = BeautifulSoup(source_code.text, 'lxml')
tableSoup = soup.find('table', attrs={'class', 'Nnavi'} )
td = tableSoup.find('td', attrs={'class','pgRR'}).a['href']
last_page_index = int(td[td.index('page=') + 5:])
last_page_index = 300
news_list = []
# for page in range(1,last_page_index) :
for page in range(600, 900):
url = news_domain_with_pageNo + str(page)
source_code = requests.get(url, timeout=None)
soup = BeautifulSoup(source_code.text, 'lxml')
newsTabelSoup = soup.find('table', attrs={'class', 'type2'})
trSoup = newsTabelSoup.find_all('tr')
i = 0
rowcount = 0;
for tr in trSoup:
i = i + 1
if i > 2 and i < 16:
if i == 8 or i == 9:
continue
j = 0
dic = {}
for td in tr:
j = j + 1
if j == 2:
strDate = str(td.span.text)
# print(strDate)
yyyy = int(strDate[0:4])
mm = int(strDate[5:7])
dd = int(strDate[8:10])
# 나중에 시간이 오후 3시 30분 이후에 있는건 제외를 하자. 다음날 영향 변수
hh = int(strDate[11:13])
minutes = int(strDate[14:16])
# dic['date'] = str(td.span.text)
dic['date'] = datetime.date(int(yyyy), int(mm), int(dd))
if j == 4:
dic['title'] = td.a.text
if j == 6:
dic['publish'] = td.text
news_list.append(dic)
return news_list
def appendRelatedNewsOnDroppedDay(self, recovery, news_list):
for recv in recovery:
d = recv['theDay']
news_list2 = []
for news in news_list:
if news.get('date') == d:
# print(news['title'])
news_list2.append(news['title'])
recv['news_list'] = news_list2
return recovery
def printResultWithNews(self, recovery):
import pprint
pprint.pprint(recovery)
#print(recovery)
# t = PrettyTable(['Date','Original Price', 'DaysToBeRecovered', 'NewsList'])
#
# for recv in recovery:
# t.add_row([recv['theDay'], recv['yesterdayPrice'], recv['counting'], recv['news_list']])
#
# print(t)
@verystrongjoe
Copy link
Author

  • first version
  • 속도 개선 필요
  • 크롤링 뉴스 카운트 개수, 하락 퍼센티지 기준 수치 파라메터로 분리
  • 속도 개선 포인트 찾아야함

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment