Skip to content

Instantly share code, notes, and snippets.

@verystrongjoe
Created March 9, 2017 00:04

Revisions

  1. verystrongjoe created this gist Mar 9, 2017.
    232 changes: 232 additions & 0 deletions Resilience.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,232 @@
    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)