ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [키움API]파이썬 주식 종가정보 불러오기2: 개별종목 종가조회
    금융퀀트/(퀀트)증권사API활용(키움) 2023. 11. 30. 07:52
    반응형

    종목별 종가 입수 함수 확인: KOA 스튜디오 구현 예시

    종목별 종가정보 조회는 키움 API로 "주식일봉차트조회요청"을 하면 된다. KOA Studio에서 Open API 접속을 한 뒤에 아래 그림 1의 좌측처럼 표시된 칸에 종목코드와 기준일자 정도를 넣으면 그림 1의 우측처럼 결과를 볼 수 있다. 그림 1의 우측 상단에는 어떤 API 함수를 호출해야 하는지 안내가 되어 있다.

    그림1: 주식 종가 입수 KOAStudio

    SetInputValue 함수를 통해서( SetInputValue("종목코드" ,  "005930"), SetInputValue("기준일자" ,  "20231129"), SetInputValue("수정주가구분" ,  "")  ) 종목코드, 기준일자, 수정주가구분 설정을 해주고, CommRqData( "RQName" ,  "opt10081" ,  "0" ,  "화면번호")를 통해서 SetInputValue 한 데이터에 대해서 정보를 요청하는 구조이다.

    종가입수 함수 구조

    KOAStudio 화면을 잘 보면 아래 그림 2의 왼쪽 처럼 주식일봉차트조회요청을 한 화면은 TR 목록에 위치하고 TR번호는 "opt10081"인 것을 알 수 있다. 그리고 키움API개발 가이드에서는 Tr 데이터에서 대해서 OnReceiveTrData라는 이벤트 메서드를 아래 그림 2의 오른쪽처럼 설명해 두고 있다.

    그림2: onReceiveTrData

    Tr 데이터에 대해서 OnReceiveTrData 메서드를 정의하고 있기 때문에 단순히 CommRqData 를 요청만 해서는 Tr 데이터를 볼 수는 없다. Tr 데이터는 아래 그림 3처럼 데이터를 요청하고 받아서 그것을 다시 처리해서 보는 구조인 것이다.

    그림3: Tr 데이터 처리 구조

    위 그림 3을 간단히 설명하면 OnReceiveTrData의 Connect 메서드를 통해서 먼저 데이터 수신 상태를 활성화해 놓고, SetInputValue 함수를 통해서 요청 변수를 먼저 세팅한 뒤 CommRqData를 통해서 데이터를 요청하는 구조이다. Connect 메서드를 통해서 데이터를 수신하는 상태라서 데이터를 받아올 수 있지만 받아온 데이터를 처리하는 함수가 있어야 하는데 그것이 GetCommData라는 함수이다. 결론적으로 OnReceiveTrData의 Connect 메서드 안에 콜백 함수로 GetCommData로 구성된 함수를 넣어놓아야 CommRqData를 통해서 데이터를 요청했을 때 데이터 처리가 된다.

    개별종목 종가조회

    종목에 대한 개별항목 조회

    위의 그림 3의 구조에 따라 Tr목록에 있는 데이터를  처리하는 함수들을 아래와 같이 만들 수 있다.

    import sys
    import pandas as pd
    from PyQt5.QtWidgets import *
    from PyQt5.QAxContainer import *
    from PyQt5 import uic
    
    #UI파일 연결
    form_class = uic.loadUiType("C:/Users/admin/Documents/kiwoom_test/mainform.ui")[0]
    
    class KiwoomAPIform(QMainWindow, form_class):
        def __init__(self):
            super().__init__()
            self.setupUi(self)
            self.setWindowTitle("KiwoomTest")
            
    ...(중략)...
        
        def btn_loginFunc(self):
            self.CommConnect()
            def login_callback(err_code):
                result = self.ConnectEvent(err_code)
                self.drawresult(result)
            self.ocx.OnEventConnect.connect(login_callback)
    
        def btn_datagetFunc(self):
            data = self.GetCodeListByMarket("0")
            stockcodes = data.split(";")
            stockcodes = stockcodes[:-1] if stockcodes[-1] == "" else stockcodes
            # 콜백함수 불러오기
            callback = lambda: self.getstockpriceinfo("opt10081", "주식일봉차트", "종목코드")
            # 정보 입수 상태 켜기
            self.ocx.OnReceiveTrData.connect(callback)
            # 정보요청, stockcodes 목록 중 첫번째 항목만 선택(stockcodes[0], 20231129 데이터 선택
            self.rqstockpriceinfo("주식일봉차트", "opt10081", "주식일봉차트", stockcodes[0], "20231129")
    
    ...(중략)...
        # API 요청하는 SetInputValue 와 CommRqData 를 rqstockpriceinfo 하나로 묶어 냄
        def rqstockpriceinfo(self, rqname: str, trcode: str, trname: str, stockcode: str, date: str):
            self.SetInputValue("종목코드", stockcode)
            self.SetInputValue("기준일자", date)
            self.SetInputValue("수정주가구분", "")
            self.CommRqData(rqname, trcode, trname)
        
        # GetCommData 데이터를 불러서 Tr 정보 처리하는 콜백함수 구성
        def getstockpriceinfo(self, trcode: str, trname: str, item: str):
            result = self.GetCommData(trcode, trname, item)
            print(result)
        
        # 키움 API 객채(ocx)에서 API를 직접 갖다 쓰는 함수들
    
    ...(중략)...    
    
        def GetCodeListByMarket(self, mkcode: str):
            return self.ocx.dynamicCall("GetCodeListByMarket(Qstring)", mkcode)
    
        def SetInputValue(self, valuename: str, value: str):
            self.ocx.dynamicCall("SetInputValue(QString, QString)", valuename, value)
            
        def CommRqData(self, rqname: str, trcode: str, trname: str):
            self.ocx.dynamicCall("CommRqData(QString, QString, int, QString)", rqname, trcode, 0, trname)
            
        def GetCommData(self, trcode: str, trname: str, item: str):
            return self.ocx.dynamicCall("GetCommData(QString, QString, int, QString)", trcode, trname, 0, item)    
        
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        window = KiwoomAPIform()
        window.show()
        sys.exit(app.exec_())

     

    전체항목 조회

    [키움API]python 코스피 종목별 종가정보 불러오기1: 종목코드 목록 입수에서 짠 코드에 위의 코드를 잘 붙였다면 기간별 종가 데이터 입수를 눌렀을 때 아래 그림 4와 같이 종목코드 하나가 나올 것이다.

    그림4: 종목코드 조회

    위 그림 4에서 종목코드만 나오는 이유는 getstockpriceinfo 함수를 콜백 할 때, GetCommData를 불러올 때 item 항목에 "종목코드"를 넣어줬기 때문이다. 아래 그림 5의 KOAStudio 화면을 잘 보면 item항목으로 던져줄 수 있는 항목이 "종목코드", "일자", "현재가", "거래량", "시가", "고가", "저가" 정도인 것을 알 수 있다. 즉 item 항목에 "종목코드", "일자", "현재가" 등을 넣으면 그에 해당하는 값들을 각각 얻을 수 있는 것이다.

    그림5: opt10081 의 item 항목 목록

    결과적으로 item 항목에 종목코드", "일자", "현재가" 등을 순서대로 넣어주는 함수로 getstockpriceinfo 함수를 아래와 같이 바꿀 수 있다.

        def getstockpriceinfo(self, trcode: str, trname: str):
            # item 항목 빈 리스트 정의
            items = []
            # GetCommData 에 item 으로 넣을 항목들 columns라는 변수에 list 로 정의
            columns = ["종목코드", "일자", "현재가", "거래량", "시가", "고가", "저가"]
            # for 문을 통해서 columns list를 하나씩 column 에 넣어서 GetCommData 결과 받아오기
            for column in columns:
                item = self.GetCommData(trcode, trname, column)
                items.append(item.strip())
            # # item 리스트를 [] 로 한 번 더 감싸서 DataFrame으로 만들 수 있도록 변경
            items = [items]
            data = pd.DataFrame(columns=columns, data=items)
    		print(data)

     

    함수를 위와 같이 변경하면 아래 그림 6과 같은 데이터프레임을 얻을 수 있다. 

    그림6: 개별종목 종가조회

    개별종목 종가정보 입수를 위한 코드를 전부 정리하면 아래와 같다.

    import sys
    import pandas as pd
    from PyQt5.QtWidgets import *
    from PyQt5.QAxContainer import *
    from PyQt5 import uic
    
    #UI파일 연결
    form_class = uic.loadUiType("C:/Users/admin/Documents/kiwoom_test/mainform.ui")[0]
    
    class KiwoomAPIform(QMainWindow, form_class):
        def __init__(self):
            super().__init__()
            self.setupUi(self)
            self.setWindowTitle("KiwoomTest")
            
    ...(중략)...
        
        def btn_loginFunc(self):
            self.CommConnect()
            def login_callback(err_code):
                result = self.ConnectEvent(err_code)
                self.drawresult(result)
            self.ocx.OnEventConnect.connect(login_callback)
    
        def btn_datagetFunc(self):
            data = self.GetCodeListByMarket("0")
            stockcodes = data.split(";")
            stockcodes = stockcodes[:-1] if stockcodes[-1] == "" else stockcodes
            # 콜백함수 불러오기, "종목코드"를 더 이상 변수로 입력할 필요 없음
            callback = lambda: self.getstockpriceinfo("opt10081", "주식일봉차트")
            # 정보 입수 상태 켜기
            self.ocx.OnReceiveTrData.connect(callback)
            # 정보요청, stockcodes 목록 중 첫번째 항목만 선택(stockcodes[0], 20231129 데이터 선택
            self.rqstockpriceinfo("주식일봉차트", "opt10081", "주식일봉차트", stockcodes[0], "20231129")
    
    ...(중략)...
        # API 요청하는 SetInputValue 와 CommRqData 를 rqstockpriceinfo 하나로 묶어 냄
        def rqstockpriceinfo(self, rqname: str, trcode: str, trname: str, stockcode: str, date: str):
            self.SetInputValue("종목코드", stockcode)
            self.SetInputValue("기준일자", date)
            self.SetInputValue("수정주가구분", "")
            self.CommRqData(rqname, trcode, trname)
        
        # GetCommData 데이터를 불러서 Tr 정보 처리하는 콜백함수 구성
        def getstockpriceinfo(self, trcode: str, trname: str):
            # item 항목 빈 리스트 정의
            items = []
            # GetCommData 에 item 으로 넣을 항목들 columns라는 변수에 list 로 정의
            columns = ["종목코드", "일자", "현재가", "거래량", "시가", "고가", "저가"]
            # for 문을 통해서 columns list를 하나씩 column 에 넣어서 GetCommData 결과 받아오기
            for column in columns:
                item = self.GetCommData(trcode, trname, column)
                items.append(item.strip())
            # # item 리스트를 [] 로 한 번 더 감싸서 DataFrame으로 만들 수 있도록 변경
            items = [items]
            data = pd.DataFrame(columns=columns, data=items)
            print(data)
        
        # 키움 API 객채(ocx)에서 API를 직접 갖다 쓰는 함수들
        
    ...(중략)...
    
        def GetCodeListByMarket(self, mkcode: str):
            return self.ocx.dynamicCall("GetCodeListByMarket(Qstring)", mkcode)
    
        def SetInputValue(self, valuename: str, value: str):
            self.ocx.dynamicCall("SetInputValue(QString, QString)", valuename, value)
            
        def CommRqData(self, rqname: str, trcode: str, trname: str):
            self.ocx.dynamicCall("CommRqData(QString, QString, int, QString)", rqname, trcode, 0, trname)
            
        def GetCommData(self, trcode: str, trname: str, item: str):
            return self.ocx.dynamicCall("GetCommData(QString, QString, int, QString)", trcode, trname, 0, item)    
        
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        window = KiwoomAPIform()
        window.show()
        sys.exit(app.exec_())
    반응형
Designed by Tistory.