20211204 man kiwoom_api continue

abraxas·2021년 12월 3일
0

tamagotchi

목록 보기
6/21

PyQt를 이용해 키움 Open API+를 사용하는 방법의 기초를 이어서 공부한다.

아래의 WikiDocs를 공부했다.

https://wikidocs.net/4239

키움증권 Open API+의 CommConnect() method를 이용해 로그인을 시도하면 OnEventConnect라는 이벤트가 발생한다. 따라서 OnEventConnect 이벤트를 처리하면 GetConnectState() method 없이도 로그인 성공 여부를 확인할 수 있다.

위 WikiDocs의 예제 12.5 코드이다.

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

class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PyStock")
        self.setGeometry(300, 300, 300, 150)

        self.kiwoom = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")
        self.kiwoom.dynamicCall("CommConnect()")

        self.text_edit = QTextEdit(self)
        self.text_edit.setGeometry(10, 60, 280, 80)
        self.text_edit.setEnabled(False)

        self.kiwoom.OnEventConnect.connect(self.event_connect)

    def event_connect(self, err_code):
        if err_code == 0:
            self.text_edit.append("로그인 성공")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWindow = MyWindow()
    myWindow.show()
    app.exec_()

아랫부분의 코드만 새로운 부분이다.

        self.text_edit = QTextEdit(self)
        self.text_edit.setGeometry(10, 60, 280, 80)
        self.text_edit.setEnabled(False)
        
    self.kiwoom.OnEventConnect.connect(self.event_connect)

    def event_connect(self, err_code):
        if err_code == 0:
            self.text_edit.append("로그인 성공")

PyQt를 이용해서 프로그램을 만들 때 많은 widget을 생성하게 되는데, 어떤 경우에는 self를 붙이고 어떤 경우에는 self를 붙이지 않는다. self를 붙일 때는 class의 다른 method에서도 해당 instance에 접근할 수 있게 하기 위함이다. 그리고 QTextEdit(self)와 같은 경우에는 이 instance를 최상위 윈도우 안에 생성하기 위해서 self를 매개변수로 전달한다.

setGeometry() method는 이전에도 봤던 class의 크기 및 위치 조절하기 위해 쓰인다. setEnabled() method는 읽기/쓰기 모드를 변경하는 데 쓰인다.

다시 OnEventConnect로 돌아와서, 이 이벤트는 함수의 인자로 nErrCode라는 값이 입력된다. 해당 값이 0이면 로그인 성공, 음수이면 로그인 실패를 의미한다. 이 값을 connect() method를 통해 event_connect() method에 전달해준다. event_connect() method는 nErrCode를 확인하고 로그인 성공 시 "로그인 성공"이라는 메시지를 text_edit instance에 붙여준다.

키움증권 서버와 데이터를 주고받는 행위를 TR(transaction)이라고 본다. "opt10001" [주식기본정보요청]을 이용해 종목명과 거래량을 출력하는 프로그램을 작성해본다. 아래는 이 예제 12.7의 코드이다.

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

class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        # Kiwoom Login
        self.kiwoom = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")
        self.kiwoom.dynamicCall("CommConnect()")

        # OpenAPI+ Event
        self.kiwoom.OnEventConnect.connect(self.event_connect)
        self.kiwoom.OnReceiveTrData.connect(self.receive_trdata)

        self.setWindowTitle("PyStock")
        self.setGeometry(300, 300, 300, 150)

        label = QLabel("종목코드: ", self)
        label.move(20, 20)

        self.code_edit = QLineEdit(self)
        self.code_edit.move(80, 20)
        self.code_edit.setText("039490")

        btn1 = QPushButton("조회", self)
        btn1.move(190, 20)
        btn1.clicked.connect(self.btn1_clicked)

        self.text_edit = QTextEdit(self)
        self.text_edit.setGeometry(10, 60, 280, 80)
        self.text_edit.setEnabled(False)

    def event_connect(self, err_code):
        if err_code == 0:
            self.text_edit.append("로그인 성공")

    def btn1_clicked(self):
        code = self.code_edit.text()
        self.text_edit.append("종목코드: " + code)

        # SetInputValue
        self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종목코드", code)

        # CommRqData
        self.kiwoom.dynamicCall("CommRqData(QString, QString, int, QString)", "opt10001_req", "opt10001", 0, "0101")

    def receive_trdata(self, screen_no, rqname, trcode, recordname, prev_next, data_len, err_code, msg1, msg2):
        if rqname == "opt10001_req":
            name = self.kiwoom.dynamicCall("CommGetData(QString, QString, QString, int, QString)", trcode, "", rqname, 0, "종목명")
            volume = self.kiwoom.dynamicCall("CommGetData(QString, QString, QString, int, QString)", trcode, "", rqname, 0, "거래량")

            self.text_edit.append("종목명: " + name.strip())
            self.text_edit.append("거래량: " + volume.strip())

