본문 바로가기

컴퓨터, IT/프로그래밍

[파이썬] 키움 API로 전종목 일봉 요청하기

반응형

키움증권에서는 OpenAPI를 제공하고 있습니다.

개인 투자자들은 별도의 비용 없이 키움증권 계좌가 있으면 API 사용 신청을 할 수 있습니다.

 

전 종목 일봉데이터를 다운로드 요청하는 코드를 포스팅합니다.

 

1. 키움 종목코드 개수

2월 기준으로 3천 종목이 조금 넘습니다. (2/7, 3065종목)

TR5회당 20초로 시간 간격을 설정하면 3시간 30분 소요됩니다.

# 3065종목 시작 16:44 종료 20:08 소요 03:24 (204분)

 

2. 사용 TR함수

OPT100081 을 사용합니다.

1회 요청시 종목의 900일치 시가/고가/저가/종가/거래량을 받아옵니다.

 

3. 전 종목을 대상으로 특정일에 해당하는 가격정보를 받는 방법은 없는지?

없습니다.

 

추후 업데이트도 고려하고 있지 않는다는 답변을 받았습니다.

이 부분에 대해서는 pykrx를 이용하여 특정일의 시세데이터를 받을 수 있으나,

pykrx가 제공하는 종목수는 2천 종목으로 키움과 1:1 매칭이 안됩니다..

 

종목 개수가 1:1로 매칭이 안되는 것은

아마도 리츠 등 특수한 종목을 pykrx에서 제공하지 않기 때문인 것으로 생각합니다.

 

4. 코드

전 종목은 요청하는 메소드.

사전에 self.kw에 comm_rq_data 가 정의되어 있어야 합니다.

def get_all_daily_price(self):
    """ 전 종목에 대해서 일봉 데이터 요청 및 DB저장  (3시간 정도 소요) """
    file = "./CodeList.db"
    if os.path.isfile(file):
        con = sqlite3.connect(file)
        df_codes = pd.read_sql("SELECT * FROM CodeList", con, index_col='index')
        con.close()
    else:
        self.msgbox.setText("종목코드 생성 필요")
        self.msgbox.exec_()
        return

    for code in df_codes.index:
        ohlcv = None
        input_dict = {}
        input_dict['종목코드'] = code
        input_dict['틱범위'] = 1
        input_dict['수정주가구분'] = 1

        self.kw.set_input_value(input_dict)
        self.kw.comm_rq_data("opt10081_req", "opt10081", 0, "0101")
        # OPT 10081 = 주식 일봉 차트 요청

        ohlcv = self.kw.latest_tr_data
        recieve_counter = 0
        while self.kw.is_tr_data_remained == True:
            recieve_counter += 1
            if recieve_counter < 1:
                self.kw.set_input_value(input_dict)
                self.kw.comm_rq_data("opt10081_req", "opt10081", 2, "0101")
                for key, val in self.kw.latest_tr_data.items():
                    ohlcv[key][-1:] = val
            else:
                break
        df2 = pd.DataFrame(ohlcv, columns=['open', 'high', 'low', 'close', 'volume'], index=ohlcv['date'])
        con2 = sqlite3.connect("./DailyPrice.db")
        df2.to_sql(code, con2, if_exists='append')

 

아래는 self.kw 인스턴트에 선언되어 있는 comm_rq_data 메소드입니다.

 

def comm_rq_data(self, rqname, trcode, next, screen_no):
    """
    서버에 조회 요청을 하는 메소드
    이 메소드 호출 이전에 set_input_value 메소드를 수차례 호출하여 INPUT을 설정해야 함
    """
    self.is_tr_running = 1
    self.dynamicCall("CommRqData(QString, QString, int, QString)", rqname, trcode, next, screen_no)

    self.tr_event_loop = QEventLoop()
    self.tr_event_loop.exec_()

    # 키움 Open API는 시간당 request 제한이 있기 때문에 딜레이를 줌
    if self.TR_REQ_COUNTER == 1:
        self.TR_LAST_TIME = datetime.datetime.now()

    # 1초에 5번 RQ시 17초 대기
    timenow = datetime.datetime.now()
    timegap = timenow - self.TR_LAST_TIME
    timegap = timegap.seconds
    timerest = int(17 - timegap)

    if (self.TR_REQ_COUNTER % 5) == 0:
        print("{}| TRcnt {} % 5 == 0, Long sleep".format(timenow, self.TR_REQ_COUNTER))
        time.sleep(18)
        self.is_tr_running = 0
    else:
        print("{}| TRcnt {} % 5 != 0, Short sleep".format(timenow, self.TR_REQ_COUNTER))
        time.sleep(self.TR_REQ_TIME_INTERVAL_SHORT)
        self.is_tr_running = 0
    self.TR_REQ_COUNTER += 1

 

 

5. 보완점

키움에서 종목코드 다운을 하면 3천종목이 나오는데,

솔직히 전체 종목을 분석할 일은 많지 않습니다.

 

시가총액 기준으로 분석할 종목을 끊어서 리스트형태로 코드를 담아둔 다음에,

리스트를 for로 돌려서 사전에 특정한 코드들 대상으로 일봉을 요청한다면,

소요되는 시간이 더욱 줄어들 것입니다.

 

3천 종목에 3시간이니,

1천5백 종목이면 1시간30분이면 되지 않을까 생각합니다.

 

 

 

pixabay : https://pixabay.com/images/id-5660546/