금융/증권사API

QeventLoop를 이용한 로그인하기 , 기본정보 요청 함수

씩씩한 IT블로그 2021. 2. 16. 17:05
반응형

 문제파악

주식 기본정보를 가져오기 위해선 로그인이 선행되어야 한다. 

하지만 로그인하는데 잠깐의 시간이 걸리고, 그 시간보다 빨리 코드가 실행되면 오류가 발생한다.

sosoeasy.tistory.com/413에서는 로그인을 확인하는 이벤트 함수에 주식 기본정보를 요청하는 함수를 넣어서 이 문제를 해결했다. 

이번 장에서는 QeventLoop를 통해 문제를 해결한다

 

 QeventLoop란?

특정 시점에서 특정 조건이 발생해야지만 다음 코드를 진행할 수 있게 만들어 주는 함수이다.

다음과 같이 세가지 단계로 구분된다.

1. loop객체 생성

self.login_event_loop = QEventLoop()

 

2. 조건생성

self.login_event_loop.exit()

 

3. 코드진행 ( 2.에서 self.login_event_loop.exit() 가 실행되어야지만 다음 코드가 진행된다)

self.login_event_loop.exec_()

 

아래의 예시에서 각 단계별 역할을 자세히 알아본다.

 

 실제예시

아래와 같이 두 함수가 있다.

        self.login() # 로그인함수
        self.getData() # 정보받아오는 함수

여기서 우리는 로그인이 확실히 성공한 후에 새로운 데이터를 받아오는 작업( self.getData() )을 수행해야한다.

 

1. 먼저 로그인과 관련된 이벤트루프를 생성한다. (1. loop객체 생성)

self.login_event_loop = QEventLoop()

2. 로그인 완료 시 실행되는 로그인 이벤트함수 맨 마지막줄에 2.조선생성문을 아래와 같이 넣는다

    # 로그인 확인 이벤트
    def myOnEventConnect(self, nErrCode):
        if nErrCode == 0:
            print('로그인 성공')
        else:
            print('로그인 실패')
        self.login_event_loop.exit()

3. 그리고 아래와 같이 login함수에 3.코드진행을 넣는다.

    def login(self):
        # 로그인 요청함수
        print("[로그인 요청]")
        self.dynamicCall("CommConnect()")
        self.login_event_loop.exec_() #login_event_loop.exit()가 실행되어야 끝남

 

그러면 로그인 확인 이벤트 함수(myOnEventConnect)가 끝나면서 self.login_event_loop.exit()가 실행되어야지만 login()함수가 끝난다. 즉 로그인이 되기 전까진 login()함수가 끝나지 않는 것이다.

따라서 self.login()함수 다음줄에 있는 self.getData()함수를 실행할때는 로그인이 되어있음을 보장받을 수 있다.

 

 소스코드

import sys
from PyQt5.QAxContainer import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

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

        # QAxWidget 객체 (키움 api연결)
        # 키움api연동, 아래의 코드와 똑같음
        # self.kiwoom = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")
        self.setControl("KHOPENAPI.KHOpenAPICtrl.1")
        self.login_event_loop = QEventLoop()

        # 이벤트함수
        self.OnEventConnect.connect(self.myOnEventConnect)  # 로그인 이벤트
        self.OnReceiveTrData.connect(self.myOnReceiveTrData)  # 데이터요청 이벤트

        # 작업함수
        self.login()
        self.getData()

    # 로그인 확인 이벤트
    def myOnEventConnect(self, nErrCode):
        if nErrCode == 0:
            print('로그인 성공')
        else:
            print('로그인 실패')
        self.login_event_loop.exit()

    # 기본정보 받기 이벤트
    def myOnReceiveTrData(self, sScrNo, sRQName, sTrCode, sRecordName, sPreNext, nDataLength, sErrorCode, sMessage, sSplmMsg):
        print("데이터 받기 시작")
        # sScrNo(화면번호), sRQName(사용자구분), sTrCode(Tran명), sRecordName(레코드명), sPreNext(연속조회 유무) , 나머지 4개는 현재버전에서 사용x
        if sRQName == 'test_opt10001':
            name = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "종목명")
            volume = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "거래량")
            price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "현재가")
            # ( strTrCode(tran코드), strRecordName(레코드명), nIndex(복수데이터 인덱스), strItemName(아이템명) )
            # 아이템명은 koa studio에 해당 tr의 output 에서 확인가능

            print(name.lstrip(), volume.lstrip(), price.lstrip())

    # 로그인
    def login(self):
        # 로그인 요청함수
        print("[로그인 요청]")
        self.dynamicCall("CommConnect()")
        self.login_event_loop.exec_() #login_event_loop.exit()가 실행되어야 끝남

    # 데이터요청
    def getData(self):
        # 데이터 요청 함수
        print("[데이터요청]")
        self.dynamicCall("SetInputValue(QString, QString)", "종목코드", "005385")  # (아이템명, 입력값)
        self.dynamicCall("CommRqData(QString, QString, QString, QString)", "test_opt10001", "opt10001", "0", "0101")
        # ( sRQName(사용자구분), sTrCode(Tran명), nPrevNext(0:조회 2:연속), sScreenNo(화면번호) )
        # TR종류는 KOA스튜디오에서 확인가능
        # 화면목록은 KOA스튜디옹서 확인가능

if __name__ == "__main__":
    app = QApplication(sys.argv)
    test = KiwoomAPI()
    app.exec_()
반응형