Dreams Come True Studio

파이썬 - 키움증권 API 계좌평가잔고내역 요청 / 실수, 정수, 문자열 필터링 본문

카테고리 없음

파이썬 - 키움증권 API 계좌평가잔고내역 요청 / 실수, 정수, 문자열 필터링

Dream Come True 2022. 4. 1. 23:01
반응형

이번 시간에는 계좌평가잔고내역 TR 요청을 해보도록 하겠습니다.

계좌에 관련한 모든 요청은 제 임의대로 화면번호 1000으로 지정했습니다.

화면번호에 대한 개념은 전에 정리한 포스팅이 있습니다.

https://blog.naver.com/senshig/222593016879

저는 kiwoomCore 클래스(공통) 가 있고 그 공통 클래스를 사용하는

화면 단위로 클래스를 쪼개서 작성하고 있습니다.

한 파일에 전부 다 넣어서 코드를 작성할 수도 있지만..

이건 사람마다 취향이 있고 각자 코딩 스타일인 것 같습니다.

def _tr_1000_event_loop_start(self): self.kiwoom.OnReceiveTrData.connect(self.__tr_1000_slot) self.tr_1000_event_loop = QEventLoop() self.tr_1000_event_loop.exec_()

화면번호 1000 Tr 요청에 대한 응답처리에 대한 슬롯을 연결하고 이벤트 루프를 시작하게 만드는 메소드입니다.

def get_deposit(self): self.kiwoom.setInputMultiValue(self.account_req) self.kiwoom.commRqData("예수금상세현황요청", "opw00001", 0, self.screenNo) self._tr_1000_event_loop_start() return self.mydeposit def get_account_detail(self, sPrevNext="0"): self.kiwoom.setInputMultiValue(self.account_req) self.kiwoom.commRqData("계좌평가잔고내역요청", "opw00018", sPrevNext, self.screenNo) if sPrevNext == '0': self._tr_1000_event_loop_start() return self.myaccount

실질적으로 외부에서 호출할 메소드들이고 키움증권에 TR 데이터 요청을 보내며 tr_1000 이벤트 루프를 시작합니다.

def __tr_1000_slot(self, sSrNo, sRQName, sTrcode, sRecordName, sPrevNext): self.logger.debug("키움TR : Screen : {} / {}({})".format(sSrNo, sRQName, sTrcode)) try: if sRQName == '예수금상세현황요청': self._opw00001(sSrNo, sRQName, sTrcode, sRecordName, sPrevNext) if sRQName == '계좌평가잔고내역요청': self._opw00018(sSrNo, sRQName, sTrcode, sRecordName, sPrevNext) except Exception as e: self.logger.error(e) finally: # TR 이벤트 슬롯 연결을 끊는다. self.kiwoom.OnReceiveTrData.disconnect(self.__tr_1000_slot) # TR 화면번호 1000 이벤트 루프 종료 self.tr_1000_event_loop.exit()

키움API 수신 응답을 RQName 으로 요청을 구분해 메소드들을 호출합니다.

응답이 끝나면 1000 이벤트 루프를 종료시킵니다.

지금 구조가 이런식으로 되어있습니다.

키움 API의 계좌평가잔고내역요청 ( opw00018) 을 보면

싱글데이터와 멀티데이터를 구분해서 던져줍니다. 조금 난이도가 있는 TR 요청이네요.

def _opw00018(self, sSrNo, sRQName, sTrcode, sRecordName, sPrevNext): '''계좌평가잔고내역요청''' getCommData = self.kiwoom.getCommData(sTrcode, sRQName) # 익명함수 반환 if sPrevNext != '2': total = { "총매입금액": int(getCommData(0, "총매입금액")), "총수익률(%)": float(getCommData(0, "총수익률(%)")), } self.myaccount["total"] = total self.myaccount["count"] = 0 # 보유종목수 # 상세요청목록 call_list = ['종목번호', '종목명', '현재가', '매입가', '보유수량', '평가손익', '평가금액', '수익률(%)','매입금액', '매매가능수량'] rows = self.kiwoom.getRepeatCnt(sTrcode, sRQName) # 한페이지당 가져올 수 있는 갯수가 정해져있다 self.myaccount["count"] = self.myaccount["count"] + rows self.myaccount["detail"] = {} for i in range(rows): self.myaccount['detail'].update({i + 1: {}}) for item in call_list: # 상세요청목록 리스트에 담긴대로 순서대로 돌면서 가져온다 self.myaccount['detail'][i + 1].update( { item: cv_float_int_str(getCommData(i, item).strip()) }) # index 1부터 시작 / float, int ,str 구분 if sPrevNext == '2': self.get_account_detail(sPrevNext='2') #다음 페이지 호출

실질적인 계좌평가잔고내역요청의 데이터 가져오는 코드가 이렇게 되어있고

