삶의 공유

[Python활용]종목별 Valuation 및 저평가 주식 Search 자동화 Project[4] 본문

Data Scientist/Python

[Python활용]종목별 Valuation 및 저평가 주식 Search 자동화 Project[4]

dkrehd 2022. 2. 3. 16:31
728x90
반응형

안녕하세요 ~ 

이번시간에도 지난번에 이어서 코스피 종목별 Valuation 및 저평가 주식 Search 자동화 Project 4번째 시간 입니다.

 

이전에 "삼성 전자" 1개 종목에 대해서 데이터를 산출하는 방법에 대해서 작성 해보았습니다.

이번 시간에는, 코스피 전 종목에 대해서 데이터를 산출하여 엑셀에 저장하는 코드를 작성해보겠습니다.

 

 

함수화 하기

이전에 만든 코드들을 한데 모아 함수로 구현 해보겠습니다.

 

아래 코드들은 이전에 1,2,3번째 시간에서 작성한 코드들과 동일하고, 중간 중간에 try, catch문과 같이 에러가 발생했을때 로그로 남기고 다음 Step이 진행 될 수 있게 코드를 짰습니다.

def read_financial_df(code):
    # 네이버 금융에서 크롤링 하기
    URL = f"https://finance.naver.com/item/main.nhn?code={code}"
    r = requests.get(URL)
    df = pd.read_html(r.text)[3]
    
    # 사용할 컬럼, 삭제할 컬럼 추출하기
    cols = []
    use_cols = []
    i = 1
    for column in df.columns:
        if i < 6:
            cols.append(column[1])
            use_cols.append(column)
        i += 1

    #사용할 dataframe만 선정하기
    df_sort = df[use_cols]
    
    #column 이름 변경
    df_sort.columns = cols

    # 인덱스 설정
    df_sort.index = df_sort['주요재무정보']
    
    # 행렬 전환 및 중복 인덱스 삭제
    df_semi = df_sort.transpose()
    df_semi = df_semi.drop([df_semi.index[0]]) # 컬럼명 중복 인덱스 삭제
    
    
    # 매출액 성장률
    revenue_growth_rate = 0
    temp = 0
    for i in range(len(df_semi['매출액'])):
        try:
            df_semi['매출액'] = df_semi['매출액'].astype('float')
        except Exception as e:
            print("예외 발생 매출액 float 전환 불가")
        if i < 3 and isinstance(df_semi['매출액'][i+1], float):
            temp += (df_semi['매출액'][i+1] - df_semi['매출액'][i]) / df_semi['매출액'][i]
    revenue_growth_rate = (temp / (len(df_semi['매출액'])-1)) *100
    
    # 영업이익 성장률
    semiincome_growth_rate = 0
    temp = 0
    for i in range(len(df_semi['영업이익'])):
        try:
            df_semi['영업이익'] = df_semi['영업이익'].astype('float')
        except Exception as e:
            print("예외 발생 영업이익 float 전환 불가")
        if i < 3 and isinstance(df_semi['영업이익'][i+1], float):
            temp += (df_semi['영업이익'][i+1] - df_semi['영업이익'][i]) / df_semi['영업이익'][i]
    semiincome_growth_rate = (temp / (len(df_semi['영업이익'])-1)) *100

    # 당기 순이익 성장률
    income_growth_rate = 0
    temp = 0
    for i in range(len(df_semi['당기순이익'])):
        try:
            df_semi['당기순이익'] = df_semi['당기순이익'].astype('float')
        except Exception as e:
            print("예외 발생 당기순이익 float 전환 불가")
        if i < 3 and isinstance(df_semi['당기순이익'][i+1], float):
            temp += (df_semi['당기순이익'][i+1] - df_semi['당기순이익'][i]) / df_semi['당기순이익'][i]
    income_growth_rate = (temp / (len(df_semi['당기순이익'])-1)) *100
    
    #EPS 증가율
    EPS_growth_rate = 0
    temp = 0
    for i in range(len(df_semi['EPS(원)'])):
        try:
            df_semi['EPS(원)'] = df_semi['EPS(원)'].astype('float')
        except Exception as e:
            print("예외 발생 EPS(원) float 전환 불가")
        if i < 3 and isinstance(df_semi['EPS(원)'][i+1], float):
            temp += (df_semi['EPS(원)'][i+1] - df_semi['EPS(원)'][i]) / df_semi['EPS(원)'][i]
    EPS_growth_rate = (temp / (len(df_semi['EPS(원)'])-1)) *100

    debt = df_semi['부채비율'][2] # 부채 비율
    
    #EPS
    EPS_C = df_semi['EPS(원)'][2]
    EPS_E = df_semi['EPS(원)'][3]
    
    #PER
    PER_C = df_semi['PER(배)'][2]
    PER_E = df_semi['PER(배)'][3]
    
    #ROE
    ROE_C = df_semi['ROE(지배주주)'][2]
    ROE_E = df_semi['ROE(지배주주)'][3]
    
    #PBR
    PBR_C = df_semi['PBR(배)'][2]
    PBR_E = df_semi['PBR(배)'][3]

    #PEG
    if EPS_growth_rate ==0:
        PEG_C = "Non"
        PEG_E = "Non"
    else:
        #print(PER_C, "/", PER_E, "/", EPS_growth_rate)
        PEG_C = float(PER_C)/float(EPS_growth_rate)
        PEG_E = float(PER_E) / float(EPS_growth_rate)
    
    # 적정 주가
    if float(EPS_C) < 0 and float(ROE_C) < 0:
        right_price_C = float(EPS_C) * float(ROE_C) * -1
        right_price_E = float(EPS_E) * float(ROE_E) * -1
    else:
        right_price_C = float(EPS_C) * float(ROE_C)
        right_price_E = float(EPS_E) * float(ROE_E)

    #PSR
    df_2 = pd.read_html(r.text)[4]
    df_2.index=df_2['종목명']
    df_2 = df_2.transpose()
    df_2 = df_2.drop([df_2.index[0]]) # 컬럼명 중복 인덱스 삭제
    company_name = df_2.index[0].split('*')[0] # 종목명
    price_C = float(df_2['현재가'][0]) # 현재가
    total_company_value = float(df_2['시가총액(억)'][0]) # 시가총액
    #print(df_semi['매출액'][-1], " / ", df_semi['매출액'][-2])
    if df_semi['매출액'][-1] == 0 or df_semi['매출액'][-1] is None or df_semi['매출액'][-2] == 0 or df_semi['매출액'][-2] is None:
        PSR_C = "Non"
        PSR_E = "Non"
    else:
        PSR_C = total_company_value / df_semi['매출액'][-2]
        PSR_E = total_company_value / df_semi['매출액'][-1]
    
    # 앞서 구한 값들을 딕셔너리 형태로 만들기
    raw_list = {
        '종목명' : company_name,
        '현재가' : price_C,
        '시가총액(억)' : total_company_value,
        '매출액성장률' : revenue_growth_rate,
        '영업이익성장률' : semiincome_growth_rate,
        '당기순이익성장률' : income_growth_rate,
        '부채비율' : debt,
        'EPS(직전)': EPS_C,
        'EPS(예측)' : EPS_E,
        'PER(직전)' : PER_C,
        'PER(예측)' : PER_E,
        'ROE(직전)' : ROE_C,
        'ROE(예측)' : ROE_E,
        'PBR(직전)' : PBR_C,
        'PBR(예측)' : PBR_E,
        '적정주가(직전)' : right_price_C,
        '적정주가(예측)' : right_price_E,
        'PEG(직전)' : PEG_C,
        'PEG(예측)' : PEG_E,
        'PSR(직전)' : PSR_C,
        'PSR(예측)' : PSR_E
    }
    df_final = pd.DataFrame([raw_list])
    
    return df_final

 

