본문 바로가기
주식분석/Quant 분석(프로그래밍)

주식 전종목 어떻게 불러올까? 거래소 종목 불러오기

by hustler78 2023. 4. 6.
728x90
반응형

주식 매수 신호를 잡는 기가 막힌 아이디어가 떠오르고, 그 아이디어를 코딩으로 구현을 했다고 합시다. 또는 pine script를 써서 HTS 차트 상에 신호를 띄울 수도 있겠죠.

하지만, 일일이 종목을 검색해 가며 신호를 찾을 수는 없는 노릇입니다. 코딩으로 거래소에 상장되어 있는 모든 종목만 불러올 수 있다면! 그 종목을 for문 등으로 돌리면서 재빨리 신호가 잡힌 종목들을 추출해 낼 수 있겠죠.

 

이번 글에서는 우선 한국거래소(Korea Exhange, KRX)에 상장된 종목들을 불러오는 연습을 해 볼까 합니다.

 

제가 주로 쓰는 방법은 두 가지가 있습니다.

 

 

상장 주식 모두 불러오기

저는 크게 두 가지 방법을 사용하고 있습니다.

 

○ 직접 거래소 사이트에 붙어, 거래소에서 제공하는 상장법인 표 가져오기

 

○ 현자께서 잘 만들어 놓은 python 라이브러리 사용하기

 

거래소 사이트에서 가져오기
import pandas as pd
import FinanceDataReader as fdr

def load_allstock_KRX():
    krx_url = 'https://kind.krx.co.kr/corpgeneral/corpList.do?method=download&searchType=13'
    stk_data = pd.read_html(krx_url, header=0)[0]
    stk_data = stk_data[['회사명', '종목코드']]
    stk_data = stk_data.rename(columns={'회사명': 'Name', '종목코드': 'Code'})

    stk_data['Code'] = stk_data['Code'].apply(lambda input: '0' * (6 - len(str(input))) + str(input))

    return stk_data

 

위 코드의 url 이 하나 적혀 있습니다. 바로 여기 이죠. 실제 이 사이트를 들어가본다면(파이썬 스크립트에서 Ctrl을 누른 상태에서 위 url을 누르면 바로 접속이 가능합니다.) 다음과 같은 엑셀 파일이 생성됩니다.

 

상장법인목록 (3).xls
0.93MB

 

엑셀 파일은 다음과 같이 구성되어 있습니다.

거래소에서 가져온 상장법인목록.xlsx

 

보면 9개의 열( column, feature 라고도 부름)로 이루어져 있습니다.

 

회사명 종목코드 업종 주요제품 상장일 결산월 대표자명 홈페이지 지역

일단 우리가 필요한 것은 회사명과  종목코드입니다. 사실 종목코드만 알아도 yfinance나 FinanceDataReader 등의 python library를 통하여 주가 정보를 부를 수 있지만, 그 코드의 종목명을 알아야 쓸모가 있겠죠.

 

그래서 우선, 회사명과 종목코드를 가지는 dataframe을 따와서 분석을 하겠습니다.

 

나중에 업종 분석이나, 대표자 중에 큰 손이 있는지 등을 판단하기 위해 나머지 column 들도 필요할 수 있으니 기억은 하고 있는 게 좋을 것 같습니다. 

 

여기까지 사전 지식을 바탕으로 저 코드에 주석 설명을 달면 아래와 같습니다.

 

def load_allstock_KRX():
    # KRX site에서 제공하는 상장법인목록 load
    krx_url = 'https://kind.krx.co.kr/corpgeneral/corpList.do?method=download&searchType=13'
    stk_data = pd.read_html(krx_url, header=0)[0]  # 해당 site에서 table 추출 및 header는 가장 첫번째 행
    stk_data = stk_data[['회사명', '종목코드']]     # 9개의 열 중 '회사명', '종목코드' 만 추출하여 dataframe 완성
    stk_data = stk_data.rename(columns={'회사명': 'Name', '종목코드': 'Code'})
                                                   # column 명을 한글에서 영어로 바꿈
    
    # 종목코드가 모두 6자리로 이루어져있지만 혹시 모르니, 6자리 미만 코드는 앞에 0을 채워넣어
    # 6자리 숫자텍스트로 변환
    stk_data['Code'] = stk_data['Code'].apply(lambda input: '0' * (6 - len(str(input))) + str(input))
                                   
    return stk_data

 

 

read_html 은 pandas에서 제공하는 함수로서 URL에 있는 표(table)를 긁어오는 역할을 합니다.

 

header =0으로 지정하여 0번째(즉, 첫 번째 행)가 column명이라는 것을 밝혀줍니다.

 

