ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [야후 파이낸스 데이터를 활용한 Quant Analysis - 3] 쓸 만한 데이터 정리하기 (2)
    Morgan Project/주식 데이터 분석 (Quant Analysis) 2022. 7. 6. 19:11

     

     

     

    지난 포스팅에 이어, yfinance를 통해 가져온 Ticker 객체에서 쓸 만한 정보가 뭐가 있는지 나머지를 정리해보고, pandas로 데이터를 보기좋게 정리하는 방법을 살펴보도록 하자.

     

     

     


     

    [financials, balance_sheet 정보]

     

     

    마찬가지로 종목코드를 입력하여 Ticker 객체를 가져오도록 하자.

     

    import yfinance as yf
    
    ticker = yf.Ticker("MSFT")

     

     

    이번에는 info 변수가 아니라, financials와 balance_sheet을 출력해보자. 그럼 다음과 같은 출력 결과를 볼 수 있다.

     

     

     

    기업의 재무제표, 현금 흐름과 관련된 세부 내용들을 이렇게 살펴볼 수 있다. 여기에서도 필요 이상으로 많은 정보가 있기 때문에, 실제 분석에서 사용될 법한 것들로만 한번 더 추려내보도록 하자.

     

     


     

    [쓸 만한 정보들 추려내기]

     

     

    1) 중요 비즈니스 금액정보

     

    - Research Development : 기업이 해당 분기에 R&D에 투자한 비용을 의미한다.

    - Net Income : 기업이 해당 분기에 올린 순이익을 의미한다.

    - Gross Profit : 기업이 해당 분기에 올린 매출 총이익을 의미한다.

    - Operating Income : 기업이 해당 분기에 올린 영업이익을 의미한다.

    - Total Revenue : 기업이 해당 분기에 올린 총매출액을 의미한다.

    - Cost Of Revenue : 기업이 해당 분기에 사용한 제품원가를 의미한다.

     

     

    2) 재무제표 정보

     

    - Total Liab : 기업이 가지고 있는 총 부채를 의미한다.

    - Total Stockholder Equity : 기업이 가지고 있는 자기자본을 의미한다.

    - Total Assets : 기업이 가지고 있는 총자산을 의미한다.

     

     


     

    [데이터 크롤링]

     

    지금까지의 내용을 pandas 형태로 만지기 쉽게 데이터를 정리해보자. yfinance 패키지의 응답 속도가 그렇게 시원치는 않기 때문에, 모든 종목을 하기는 힘들고, 하루 요청량도 정해져있어서 종목을 어느정도는 필터링을 한 뒤에 크롤링을 수행하는 것을 추천한다. 크롤링을 수행하기 전, 미리 column 정보를 다음과 같이 매핑해두도록 하자.

     

    info_columns_mapper = {
        # 정보 관련
        'market': '상장종류',  # nasdaq, nyse, amex
        'sector': '섹터',
        'industry': '산업군',
        'recommendationKey': '종합매수의견',
        
        # 매매 정보 관련
        'sharesOutstanding': '발행주식수',
        'averageVolume10days': '종목평균거래량(10일)',
        'averageVolume': '종목평균거래량',
        'heldPercentInstitutions': '기관보유비율',
        'shortRatio': '일일공매도비율',
        'sharesPercentSharesOut': '발행주식대비공매도비율',
        'shortPercentOfFloat': '유동주식중공매도비율',
        
        # 가격 관련
        'marketCap': '시가총액',  # 200B:mega // 10B~200B:large // 2B-10B:medium // 300M~2B:small // 50M~300M:micro // ~50M:nano
        'currentPrice': '현재가',
        'fiftyDayAverage': '50일평균가',
        'twoHundredDayAverage': '200일평균가',
        'fiftyTwoWeekHigh': '52주최고가',
        'fiftyTwoWeekLow': '52주최저가',
        'SandP52WeekChange': 'S&P_52주변동성',
        '52WeekChange': '52주변동성',
        'ytdReturn': '연초대비수익률',
        'fiveYearAverageReturn': '5년연평균수익률',  # 5년연평균수익률
        'beta': '베타값',  # 5년 데이터, 개별주식의 변동률을 의미. 1에 가까울수록 시장과 가깝고, 1을 넘어가면 시장 대비 고변동, 0으로 가까우면 시장 대비 저변동 주식을 의미함.
        
        # 현금 창출, 매출 관련 (ttm)
        'totalRevenue': '총매출액',
        'grossProfits': '매출총이익',  # 매출이익(매출액 - 매출원가)
        'revenuePerShare': '주당매출액',
        'ebitda': 'EBITDA',  # 감가상각 등의 부가비용을 차감하기 전의 금액, 영업 활동을 통한 현금 창출 능력. 유형자산의 가치까지 포함하는 지표
        'ebitdaMargins': 'EBITDA마진',  # 유형자산의 유지비용을 고려한 기업의 현금 창출 능력
        
        # 재무 상태 관련 (mrq)
        'debtToEquity': '부채자본비율',
        'operatingCashflow': '영업현금흐름',  # 영업현금흐름 : 영업이익 - 법인세 - 이자비용 + 감가상각비
        'freeCashflow': '잉여현금흐름',  # 기업의 본원적 영업활동을 위해 현금을 창출하고, 영업자산에 투자하고도 남은 현금
        'totalCashPerShare': '주당현금흐름',
        'currentRatio': '유동비율',  # 회사가 가지고 있는 단기 부채 상환 능력
        'quickRatio': '당좌비율',  # 회사가 가지고 있는 단기 부채 상환 능력
        
        
        # 경영 효율 관련
        'returnOnAssets': '자기자본이익률',  # mrq : 간단히 말해, 얼마를 투자해서 얼마를 벌었냐
        'returnOnEquity': '총자산순이익률',  # mrq : ROE와 비교하여 기업이 가지고 있는 부채의 비중을 볼 때
        'grossMargins': '매출총이익률',  # ttm : 매출이익(매출액 - 매출원가) / 매출액 : 매출이익률, Gross Profit Margin (GPM)
        'operatingMargins': '영업이익률',  # ttm : 매출총이익 - 판관비 - 감가상각비
        'profitMargins': '순이익률',  # ttm : Net Income(순이익) / Revenue(총수익) : 순이익률, Net Profit Margin (NPM)
        
        # 기업 자산 관련
        'totalCash': '총현금액',
        'totalDebt': '총부채액',
        
        # 기업 가치 관련
        'priceToBook': 'PBR',  # 기업이 가진 순 자산에 비해 주가가 얼마나 비싼지
        'enterpriseValue': '기업가치',  # 기업가치 : 시가총액 + (총차입금 - 현금성 자산)
        'enterpriseToRevenue': 'EV/R',  # 매출액대비 기업가치 비율
        'enterpriseToEbitda': 'EV/EBITDA',  # EBITDA대비 기업가치 비율 : PER과 의미적으로 비슷한 지표
        'forwardEps': '선행1년EPS',  # 주당순이익, 보통 5년동안의 EPS를 관찰해서 추이를 봄
        'trailingEps': '1년EPS',  # 주당순이익 = 당기순이익 / 유통주식수
        'priceToSalesTrailing12Months': '1년PSR',  # 주가매출액비율 (1년 기준)
        'forwardPE': '선행1년PER',  # 향후 1년동안 예상되는 PER
        'trailingPE': '1년PER',  # 현재 PER. 기업이 한 주당 벌어들이는 순이익에 비해, 실제 주가가 몇 배가 되는 지 나타내는 지표. 고평가 저평가에 사용
        
        # 배당 관련
        'dividendYield': '배당수익률',  # 현재 기준 배당 수익률
        'payoutRatio': '배당성향',  # 20 ~ 60% 사이가 일반적.
        'trailingAnnualDividendYield': '1년배당수익률',  # 지난 1년간 배당 수익률
        'dividendRate': '주당수익달러',
        'trailingAnnualDividendRate': '1년주당수익달러',
        
        # 성장성 관련
        'revenueGrowth': 'mrq매출액증가율',
        'earningsGrowth': 'mrq수익상승률',
        'earningsQuarterlyGrowth': 'yoy수익상승률',  # yoy : 지난해 동일 분기 대비 최근 분기의 수익 상승률
        'revenueQuarterlyGrowth': 'yoy매출상승률',  # yoy : 지난해 동일 분기 대비 최근 분기의 매출 상승률
        'heldPercentInsiders': '직원보유비율',
    }
    
    financial_columns_mapper = {
        'Research Development': 'R&D비용',
        'Net Income': '순이익',
        'Gross Profit': '매출총이익',
        'Operating Income': '영업이익',
        'Total Revenue': '총매출',
        'Cost Of Revenue': '제품원가',
    }
    
    balance_sheet_columns_mapper = {
        'Total Liab': '총부채',
        'Total Stockholder Equity': '자기자본',
        'Total Assets': '총자산',
    }

     

    아래 코드는 나스닥 종목 중, 시가총액이 100,000,000불 이상인 종목들 중에, 20개만 잘라서 수행을 해 본 것이다. 이런식으로 보고싶은 종목의 규칙을 만들어서 사용해야 정상적인 크롤링을 수행할 수 있다.

     

    df = pd.DataFrame()
    
    temp_df = nasdaq_df[nasdaq_df['Market Cap']>100000000]
    for index, row in temp_df.iloc[:20, ].iterrows():
        ticker_start_time = time.time()
        symbol = row['Symbol']
        ticker = yf.Ticker(symbol)
        raw_info = ticker.info
        try:
            if raw_info['quoteType'] == 'EQUITY':  # ETF를 제외한 개별 종목
                inner_dict = {}
    
                # 기본 정보 추가
                inner_dict['symbol'] = row['Symbol']
                inner_dict['name'] = row['Name']
                inner_dict['country'] = row['Country']
                inner_dict['origin_sector'] = row['Sector']
                inner_dict['industry'] = row['Industry']
    
                # info 정보 추가
                for info_column in info_columns_mapper:
                    value = raw_info[info_column]
                    inner_dict[info_columns_mapper[info_column]] = value
    
                # ticker.financials : 직전 4년 매출관련 데이터 추가
                financial_dict = ticker.financials.T.to_dict('list')
                for financial_column in financial_columns_mapper:
                    value_list = list(reversed(financial_dict[financial_column]))
                    inner_dict["list_financial_" + financial_columns_mapper[financial_column]] = value_list
    
                # ticker.balance_sheet : 직전 4년 재무상태 데이터 추가
                balance_sheet_dict = ticker.balance_sheet.T.to_dict('list')
                for balance_sheet_column in balance_sheet_columns_mapper:
                    value_list = list(reversed(balance_sheet_dict[balance_sheet_column]))
                    inner_dict["list_balancesheet_" + balance_sheet_columns_mapper[balance_sheet_column]] = value_list
    
                # append to df
                df = df.append(inner_dict, ignore_index=True)
                
                # time check
                print(symbol)
                print("--- %s seconds ---" % (time.time() - total_start_time))
        except Exception as e:
            print(symbol, 'Error:', e)

     

     

    이를 실행해보면 다음과 같이 데이터를 pandas 형태로 정리할 수 있다. 이제 이 결과를 가지고 각자 분석 주제를 정해 분석을 수행해보도록 하자.

     

     

     

     

     

     

     

    댓글

분노의 분석실 Y.LAB