테스트를 해보기 위해 총 27개 종목을 매수 했습니다.

call_list 에 원하는 요청목록의 순서와 목록을 바꿔주기만 하면 되도록 만들었습니다.

if __name__ == '__main__': app = QApplication(sys.argv) kiwoom = KiwoomScreen1000() print("[계좌평가잔고]") print(json.dumps(kiwoom.get_account_detail(), ensure_ascii=False, indent=3)) app.exec_()

이대로 돌려봤습니다.

그런데... 체크해보니 계좌평가잔고내역 요청 멀티데이터 27개는 한페이지 안에서 다 도네요.

더 많은 종목을 매수해봐야 다음페이지 호출까지 정확하게 테스트를 해볼 수 있을것 같습니다.

여기서 언급을 안한것이 있는데,

데이터 가져올때 실수, 정수, 문자열 체크가 필요합니다.

키움증권 API의 TR요청 데이터는 어떤 자료형이라도

실제로는 전부 문자열로 다 받아 온다는 것입니다.

그래서 1522 라는 정수형 데이터를 받아온다고 치면

00000001522 대략 이런식의 문자열로 가져오게 됩니다.

그래서 이렇게 float형과 int형과 string형을 체크해서

담아와야 예쁘게 가져올 수 있다는 번거로움이 있습니다.

이렇게 요청 리스트가 몇개 안될때는 그냥 수동으로 몇개 변환해주면 되지만

만약에 저런 목록이 수천개가 된다 ?

그런 극단적인 상황을 가정했을때는 절대로 노가다를 할 수가 없겠죠.

그래서 저는 언제나 그런 극단적인 상황을 가정해

목록만 넣어주면 알아서 변환해오는 걸 지향합니다.

어떻게 보면 집착에 가까울 때가 있기도 한데,,

제 코딩스타일이 그냥 그렇네요.

그래서 앞으로 자주 사용하게 될것 같은 함수를 만들어서

최대한 반복작업을 줄이기 위한 형변환 함수를 만들었습니다.

def cv_float_int_str(data): try: data = float(data) i = int(data) if data == i: data = i except Exception as e: pass return data

문자형 데이터가 들어갔을때 float 으로 변환에 성공하면 float으로 변환하고

그 값이 int형으로 변환한 값이랑 동일하면 int형이라고 볼 수 있겠죠?

이런 과정이 실패한다면 그대로 돌려주는 코드입니다

그래서 위와 같이 되는 것입니다.

이 코드는 자바개발을 할때 제가 사용했던 코드중 하나인데

파이썬 버전으로 만들어 봤고 아마 더 좋은 방법도 있을것 같습니다.

def _opw00018(self, sSrNo, sRQName, sTrcode, sRecordName, sPrevNext): '''계좌평가잔고내역요청''' getCommData = self.kiwoom.getCommData(sTrcode, sRQName) # 익명함수 반환 if sPrevNext != '2': # 싱글데이터 요청리스트 scall_list = ["총매입금액", "총평가금액", "총평가손익금액", "추정예탁자산", "총수익률(%)", "조회건수"] self.myaccount["total"] = {} # 싱글데이터 담을 곳 # 요청목록을 가지고 total 에 형변환해서 담는다. for item in scall_list: self.myaccount['total'].update({ item: cv_float_int_str(getCommData(0 , item).strip()) }) # 멀티데이터 요청리스트 mcall_list = ['종목명', '현재가', '매입가', '보유수량', '금일매수수량', '금일매도수량', '매매가능수량', '평가손익', '평가금액', '평가수수료', '세금', '수익률(%)', '매입금액', '보유비중(%)'] rows = self.kiwoom.getRepeatCnt(sTrcode, sRQName) # 한페이지당 최대 갯수가 정해져있다 self.myaccount["detail"] = {} # 멀티데이터 담을 곳 for i in range(rows): # 종목번호는 문자열 맨 앞글자를 제외한 단축코드로 담고 code 딕셔너리 추가 code = getCommData(i, '종목번호').strip()[1:] self.myaccount['detail'].update({code: {}}) # 나머지 요청목록은 call_list에서 돌면서 형변환을 하고 각 code 딕셔너리 안에 담음 for item in mcall_list: self.myaccount['detail'][code].update({ item: cv_float_int_str(getCommData(i, item).strip()) }) if sPrevNext == '2': self.get_account_detail(sPrevNext='2') #다음 페이지 요청

조회건수로 그냥 보유종목수를 가져올 수 있길래 count를 제거하고 요청 목록들을 좀더 추가했습니다.

그리고 종목번호는 이TR 같은 경우 키움API가 앞에 영문자를 붙여서 제공해주길래

앞글자를 제거하고 숫자로 된 문자열로 인덱스 대신에 종목코드로 묶어서 담아오도록 해봤습니다.

 
반응형
Comments