if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWindow = MyWindow()
    myWindow.show()
    app.exec_()

위 예제 코드에는 네 가지의 PyQt widget이 사용되었다. QLabel widget은 간단한 텍스트를 출력하는 데 쓰인다. QLineEdit widget은 간단한 사용자 입력을 처리하는 데 쓰인다. QPushButton은 버튼을 생성하는 데 쓰인다. QTextEdit은 메시지를 출력하는데 쓰인다.

        label = QLabel("종목코드: ", self)
        label.move(20, 20)

위 코드가 QLabel widget을 생성해서 "종목코드: "라는 텍스트를 출력한다. move() method는 (x, y) 좌표인 것 같다. QLabel widget은 텍스트 출력하는 데만 사용되고 다른 곳에 사용되지 않기 때문에, self.label가 아닌 label로 써준다.

        self.code_edit = QLineEdit(self)
        self.code_edit.move(80, 20)
        self.code_edit.setText("039490")

여기서 code_edit은 다른 method에서도 사용할 계획이기에 self.code_edit으로 바인딩해준다.

전체 코드에서 첫 번째로 중요한 부분은 btn1_clicked() method라고 생각한다. btn1.clicked 이벤트 발생 시 btn1_clicked() method로 connect 되어있다. 이 method는 다음과 같다.

    def btn1_clicked(self):
        code = self.code_edit.text()
        self.text_edit.append("종목코드: " + code)

        # SetInputValue
        self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종목코드", code)

        # CommRqData
        self.kiwoom.dynamicCall("CommRqData(QString, QString, int, QString)", "opt10001_req", "opt10001", 0, "0101")

키움 Open API+의 TR의 처리는 네 가지의 과정을 거친다. 먼저, SetInputValue() method로 TR 입력값을 설정한다. 다음에 CommRqData() method로 TR을 서버로 보낸다. 서버로부터 이벤트가 발생할 때까지 대기한다. CommGetData() method를 통해 서버로부터 수신한 데이터를 가져온다. 위 btn1_clicked() method는 처음 두 가지 과정을 포함한다. CommRqData() method의 첫 번째 인자는 사용자가 TR을 구분하기 위해 사용된다. 두 번째 인자는 요청하는 TR 코드이다. 세 번째 인자는 단순 조회 TR의 경우 0이다. 네 번째 인자는 화면 번호로 기본값인 "0101"을 사용했다.

전체 코드에서 다음으로 중요한 부분은 receive_trdata() method 부분이다.

    def receive_trdata(self, screen_no, rqname, trcode, recordname, prev_next, data_len, err_code, msg1, msg2):
        if rqname == "opt10001_req":
            name = self.kiwoom.dynamicCall("CommGetData(QString, QString, QString, int, QString)", trcode, "", rqname, 0, "종목명")
            volume = self.kiwoom.dynamicCall("CommGetData(QString, QString, QString, int, QString)", trcode, "", rqname, 0, "거래량")

이 method는 OnReceiveTrData 이벤트가 발생하면 트리거 된다. OnReceiveTrData 이벤트는 총 9개의 인자가 있다: sScrNo, sRQName, sTrCode, sRecordName, sPreNext, nDataLength, sErrorCode, sMessage, sSplmMsg. receive_trdata() method가 이 9개 인자를 self 이후에 받게 된다. 이후 CommGetData() method를 이용해 데이터를 가져온다. CommGetData() method는 Tran 데이터, 실시간 데이터, 체결잔고 데이터를 반환한다.

CommGetData() method를 이용해서 종목명과 거래량을 가져오기 위해서는 4개의 인자 중 첫 번째와 세 번째 인자는 TR 코드와 사용자가 TR을 구분하기 위해 지정한 이름이다. 두 번째 인자는 비어있는 문자열이고, 네 번째 인자는 0, 마지막으로 다섯 번째는 종목명을 가져올 때는 "종목명" 거래량을 가져올 때는 "거래량"이다.

코드를 짤 때 좀 더 꼼꼼해야 하겠다.

오늘은 여기까지.

다음에도 계속해서 PyQt를 이용해 키움 Open API+를 사용하는 방법의 기초를 공부할 것이다.

0개의 댓글