키움 OPEN API 계좌평가 잔고내역 가져오기

 

 

이전 글 보기

 

01_시작

02_기본설정

03_pykiwoom vs. 직접코딩

04_키움 open api 로그인 하기

05_키움 OPEN API에 TR 요청하기(feat. 예수금과 계좌잔고 받아오기)

06_키움 KOA 설치하기

07_키움 KOA 이해하기

08_키움 KOA 이해하기_2

 

 

 

지난 05번 글에서, 키움 OPEN API에서 TR(transaction) 요청으로 예수금과 계좌잔고를 받아왔다.

 

오늘 계좌평가 잔고내역을 가지고 오고자 한다.

 

계좌평가 잔고내역은 다음 영웅문에서와 같이 내 계좌에 가지고 있는 종목들의 현황과 계좌잔고, 수익률 등의 정보를 담고 있는 화면이다. 영웅문에서는 화면번호 0391번이다.

 

 

키움 계좌평가 잔고내역

 

 

나의 모의 투가 계좌에는 총 22개 종목이 있다. 모의투자 금액으로 22개 종목을 담았는데 벌써 수익률이 5.34%로 48만원을 벌고 있다. 왜 모의투자만 버냐고....

 

 

 

계좌평가 잔고내역 조회를 하기 전에 몇가지 개념을 잡아야 한다. 계좌평가 잔고내역에서는 상당히 많은 정보가 있다.

 

1. 내 계좌 전체 평가액, 수익률, 추정자산, 매입, 손익

2. 내 계좌에 담겨있는 종목명

3. 내 계좌에 담겨있는 종목별 평가손익, 수익률, 매입가, 보유수량, 가능수량, 현재가

4. 화면 우측 상단에 있는 "다음" 버튼

 

 

1~3번은 직관적이라 설명은 생략하고, 4번에 대한 설명이 필요하다.

영웅문에서 계좌평가 잔고내역을 조회하면 종목 20개만 우선 조회된다. 보유 종목이 20개가 넘는다면, 창 우측 상단의 "다음" 버튼을 눌러 20개를 초과하는 종목 정보를 불러올 수 있다.

 

위 그림에서 봐도 "하이트진로 ~ SK이노베이션"이 20개이다. 총 수익률이 6.48%를 보이고 있다. 이 수익률은 나의 보유 종목 22개 중 우선 조회된 20개 종목에 대한 수익률이다.

 

이 상태에서 화면 우측 상단의 "다음" 버튼을 눌러주면 그 뒤에 숨어있던 "카카오게임, 빅히트" 종목이 드러난다. 그리곤 수익률이 5.34%로 감소한다. 이는 22개 종목에 대한 수익률이다.

 

이러한 방식이 키움 OPEN API에서도 동일하게 작동한다. "다음" 버튼을 눌러줄 필요가 있다는 것이다.

 

 

 

이제 키움 KOA에서 내용을 확인해 보자

 

키움 KOA - opw00018

 

키움 KOA에서 계좌평가잔고내역요청의 TR번호는 opw00018이다. 넘겨줘야하는 파라메터들에 대한 정보가 나타나 있다.

 

 

 

이번에는 키움 KOA에서 "GetRepeatCnt"에 대해 알아보자.

 

키움 KOA - GetRepeatCnt

 

GetRepeatCnt() 함수는 조회수신한 멀티데이터의 갯수(반복)수를 얻을수 있다. 예를들어 차트조회는 한번에 최대 900개 데이터를 수신할 수 있는데 이렇게 수신한 데이터갯수를 얻을때 사용한다. 이 함수는 반드시 OnReceiveTRData()이벤트가 호출될때 그 안에서 사용해야 한다.

 

지금은 계좌평가 잔고내역을 조회하고 있으며, 한번에 조회가능한 최대 데이터는 20개이다.

 

 

 

이제 코드를 알아보자.

코드 작성을 위한 전반적인 도움은 지난 글에서 설명한 유튜브 "프로그램 동산" 채널을 도움을 받았다.

 

 

