파이썬을 이용한 한국주식(코스피, 코스닥) 주가 데이터 수집 - FinanceDataReader, pykrx, pandas_datareader, yfinance 비교

목차

    0. 관련 글 목록


    1. 들어가며

    이번 글에서는 한국 주식의 주가 데이터를 수집할 때 사용할 수 있는 4개의 파이썬 패키지를 비교해보려고 한다.

    패키지 간의 비교는 (1)종목 리스트 조회, (2)상장 종목의 주가 데이터 조회, (3)상장폐지 종목의 주가 데이터 조회를 기준으로 수행하였다.

    import FinanceDataReader as fdr
    from pykrx import stock
    import pandas_datareader.data as pdr
    import yfinance as yf

    2. 종목 리스트 조회

    생존편향(survivorship bias)을 고려하여 주가 데이터를 수집하려면 백테스트에 사용할 데이터에 상장폐지 종목도 포함되어 있어야 한다. 이를 위해서는 어떤 종목이 어떤 시점에 상장되어 있고, 어떤 종목이 어떤 시점에 상장폐지 되었는지 알 수 있어야 하기 때문에 상장종목의 리스트와 상장폐지 종목의 리스트의 조회가 가능해야 한다. 도입부에서 나열한 4개의 패키지 중 FinanceDataReader와 pykrx가 이 기능을 제공하고 있다. FinanceDataReader는 현재 시점에서 가장 가까운 영업일 기준의 상장종목과 상장폐지 종목 리스트 조회 기능을 제공하고 있고, pykrx는 특정일자의 상장종목 리스트 조회 기능을 제공하고 있다.

    2.1. FinanceDataReader

    • 현재 시점의 시장별 상장종목 리스트를 가져올 수 있음
    • 종목코드, 시장, 종목명, 섹터, 산업군, 상장일, 결산월, 대표자, 홈페이지, 사업체 지역을 알 수 있음
    • 과거 특정 시점의 상장종목 리스트는 알 수 없으나 상장폐지 종목을 조회할 수 있음
    # 가장 최근 영업일의 시장별 종목리스트를 가져옴
    stocks = fdr.StockListing('KRX') # 코스피, 코스닥, 코넥스 전체
    stocks

    stocks.info()
    
    <class 'pandas.core.frame.DataFrame'>
    Int64Index: 7633 entries, 0 to 7632
    Data columns (total 10 columns):
     #   Column          Non-Null Count  Dtype         
    ---  ------          --------------  -----         
     0   Symbol          7633 non-null   object        
     1   Market          7633 non-null   object        
     2   Name            7633 non-null   object        
     3   Sector          2499 non-null   object        
     4   Industry        2481 non-null   object        
     5   ListingDate     2499 non-null   datetime64[ns]
     6   SettleMonth     2499 non-null   object        
     7   Representative  2499 non-null   object        
     8   HomePage        2348 non-null   object        
     9   Region          2499 non-null   object        
    dtypes: datetime64[ns](1), object(9)
    memory usage: 656.0+ KB
    # KRX stock delisting symbol list 상장폐지 종목 전체 리스트
    krx_delisting = fdr.StockListing('KRX-DELISTING')
    krx_delisting

    krx_delisting.info()
    
    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 3355 entries, 0 to 3354
    Data columns (total 15 columns):
     #   Column             Non-Null Count  Dtype         
    ---  ------             --------------  -----         
     0   Symbol             3355 non-null   object        
     1   Name               3355 non-null   object        
     2   Market             3355 non-null   object        
     3   SecuGroup          3355 non-null   object        
     4   Kind               3355 non-null   object        
     5   ListingDate        3355 non-null   datetime64[ns]
     6   DelistingDate      3355 non-null   datetime64[ns]
     7   Reason             3355 non-null   object        
     8   ArrantEnforceDate  989 non-null    datetime64[ns]
     9   ArrantEndDate      989 non-null    datetime64[ns]
     10  Industry           3355 non-null   object        
     11  ParValue           3124 non-null   float64       
     12  ListingShares      3307 non-null   float64       
     13  ToSymbol           3355 non-null   object        
     14  ToName             3355 non-null   object        
    dtypes: datetime64[ns](4), float64(2), object(9)
    memory usage: 393.3+ KB

    2.2. pykrx

    • 특정 시점의 상장 종목코드 조회 가능
    • 해당 종목코드의 종목명을 조회하는 함수가 별도로 존재
    # 날짜를 명시해주지 않으면 가장 최근 영업일의 시장별 종목리스트를 가져옴
    tickers = stock.get_market_ticker_list()
    tickers[:6], tickers[-6:]
    
    (['095570', '006840', '027410', '282330', '138930', '001460'],
     ['005010', '069260', '000540', '000547', '000545', '003280'])
     
    tickers = stock.get_market_ticker_list('2010-01-01')
    tickers[:6], tickers[-6:]
    
    (['004560', '004565', '001460', '001465', '084680', '001040'],
     ['005010', '069260', '000540', '000547', '000545', '003280'])
     
     stock.get_market_ticker_name('005930')
     
     '삼성전자'

    3. 상장종목의 주가 조회

    이번에는 상장 종목의 주가 정보를 조회해보자. 주가 정보를 제공하는 패키지들은 보통 OHLCV(시가/고가/저가/종가/거래량) 형태로 데이터를 제공하며, 액면분할 등을 고려한 수정주가를 보여주는데 패키지에 따라 거래량은 보정이 안된 경우가 있다. 이번 글에서는 삼성전자(005930)의 주가 데이터 조회를 예시로 들어보려고 한다. 삼성전자의 상장일은 1975년 6월 11일인데 이 시점부터 데이터를 제공하는 패키지는 없었고, 패키지마다 데이터 제공 시작시점이 모두 달랐다.

    3.1. FinanceDataReader

    • 조회 시점에 따라 조회할 수 있는 최대 과거 시점이 변동됨
    • 예를 들어, 2022-03-22에 조회했을 때는 1998-02-05부터 조회됐었는데, 2022-03-23에 조회했을 때는 1998-02-06부터 조회됨 - 네이버금융에서 데이터를 가져오는데 일자가 지날 때 마다 과거 데이터를 삭제하는 것으로 보임
    • 액면분할을 반영한 수정주가가 조회되는데 거래량은 보정되지 않은 상태임
    start_date = '1975-06-11'
    end_date = '2022-03-23'
    
    df_fdr = fdr.DataReader('005930', start=start_date, end=end_date)
    df_fdr

    3.2. pykrx

    • 1990년 데이터부터 조회 가능
    • 수정주가가 디폴트로 조회됨(adjusted 옵션으로 수정주가 여부 설정가능)
    • adjusted=False로 조회하면 1995-05-02부터 조회되고, 거래대금과 등락률 칼럼이 추가됨
    • 액면분할을 반영한 수정주가가 조회되는데 거래량은 보정되지 않은 상태임
    df_pykrx = stock.get_market_ohlcv_by_date(fromdate=start_date, 
                                              todate=end_date,
                                              ticker="005930")
    df_pykrx

    df_pykrx = stock.get_market_ohlcv_by_date(fromdate=start_date, 
                                              todate=end_date,
                                              ticker="005930", adjusted=False)
    df_pykrx

    3.3. pandas_datareader

    • 데이터소스를 naver로 지정하면 1990년 데이터부터 조회할 수 있고, yahoo로 지정하면 2000년 데이터부터 조회할 수 있음
    • 액면분할이 고려된 수정주가로 조회됨
    • yahoo finance를 데이터소스로 사용할 때는 종목코드 뒤에 코스피 종목인 경우 .KS, 코스닥 종목인 경우 .KQ를 붙여줘야 함
    df_pdr = pdr.DataReader('005930', 'naver', start=start_date, end=end_date)
    df_pdr

    # yahoo finance를 데이터 소스로 사용할 때는 종목코드 뒤에 코스피 종목인 경우 .KS, 코스닥 종목인 경우 .KQ를 붙여줘야 함
    df_pdr = pdr.DataReader('005930.KS', 'yahoo', start=start_date, end=end_date)
    df_pdr

    3.4. yfinance

    • yahoo finance를 데이터 소스로 사용하는 패키지이기 때문에 위에서 설명한 바와 같이 코스피 종목에는 .KS, 코스닥 종목에는 .KQ를 붙여줘야 함
    • 가장 다양한 정보 확인 가능 - 배당정보, 분할정보, 재무정보 등
    • 2000년 데이터부터 조회 가능
    • end에 설정한 일자의 전일자까지 조회되기 때문에 조회하고자 하는 종료일+1일을 end에 넣어줘야함
    • 분단위 데이터도 조회 가능하지만 조회 가능한 기간에 제한이 있음
    ticker = yf.Ticker('005930.KS')
    
    ticker.history(
                   interval='1d',
                   start=start_date,
                   end='2022-03-24',
                   actions=True,
                   auto_adjust=True)

    # 분단위 데이터 조회. 조회할 수 있는 기간에 제한이 있음
    # 마지막행의 데이터는 당일 종가로 조회되는 듯?
    df_minute = ticker.history(
                   interval='1m',
                   start='2022-03-20',
                   end='2022-03-22',
                   actions=True,
                   auto_adjust=True)
    df_minute

    # 재무정보도 조회가능
    ticker.financials


    4. 상장폐지 종목의 주가 조회

    상장폐지 종목의 주가 조회는 FinanceDataReader, pykrx, pandas_datareader에서 데이터 소스를 naver로 설정했을 때만 가능하다. yahoo finance에서는 상장폐지 종목에 대한 정보를 제공하지 않고 있는 것 같다. 상장폐지 종목의 리스트는 앞에서 설명한 것처럼 FinanceDataReader를 통해 조회하면 된다.

    4.1. FinanceDataReader

    krx_delisting[krx_delisting.Symbol=='001047']

    # KRX delisting stock data 상장폐지된 종목 가격 데이터 (상장일~상장폐지일)
    df = fdr.DataReader('001047', exchange='KRX-DELISTING')
    df

    4.2. pykrx

    stock.get_market_ohlcv_by_date(fromdate=start_date, 
                                   todate=end_date,
                                   ticker="001047")

    4.3. pandas_datareader

    df_pdr = pdr.DataReader('001047', 'naver', start=start_date, end=end_date)
    df_pdr


    5. 패키지별 특정 기간의 값 비교

    2000년 1월 4일 ~ 2000년 1월 7일의 삼성전자 데이터를 비교해보자.

    start_date = '2000-01-01'
    end_date = '2000-01-07'
    # FinanceDataReader
    df_fdr = fdr.DataReader('005930', start=start_date, end=end_date)
    df_fdr

    # pykrx
    df_pykrx = stock.get_market_ohlcv_by_date(fromdate=start_date, 
                                              todate=end_date,
                                              ticker="005930")
    df_pykrx

    # pandas_datareader - naver
    df_pdr = pdr.DataReader('005930', 'naver', start=start_date, end=end_date)
    df_pdr

    # pandas_datareader - yahoo
    df_pdr = pdr.DataReader('005930.KS', 'yahoo', start=start_date, end=end_date)
    df_pdr

    # yfinance
    ticker = yf.Ticker('005930.KS')
    ticker.history(
                   interval='1d',
                   start=start_date,
                   end='2000-01-08',
                   actions=True,
                   auto_adjust=False)

    krx나 naver를 데이터 소스로 사용하는 경우에는 거래량이 액면분할을 고려하지 않은 상태로 조회되고, yahoo finance를 데이터 소스로 사용하는 경우에는 거래량이 액면분할을 고려한 상태로 조회된다(1483967*50=74198350).