본문 바로가기
Programming/Quant

[퀀트투자를 위한 툴 만들기 2] Company Guide(Fn Guide)에서 종목 재무정보 추출

by 지표덕후 2021. 5. 19.

파이선과 엑셀 Xlwings 패키지를 활용해 퀀트투자를 위한 종목선정 툴을 만들었습니다.

 

[퀀트투자를 위한 툴 만들기 0] 파이썬과 엑셀을 활용한 종목 선정 프로그램 기획

계량적인 방식으로 주식투자를 해보려고 합니다. 철저하게 숫자만 가지고 살지 말지를 판단하는 겁니다. 소위 말하는 퀀트투자인 건데, 비계량적인 투자방식을 완전히 포기할 순 없어, (... 라고

mokeya.tistory.com




이 작업은 크게 네 가지 과업으로 이루어지는데,
이 포스팅은 그 두 번째 단계에 대한 내용을 담고 있습니다.
첫 단계에서 대신증권API로 상당히 다양한 지표들을 확보할 수 있지만
재무정보가 좀 부실해요. 그걸 보완하기 위한 과정입니다.
(아래 목차 클릭 시 해당 포스팅으로)

1. 대신증권API로 주식시장 전종목에 대한 정보 추출
2. Company Guide(Fn Gudie) 웹을 크롤링해 전종목에 대한 재무정보 추출(현재 글)
3. 1과 2의 결과물을 종목코드를 기준으로 합친 후 투자지표 필드 추가
4. 3의 결과물을 가지고 xlwings 패키지 활용하여 엑셀툴 제작

 

 

 

코딩의 결과

작업이 정상적으로 완료되면 이런 결과물이 튀어나옵니다.
상장된 종목들의 '매출액', '매출총이익', '영업이익', '당기순이익', '자산', '유동자산', '부채', '유동부채', '자본(순자산)', '영업현금흐름'을 테이블로 저장한 것입니다.

종목코드 매출액 매출총이익 영업이익 당기순이익 자산 유동자산 부채 유동부채 자본(순자산) 영업현금흐름
A000020 307,200,000,000 121,700,000,000 9,900,000,000 9,400,000,000 376,000,000,000 235,500,000,000 75,200,000,000 55,700,000,000 300,900,000,000 13,300,000,000

 

 

작업환경

1. 파이썬3.7(32bit)
2. 파이썬IDE는 JetBrain의 Pycharm

 

 

코드

Fnguide에서 종목별 재무제표 테이블은 아래와 같은 URL 체계를 가지고 있습니다.
https://comp.fnguide.com/SVO2/ASP/SVD_Finance.asp?pGB=1&gicode=종목코드&cID=&MenuYn=Y&ReportGB=&NewMenuID=103&stkGb=701

Fnguide에서 종목별 재무비율 테이블은 아래와 같은 URL 체계를 가지고 있고요.
https://comp.fnguide.com/SVO2/ASP/SVD_FinanceRatio.asp?pGB=1&gicode=종목코드&cID=&MenuYn=Y&ReportGB=&NewMenuID=104&stkGb=701



이 구조를 활용해서 종목코드와 데이터 종류를 입력받아
HTML 코드를 반환하는 함수를 정의했습니다.
가령 삼성전자의 재무제표 HTML코드를 가져오려면 get_html_fnguide("005930", 0)을 입력하면 됩니다.

# 필요한 패키지 모두 import 
import pandas as pd from pandas 
import DataFrame from urllib.request 
import urlopen, Request 

# 종목별로 HTML을 반환하는 함수를 구현
def get_html_fnguide(ticker, gb):
    """
    :param ticker: 종목코드
    :param gb: 데이터 종류 (0 : 재무제표, 1 : 재무비율, 2: 투자지표, 3:컨센서스 )
    :return:
    """
    url=[]

    url.append("https://comp.fnguide.com/SVO2/ASP/SVD_Finance.asp?pGB=1&gicode=A" + ticker + "&cID=&MenuYn=Y&ReportGB=&NewMenuID=103&stkGb=701")
    url.append("https://comp.fnguide.com/SVO2/ASP/SVD_FinanceRatio.asp?pGB=1&gicode=A" + ticker + "&cID=&MenuYn=Y&ReportGB=&NewMenuID=104&stkGb=701")
    url.append("https://comp.fnguide.com/SVO2/ASP/SVD_Invest.asp?pGB=1&gicode=A"+ ticker + "&cID=&MenuYn=Y&ReportGB=&NewMenuID=105&stkGb=701")
    url.append("https://comp.fnguide.com/SVO2/ASP/SVD_Consensus.asp?pGB=1&gicode=A" + ticker +"&cID=&MenuYn=Y&ReportGB=&NewMenuID=108&stkGb=701")

    if gb>3 :
        return None

    url = url[gb]
    try:

        req = Request(url, headers={'User-Agent': 'Mozilla/5.0'})
        html_text = urlopen(req).read()

    except AttributeError as e :
        return None

    return html_text

 



종목코드는 일일이 입력하는 것이 아니라
1단계에서 추출한 시중 종목들의 코드를 한꺼번에 가져와 입력할 겁니다.
종목코드들은 "A숫자코드"의 형식으로 저장되어 있기에 추출할 때 "A"를 탈락시키고
숫자만 추출해야 합니다. 그것을 listRefineCodes라는 변수에 list 형태로 저장하였습니다.

# 주권만 필터링
dfStock = dfMarketEye[dfMarketEye['종목구분'] == 1]

# 코드에서 숫자(\d)만 추출
dfStock['정제코드'] = dfStock.loc[:, '종목코드'].str.extract('(\d+)')
listRefineCodes = dfStock['정제코드'].tolist()

 

 

 


종목코드를 하나하나 입력 받아서
해당 종목의 재무정보를 추출해 list로 저장하는 for loop 구문을 작성합니다.
pandas 패키지로 손쉽게 가능한데,
Fnguide에 이 재무정보들이 테이블 형태로 저장되어 있기 때문에 그렇습니다.
pandas 패키지에서 제공하는 read_html 함수는
html의 table 클래스에서 특정 위치의 요소값을 쉽게 추출할 수 있게 해줍니다.
저는 이 함수들을 이용해서 상장된 종목들의
매출액, 매출총이익, 영업이익, 당기순이익, 자산, 유동자산, 부채, 유동부채, 자본(순자산), 영업현금흐름을 추출하여 데이터프레임으로 저장했습니다.

data = []
for code in listRefineCodes:
    rowfIncomeStatement = [0, 2, 4, 15]  # 매출액, 매출총이익, 영업이익, 당기순이익
    rowFinancialStatement = [0, 1, 4, 5, 8]  # 자산, 유동자산, 부채, 유동부채, 자본(순자산)
    rowCashFlow = [0]  # 영업으로 인한 현금흐름
    print(code)
    listCode = ["A"+str(code)]

    # 재무제표 테이블에서 지표 추출
    try:
        dfIncomeStatement = pd.read_html(get_html_fnguide(str(code), 0))[0]
        listIncomeStatement = dfIncomeStatement.iloc[rowfIncomeStatement, 3].tolist()
    except:
        listIncomeStatement = [0, 0, 0, 0]

    # 포괄손익계산서 테이블에서 지표 추출
    try:
        dfFinancialStatement = pd.read_html(get_html_fnguide(str(code), 0))[2]
        listFinancialStatement = dfFinancialStatement.iloc[rowFinancialStatement, 3].tolist()
    except:
        listFinancialStatement = [0, 0, 0, 0, 0]
    
    # 현금흐름표 테이블에서 지표 추출
    try:
        dfCashFlow = pd.read_html(get_html_fnguide(str(code), 0))[4]
        listCashFlow = dfCashFlow.iloc[rowCashFlow, 3].tolist()
    except:
        listCashFlow = [0]

    listFinance = listIncomeStatement + listFinancialStatement + listCashFlow
    finalFinance = listCode + list(map(lambda x: '{0:,.0f}'.format((x * 100000000)), listFinance))
    data.append(finalFinance)
    listCode = []
    # time.sleep(0.5)

df = DataFrame(data, columns=['종목코드'
                             , '매출액', '매출총이익', '영업이익', '당기순이익'
                             , '자산', '유동자산', '부채', '유동부채', '자본(순자산)'
                             , '영업현금흐름']).astype(float)

df.to_csv('FNGuide.csv', encoding="cp949")




이 방식에는 몇 가지 문제점이 있습니다.
1 우선주는 Fngudie에 정보가 없습니다.
2 ETF는 재무정보가 없습니다.
3 보험, 금융업종은 재무제표(테이블) 양식이 달라서 의도한 지표가 수집되지 않습니다.

그럼에도 불구하고 다음 포스팅에서는
1단계에서 추출한 종목별 데이터에
이번 단계에서 추출한 종목별 재무정보를 머징(merging)할 겁니다.


상장기업의 재무제표를 수집하는 방법엔 본 포스팅에서 소개한 웹 크롤링 외에 공개된 API를 활용하는 방법도 있습니다. 허가되지 않은 웹 크롤링보다 떳떳하고, 안정적인 데이터 수집 방식입니다. 아래 링크에서는 전자공시시스템(DART)의 오픈API와 파이썬을 활용해 국내 상장기업 전체의 재무제표를 수집하는 방법을 소개하고 있습니다.

 

전체 상장기업 재무제표 조회방법(feat. 파이썬으로 DART API 호출)

퀀트투자 혹은 종목 스크리닝을 자체적으로 해보려고 툴을 만들었는데요. 이 때 필요한 것이 상장기업 전체에 대한 재무정보 혹은 재무제표입니다. 전체 상장기업의 데이터를 얻는 가장 일반적

mokeya.tistory.com

 

댓글