class Kiwoom(QAxWidget):
    def __init__(self):
        super().__init__()

        self.account_num = "81547491111"
        self.account_pw = "********"
        self.account_stock_dict = {}
        self.detail_account_mystock()


    def detail_account_mystock(self, sPrevNext="0"):
        # 계좌평가 잔고내역 요청
        # sPrevNext="0" : 종목 페이지(목록) 넘기지 않기
        print("계좌평가 잔고내역 요청하기 연속조회 %s" % sPrevNext)
        self.dynamicCall("SetInputValue(QString, QString)", "계좌번호", self.account_num)
        self.dynamicCall("SetInputValue(QString, QString)", "비밀번호", self.account_pw)
        self.dynamicCall("SetInputValue(QString, QString)", "비밀번호입력매체구분", "00")
        self.dynamicCall("SetInputValue(QString, QString)", "조회구분", "2")
        self.dynamicCall("CommRqData(QString, QString, int, QString)", "계좌평가잔고내역요청", "opw00018", sPrevNext, self.screen_my_info)

        self.detail_account_info_event_loop.exec_()


	def trdata_slot(self, sScrNo, sRQName, sTrCode, sRecordName, sPrevNext):
        if sRQName == "계좌평가잔고내역요청":
            total_buy_money = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "총매입금액")
            print("총매입금액 %s" % int(total_buy_money))

            total_profit_loss_rate = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "총수익률(%)")
            print("총수익률(%s) : %s" % ("%", float(total_profit_loss_rate)))

            # 계좌평가잔고 개별 종목 Count 조회, 멀티데이터 가져오기
            rows = self.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName)
            cnt = 0
            for i in range(rows):
                code = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목번호")
                code_nm = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목명")
                stock_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "보유수량")
                buy_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "매입가")
                learn_rate = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "수익률(%)")
                current_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "현재가")
                total_chegual_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "매입금액")
                possible_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "매매가능수량")

                if code in self.account_stock_dict:
                    pass
                else:
                    self.account_stock_dict.update({code:{}})

                #code = code.strip()[1:] # 공백지우고 종목코드 앞 알파벳 제외한 값 만들기(A:장내주식, J:ELW종목, Q:ETN종목)
                code_nm = code_nm.strip() # 공백지우기
                stock_quantity = int(stock_quantity.strip())
                buy_price = int(buy_price.strip())
                learn_rate = float(learn_rate.strip())
                current_price = int(current_price.strip())
                total_chegual_price = int(total_chegual_price.strip())
                possible_quantity = int(possible_quantity.strip())

                # account_stock_dict에 담기
                self.account_stock_dict[code].update({"종목명": code_nm})
                self.account_stock_dict[code].update({"보유수량": stock_quantity})
                self.account_stock_dict[code].update({"매입가": buy_price})
                self.account_stock_dict[code].update({"수익률(%)": learn_rate})
                self.account_stock_dict[code].update({"현재가": current_price})
                self.account_stock_dict[code].update({"매입금액": total_chegual_price})
                self.account_stock_dict[code].update({"매매가능수량": possible_quantity})

                cnt += 1

            print("계좌에 있는 종목 %s" % cnt)
            print("계좌에 있는 종목 %s" % self.account_stock_dict)

            # 종목이 20개 초과라 다음 페이지 클릭이 필요한 경우
            # 종목이 20개 초과인 경우, sPrevNext가 2로 반환됨
            if sPrevNext == "2" :
                self.detail_account_mystock(sPrevNext="2")
            else:
                self.detail_account_info_event_loop.exit()

 

"def detail_account_mystock(self, sPrevNext="0"):"에서 목록이 몇개인지 모르므로, sPrevNext는 우선 0으로 지정한다. 0은 "다음" 버튼을 누르지 않는 것을 의미한다.

 

SetInputValue함수로 넘길 파라메터(아이디, 비번 등)를 넘겨준다. 그것들을 모아 CommRqData 함수로 데이터를 넘긴다.

 

 

"def trdata_slot(self, sScrNo, sRQName, sTrCode, sRecordName, sPrevNext):" TR보내는 슬롯을 만들어 작업한다.

 

"total_buy_money"와 "total_profit_loss_rate"는 내 계좌의 총정보를 의미한다. 가장 위의 영웅문 그림에서 "총수익률, 총손익" 등을 의미한다.

 

 

"rows = self.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName)"로 행 수를 rows 변수에 담아 둔다. 그 아래 for문에서 종목 하나씩 관련 정보를 요청한다. code가 account_stock_dict에 있으면 넘어가고, 없으면 딕셔너리를 업데이트(자료 추가하기)를 실행한다. 

 

"self.account_stock_dict.update({code:{}})"는 다음으로 대체하여 사용할 수 있다.

"self.account_stock_dict[code] = {}"

 

수신한 데이트 전처리를 해주고, 만들어 놓은 account_stock_dict에 자료를 업데이트 한다.

 

"cnt+= 1" cnt 변수를 1 증가시켜 준다.

 

 

종목이 20개를 초과하여 sPrevNextrk "2"로 반환되는 경우, "sPrevNext="2" 로 넘겨 "다음버튼"을 누를 수 있도록 해준다.

 

 

 

 

파이썬을 학습하며 남기는 블로그입니다.
질문, 지적, 조언은 항상 환영합니다.

 

 

2021.01.13. 코리.

 

 

+ Recent posts