코스피 전 종목 크롤링

 

코스피 종목에 대해 크롤링 하는 방법에 대해서는 하기 블로그 참고 부탁드립니다.

https://wg-cy.tistory.com/54

 

[데이터수집] 한국 거래소 업종 분류 현황 및 개별 지표 크롤링 하기

※ 이 포스팅은 https://hyunyulhenry.github.io/quant_python/05_crawl_practice.html 를 참고 하여 만든 내용입니다. 한국 거래소의 업종 분류 현황 및 개별지표 크롤링 파이썬을 이용하여 업종 분류 현황을..

wg-cy.tistory.com

 

그럼 코스피 전종목에 대한 얻은 종목 코드를 바탕으로  위에 정의한 함수에 인수로 넣어주어 하나씩 접근해보겠습니다.

먼저 pandas의 DataFrame 객체를 하나 만들어 줍니다.

그리고 코스피 전 종목의 코드들(sector_KS)을 하나씩 접근해서 위에 정의한 함수 (read_financial_df(code))에 code값을 넣어 줍니다.

 

이번 코드들도 try ~ except 구문을 사용해서 에러 발생 시 어떤 부분이 에러가 나는지 로그를 남기고 다음 Stetp이 진행 될 수 있도록 코드를 작성하였습니다.

 

for loop가 돌면서 미리 만들어 둔 DataFrame객체에 항목들을 계속 추가 해줍니다.

 

그리고 마지막으로 to_excel 함수를 사용해서 엑셀로 저장해 줍니다.

df = pd.DataFrame()
for code in sector_KS['종목코드']:
    try:
        re_code = str(code)
        df = df.append(read_financial_df(re_code))

    except Exception as e:
        print("{0} 종목 예외 발생 : {1}".format(code, str(e)))

df.to_excel('stock_Valuation.xlsx')

코드를 실행하면 아래와 같이 에러가 뜨시는 경우를 보실 거에요 !

 

실제 이 코드에 대한 네이버 금융 사이트를 들어가보시면, 재무 정보에 대한 내용이 없는 것은 확인 하실수 있으실거에요.

이 항목들은 제외하고 엑셀로 저장된 파일을 한번 열어 보겠습니다.

 

잘 나오는 것을 확인 할 수 있었습니다 !

 

이제 이것을 기반으로 저평가 주식을 찾고, 시뮬레이션을 통해 수익률을 계산해보겠습니다.

 

그럼 이번 포스팅을 마치겠습니다.

 

읽어주셔서 감사합니다.

반응형