ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • PER PBR 활용03 : 주식별 PER PBR 목록 만들기
    금융퀀트/(퀀트)PERPBR활용 2023. 6. 1. 02:39
    반응형

    "개별주식 PER, PBR"과 "주식목록"

    우리는 04 투자전략: PER PBR 활용01(PER PBR 데이터 입수:python)에서 네이버 증권(https://finance.naver.com/)을 통해서 개별 주식의 PER, PBR을 구하는 getPerPbr 함수를 만들었고, 04 투자전략: PER PBR 활용02(주식목록 구축: 공공데이터API) 에서 공공데이터 포털(https://www.data.go.kr) API를 통해서 기준 일자의 주식 코드, 종가, 시가총액 LIST를 받아오는 getStockList 함수를 만들었다. 이제 두 함수를 같이 사용하여 기준 일자의 주식  코드, 종가, 시가총액, PER, PBR 등을 한 번에 볼 수 있는 통합 데이터를 만들어 보자. 

    주식코드별 PER, PBR 데이터 목록 생성

    주식코드를 getPerPbr 함수에 넣으면 아래 그림과 같이 '주식코드', 'PER', 'PBR'로 이루어진 한 줄짜리 DataFrame을 얻을 수 있다.

    그림1: getPerPbr 함수 결과 예시

    따라서 getStockList를 통해서 입수된 주식코드를 하나씩 getPerPbr 함수에 넣으면 각각의 주식코드별로 PER, PBR 을 보여주는 한 줄짜리 DataFrame 들을 얻을 수 있다. 이 DataFrame 들을 pandas 라이브러리의 concat 함수를 써서 Row 를 계속 추가해주면, getStockList 를 통해서 입수된 주식코드 전체에 대한 PER, PBR 값을 보여주는 하나의 데이터를 만들 수 있다. 아래는 예시 코드이다. 

     

    # getStockList 함수에 pageNo=1, 기준일자: 2023-05-24, 출력Row: 30, opikey 를 넣어서 나온 결과
    # df_a 에 저장
    df_a = getStockList(1, "20230524", "30", opendatakey)
    # df_b 빈 DataFrame 생성
    df_b = pd.DataFrame(columns=['주식코드', 'PER', 'PBR'])
    # df_a 의 "주식코드" 컬럼의 개별 값을 code 라는 변수에 넣고 각각 getPerPbr 함수에 입력
    # getPerPbr(code) 로 나온 DataFrame 와 기존에 설정해 둔 df_b DataFrame 을 통합
    for code in df_a["주식코드"]:
        df_b = pd.concat([df_b,getPerPbr(code)], ignore_index=True)

     

    결과를 확인해 보면, 먼저 getStockList 를 통해 입수한 데이터가 아래 그림 2의 왼쪽과 같이 구축되고 개별 주식코드를 getPerPbr 함수에 넣어서 DataFrame을 만들면 아래 그림 2의 오른쪽과 같은 데이터가 구축된다.

    그림2: 각 함수 실행 결과값

    주식 목록 데이터와 주식코드별 PER, PBR 데이터 통합

    merge 함수를 써서 위 그림 2의 두 DataFrame을 합치면 하나의 데이터로 주식의 종가, 시가총액, PER, PBR 등을 전부 확인할 수 있다. 위 코드의 df_b를 만들 때 사용한 concat 이 Row를 추가하는 함수라면, merge는 column을 추가하는 함수이다. merge 함수를 사용할 때 먼저 on과 how parameter는 필수적으로 체크해야 한다. on 은 두 데이터를 합칠 때 기준이 되는 컬럼을 나타내고, how는 on에 해당되는 컬럼을 기준으로 어떻게 합칠지를 나타낸다. on에 해당되는 데이터를 교집합만 합칠지(inner join), 합집합으로 합칠지(outer join), 왼쪽 데이터 기준으로 합칠지(left join), 오른쪽 데이터 기준으로 합칠지(right join)에 따라서 inner, outer, left, right로 나뉜다. 두 DataFrame 이 '주식코드'라는 컬럼명 동일하기 때문에 기준컬럼을 설정하는 on 은 따로 설정을 안 해줘도 된다. 그리고 두 데이터 모두 '주식코드' 값이 존재해야 하기 때문에 how='inner'로 설정한다. 전체 통합데이터를 나타내는 코드는 아래와 같다.

     

    import pandas as pd
    import requests
    from bs4 import BeautifulSoup
    
    opendatakey = "나의 API키"
    
    # getStockList 설정, pageno(숫자), 기준일자(문자열), 출력Row수(문자열), api키(문자열) 입수
    def getStockList(pageno:int, basedt:str, noofrows:str, apikey:str):
    	# df 라는 빈 LIST 생성
        df = []
        # page 별로 돌면서 기준일자, 출력Row수, api 키를 넣어서 API get요청
        for page in range(1,pageno+1):
            url = "https://apis.data.go.kr/1160100/service/GetStockSecuritiesInfoService/getStockPriceInfo"
            params = {
                "serviceKey":apikey,
                "pageNo": page,
                "basDt": basedt,
                "numOfRows" : noofrows
            }
            headers = {
                "accept": "application/xml"
            }
            res = requests.get(url, params=params, headers=headers)
            # response 를 soup 변수에 저장
            soup = BeautifulSoup(res.text, "lxml")
            # 데이터에서 종목코드, 종목명, 시장구분, 상장주식수, 시가총액을 찾아내서 df_if 리스트에 입수
            for stock in soup.find_all("item"):
                stockcode = stock.find("srtncd").text #종목코드
                stockname = stock.find("itmsnm").text #종목명
                mrkctg =  stock.find("mrktctg").text #시장구분
                lstgstcnt = stock.find("lstgstcnt").text #상장주식수
                mrkttotamt = stock.find("mrkttotamt").text #시가총액
                df_if = [stockcode, stockname, mrkctg, lstgstcnt, mrkttotamt]
                # 최초 설정한 df list 에 추가
                df.append(df_if)
        # DataFrame 설정
        df = pd.DataFrame(df, columns = ["주식코드", "주식명", "시장구분", "상장주식수", "시가총액"])
        return df
    
    # getPerPbr 설정, stcode(문자열) 입수
    def getPerPbr(stcode:str):
    	# df 라는 빈 LIST 생성
        df = []
        # 입수된 stcode 를 통해서 URL 조합 및 URL 로 get 요청
        url = "https://finance.naver.com/item/main.naver?code={}".format(stcode)
        res = requests.get(url)
        # response 를 soup 변수에 저장
        soup = BeautifulSoup(res.text, "lxml")
        # per pbr 데이터 찾아서 per, pbr 이라는 변수에 입수 n/a 일 경우 0 으로 처리
        try:
            per = soup.select_one("#_per").text
        except AttributeError:
            per = 0   
        try:
            pbr = soup.select_one("#_pbr").text
        except AttributeError:
            pbr = 0
        df_if = [stcode, per, pbr]
        # 최초 설정한 df list 에 추가
        df.append(df_if)
        # DataFrame 설정
        df = pd.DataFrame(df, columns=['주식코드', 'PER', 'PBR'])
        return df
    
    if __name__=="__main__":
    	# pageno = 2, 기준일자 2023-05-24, 출력 Row수 30, apikey 를 넣어서 getStockList 실행
        # 결과값 df_a 에 저장
        df_a = getStockList(2, "20230524", "30", opendatakey)
        # df_b 빈 데이터프레임 설정
        df_b = pd.DataFrame(columns=['주식코드', 'PER', 'PBR'])
        # df_a 의 "주식코드" 컬럼값을 차례로 code 라는 변수에 입력
        for code in df_a["주식코드"]:
        	# df_b 데이터프레임에 getPerPbr에 code를 입력해서 나온 데이터프레임을 Row 추가
            df_b = pd.concat([df_b,getPerPbr(code)], ignore_index=True)
        # df_a 와 df_b 를 '주식코드' 기준으로 inner join
        df = pd.merge(df_a, df_b, how='inner')
        # 최종 결과물 출력
        print(df)
    반응형
Designed by Tistory.