rename으로 dataframe의 column명을 변경할 수 있습니다.

 

lambda input: '0' * (6 - len(str(input))) + str(input)

   lambda 문법을 사용하여 간략한 함수를 만듭니다. input이 6자리 미만이면 앞에 0을 채워 넣어 6자리 숫자테스트로

  강제하는 함수입니다. 

 

결과를 실행시키면 아래처럼 나옵니다. index 넘버가 0~2589 인 것으로 보아 총 2,590개의 종목이 불러와졌네요.

 

    df_stock = load_allstock_KRX()
    print(df_stock)         # 위의 5행 print

 

           Name    Code
0        AJ네트웍스  095570
1       BNK금융지주  138930
2           DSR  155660
3            GS  078930
4     HDC현대산업개발  294870
...         ...     ...
2585    지앤이헬스케어  299480
2586     카이바이오텍  446600
2587     코스텍시스템  169670
2588       타임기술  318660
2589   한국미라클피플사  331660

 

 

 

FinanceDataReader 라이브러리 사용

다음은 FinanceDataReader에서 편하게 불러올 수 있는 방법입니다.

 

def load_allstock_KRX_fdr():
    df_krx = fdr.StockListing("KRX")
    df_krx = df_krx[['Code', 'Name', 'MarketId']]
    return df_krx

StockListing이라는 함수로 불러옵니다. fdr 은 FinanceDataReader의 별칭이죠.

StockListing의 결과는 많은 column으로 이루어져 있습니다. 

 

    df_krx = fdr.StockListing("KRX")
    print(df_krx.columns)       # column information 조회

위의 code로 column을 조회하면 

Index(['Code', 'ISU_CD', 'Name', 'Market', 'Dept', 'Close', 'ChangeCode',
       'Changes', 'ChagesRatio', 'Open', 'High', 'Low', 'Volume', 'Amount',
       'Marcap', 'Stocks', 'MarketId'],

위와 같이 column이 잔뜩 나옵니다.  종목 코드, 종목명뿐만 아니고, 거래소 내 어떤 시장인지, 또 시고 저 종 정보와 일일 등락률, 시가총액 등 구체적인 정보를 제공합니다. 

여기서 우리한테 필요한 정보는 'Code', 'Name', 'MarketId' 정보면 충분할 것 같습니다.

MarketID column은 해당 기업이 Kospi, Kosdaq, Konex 중 어느 시장에 상장되어 있는지는 알려주는 시장 정보입니다.

 

    df_krx = df_krx[['Code', 'Name', 'MarketId']]

로 열을 제한하여 표현하면 아래와 같은 정보를 얻습니다.

 

        Code      Name MarketId
0     005930      삼성전자      STK
1     373220  LG에너지솔루션      STK
2     000660    SK하이닉스      STK
3     207940  삼성바이오로직스      STK
4     006400     삼성SDI      STK
...      ...       ...      ...
2708  267060     명진홀딩스      KNX
2709  308700       테크엔      KNX
2710  322190        베른      KNX
2711  058420      제이웨이      KSQ
2712  271850      다이오진      KNX

어라, FinanceDataReader로 조회해 보니, 데이터의 개수가 0 ~ 2712까지 2,713개가 잡히네요.  첫 번째 방법처럼 거래소자료에 붙어 가져온 정보에는 2,590개였는데요. 123개의 데이터 개수 차이가 있네요.

 

과연 어떤 차이인지 알아보겠습니다.

 

 

 

 

거래소 상장목록과 FinanceDataReadr 정보의 개수 차이는?

 

아래의 코드를 살펴봅시다. 목적은

FinanceDataReader로는 조회가 되나, 거래소 엑셀 자료에서는 보이지 않는 자료를 출력해 볼 예정입니다.

즉 FDR 자료와 거래소 자료의 차집합을 보는 것이죠.

 

import pandas as pd
import FinanceDataReader as fdr

def load_allstock_KRX():
    krx_url = 'https://kind.krx.co.kr/corpgeneral/corpList.do?method=download&searchType=13'
    stk_data = pd.read_html(krx_url, header=0)[0]
    stk_data = stk_data[['회사명', '종목코드']]
    stk_data = stk_data.rename(columns={'회사명': 'Name', '종목코드': 'Code'})

    stk_data['Code'] = stk_data['Code'].apply(lambda input: '0' * (6 - len(str(input))) + str(input))

    return stk_data


def load_allstock_KRX_fdr():
    df_krx = fdr.StockListing("KRX")
    df_krx = df_krx[['Code', 'Name', 'MarketId']]
    return df_krx


if __name__  == '__main__':

    df_stock = load_allstock_KRX()         # KRX site load : column={Name, Code}
    df_stock_fdr = load_allstock_KRX_fdr() # FDR library load : colume= {Name, Code, MarketID}

    # 위 두 dataframe 을 merge 함수를 사용하여 join할 예정
    # how = outer로 하여 outer join을 실행하고
    # indicator = True로 하여 data가 어떤 dataframe에 속하는지를 판단해줌
    # indicator = True 를 하면, both, left_only, right_only 이렇게 3값중 하나를 출력하는
    # '_merge' 라는 column 생성됨
    
    df_merge =pd.merge(df_stock[['Code']], df_stock_fdr[['Code']], how='outer', indicator=True)
    print(df_merge)
    
    # merge한 dataframe의 merging 정보의 3가지 유형의 값이 각각 몇 개 있는지 세어봄
    print(df_merge.groupby('_merge').count())

    # _merge가 right only 인 것만 추출
    df_differ = df_merge.query('_merge=="right_only"')
    
    # financedatareader 에서 뽑은 dataframe가 inner join 함
    df_res = pd.merge(df_stock_fdr, df_differ, how='inner')

    print(df_res)  # 결론적으로 fdr는 추출이 되나, 거래소 자료에는 빠진 종목이 출력됨

pandas.merge 용법을 기억해 둘 필요가 있습니다.

 

dataframe.groupby , dataframe.query 함수 용법을 알아둡시다.

 

 

 

결과는 아래와 같습니다.

# outer join으로 merge 한 자료
# df_stock 과 df_stock_fdr의 모든 data가 등장하며
# 둘 다 속한 자료는 both
# df_stock에 속한 자료는 left_only
# df_stock_fdr에 속한 자료는 right_only
       Code      _merge
0     095570        both
1     138930        both
2     155660        both
3     078930        both
4     294870        both
...      ...         ...
2708  001527  right_only
2709  001525  right_only
2710  002787  right_only
2711  021045  right_only
2712  000547  right_only

[2713 rows x 2 columns]
            Code

# df_merge의 '_merge' 열의 3가지 값, left_only, right_only, both 에 해당하는
# 자료의 갯수
# left_only 는 없는 것으로 보아 fdr 자료가 거래소 자료를 완전히 포함하고 있음
# both : 2590개로 거래소 자료와 동일
# right_only : fdr 정보는 거래소정보를 포함하면 추가적으로 123개가 더 있음
_merge          
left_only      0
right_only   123
both        2590


# 위 merge결과를 fdr 정보와 inner merge해 보면
# 어떤 종목들이 fdr에 더 포함되는지 알 수 있음

      Code     Name         MarketId      _merge
0    005935    삼성전자우      STK  right_only
1    005387   현대차2우B      STK  right_only
2    051915    LG화학우      STK  right_only
3    005385     현대차우      STK  right_only
4    066575    LG전자우      STK  right_only
..      ...      ...      ...         ...
118  001527    동양2우B      STK  right_only
119  001525      동양우      STK  right_only
120  002787  진흥기업2우B      STK  right_only
121  021045   대호특수강우      KSQ  right_only
122  000547  흥국화재2우B      STK  right_only

[123 rows x 4 columns]

 

주석을 잘 읽어주세요. 결론은 이렇습니다.

 

1) FDR 자료가 거래소에서 뽑은 자료를 완전히 포함한다

 

2) FDR 에는 속하면서 거래소 자료에 있지 않은 종목들을 뽑아본 결과 모두

 

우선주

 

임을 확인할 수 있습니다. 하긴 그도 그럴 것이 거래소에서 엑셀로 제공하는 상장법인 목록은 보통주, 우선주를 가리지 않지만, FinanceDataReader에서는 이 둘이 구분되기 때문입니다.

 

벤다이어 그램으로 표시해 볼까요?

 

 

 

결론

두 방법을 비교했을 땐, 거래소 자료를 표로 가져오는 것보다는 FinanceDataReader를 통한 데이터 입수가 더 좋아 보입니다. 하지만 염두에 두고 있어야 하는 것이

1) 거래소 데이터 입수 방법의 변경이 있으면 그에 맞춰 새로운 코드로 개선해야 한다는 것

2) FinanceDataReader는 서비스 정신이 투철한 파이썬 개발자 그룹이 사용자의 편의를 위해 봉사해 준 라이브러리

이기 때문에 업데이트 여부나 자료의 정합성을 꾸준히 체크해 줘야 한다는 점입니다.

 

앞으로 개발자 분들의 선의를 신뢰하며 FinanceDataReader에 의지해 보도록 하죠!

 

 

728x90
반응형

댓글