친절한곳

구성한 UI 파일 실행하기 


지난 챕터에서 만들어둔 UI를 가지고 간단한 키움 API를 사용해보도록 하겠습니다.
먼저 PyCharm을 실행 합니다.
그리고 아래와 같이 stock 프로젝트에서 우클릭 후 New > Directory 항목을 클릭 합니다.



디렉토리 이름은 아래와 같이 apiTest 로 하도록 하겠습니다.




그리고 아래와 같이 기존에 만들어둔 apiTest.ui 파일을 좌클릭 후 드래그하여 

방금 만들어둔 apiTest 디렉토리에 옮깁니다.

그리고 오픈되는 확인창에서 OK 버튼을 클릭 합니다.

그럼 아래와 같이 apiTest 디렉토리에 apiTest.ui 파일이 들어가게 됩니다.




그리고 apiTest 디렉토리 우클릭하여 New > Python File 을 클릭합니다.

이후 노출되는 창에서 Name을 apiTest로 입력하여 OK 버튼을 클릭합니다.




그럼 아래와 같이 소스 코드를 작성할 apiTest.py 파일 까지 만들어졌습니다.




그럼 이제 해당 apiTest.py 파일과 apiTest.ui 파일을 연결하여 실행해보도록 하겠습니다.

아래의 소스코드를 apiTest.py 파일에 복사 또는 작성 합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic
 
form_class = uic.loadUiType("apiTest.ui")[0]    # ui 파일을 로드하여 form_class 생성
 
class MyWindow(QMainWindow, form_class):    # MyWindow 클래스 QMainWindow, form_class 클래스를 상속 받아 생성됨
    def __init__(self): # MyWindow 클래스의 초기화 함수(생성자)
        super().__init__()  # 부모클래스 QMainWindow 클래스의 초기화 함수(생성자)를 호출
        self.setupUi(self)  # ui 파일 화면 출력
 
# py 파일 실행시 제일 먼저 동작
if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWindow = MyWindow()  # MyWindow 클래스를 생성하여 myWondow 변수에 할당
    myWindow.show()  # MyWindow 클래스를 노출
    app.exec_()  # 메인 이벤트 루프에 진입 후 프로그램이 종료될 때까지 무한 루프 상태 대기



그리고 Ctrl+Shift+F10을 이용하여 실행 또는

아래와 같이 apiTest.py 파일을 우클릭 후 Run 'apiTest' 버튼을 클릭합니다.




그럼 아래와 같이 만들었던 화면구성으로 된 윈도우 창이 노출되는 것을 확인할 수 있습니다.




키움 로그인 연결 하기 


그럼 다음으로 키움 API를 사용해보기 위해 키움에 로그인하는 부분을 추가하도록 하겠습니다.

다음 소스 코드로 기존 apiTest.py 파일 전체를 변경하거나,

변경된 부분만 추가 하도록 하겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic
from PyQt5.QAxContainer import *
 
form_class = uic.loadUiType("apiTest.ui")[0]    # ui 파일을 로드하여 form_class 생성
 
class MyWindow(QMainWindow, form_class):    # MyWindow 클래스 QMainWindow, form_class 클래스를 상속 받아 생성됨
    def __init__(self): # MyWindow 클래스의 초기화 함수(생성자)
        super().__init__()  # 부모클래스 QMainWindow 클래스의 초기화 함수(생성자)를 호출
        self.setupUi(self)  # ui 파일 화면 출력
 
        self.kiwoom = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")  # 키움증권 Open API+의 ProgID를 사용하여 생성된 QAxWidget을 kiwoom 변수에 할당
 
        self.lineEditCode.setDisabled(True) # 종목코드 입력란을 비활성화 상태로 변경
        self.btnSearch.setDisabled(True)    # 조회 버튼을 비활성화 상태로 변경
        self.pteLog.setDisabled(True)       # plainTextEdit를 비활성화 상태로 변경
 
        self.btnLogin.clicked.connect(self.btn_login)   # ui 파일을 생성할때 작성한 로그인 버튼의 objectName 으로 클릭 이벤트가 발생할 경우 btn_login 함수를 호출
        self.kiwoom.OnEventConnect.connect(self.event_connect)  # 키움 서버 접속 관련 이벤트가 발생할 경우 event_connect 함수 호출
 
    def btn_login(self): # Login 버튼 클릭 시 실행되는 함수
        ret = self.kiwoom.dynamicCall("CommConnect()")  # 키움 로그인 윈도우를 실행
 
    def event_connect(self, err_code):  # 키움 서버 접속 관련 이벤트가 발생할 경우 실행되는 함수
        if err_code == 0:   # err_code가 0이면 로그인 성공 그외 실패
            self.lineEditCode.setDisabled(False)    # 종목코드 입력란을 활성화 상태로 변경
            self.btnSearch.setDisabled(False)   # 조회 버튼을 활성화 상태로 변경
            self.pteLog.setDisabled(False)  # plainTextEdit를 활성화 상태로 변경
            self.pteLog.appendPlainText("로그인 성공")    # ui 파일을 생성할때 작성한 plainTextEdit의 objectName 으로 해당 plainTextEdit에 텍스트를 추가함
        else:
            self.lineEditCode.setDisabled(True)  # 종목코드 입력란을 비활성화 상태로 변경
            self.btnSearch.setDisabled(True)  # 조회 버튼을 비활성화 상태로 변경
            self.pteLog.setDisabled(True)  # plainTextEdit를 비활성화 상태로 변경
            self.pteLog.appendPlainText("로그인 실패")    # ui 파일을 생성할때 작성한 plainTextEdit의 objectName 으로 해당 plainTextEdit에 텍스트를 추가함
 
# py 파일 실행시 제일 먼저 동작
if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWindow = MyWindow()  # MyWindow 클래스를 생성하여 myWondow 변수에 할당
    myWindow.show()  # MyWindow 클래스를 노출
    app.exec_()  # 메인 이벤트 루프에 진입 후 프로그램이 종료될 때까지 무한 루프 상태 대기



해당 소스코드를 적용 후 Ctrl + Shift + F10 버튼을 클릭하거나

apiTest.py 파일을 우클릭 후 Run 'apiTest' 버튼을 클릭하여 실행할 경우

아래와 같이 종목코드 입력란, 조회 버튼, plainTextEdit 영역이 비활성화 상태로 노출됩니다.




이후 로그인 버튼을 클릭하면 키움 로그인 창이 노출되고,

키움 로그인 창에서 로그인 하면

아래와 같이 종목코드 입력란, 조회 버튼, plainTextEdit 영역이 활성화 상태로 노출되고,

"로그인 성공" 메시지가 노출되게 됩니다.




계좌 정보 가져오기 


다음으로 주식 거래를 하기 위해 꼭 필요한 계좌 정보를 가져오도록 해보겠습니다.

다음 소스 코드로 기존 apiTest.py 파일 전체를 변경하거나,

변경된 부분만 추가 하도록 하겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic
from PyQt5.QAxContainer import *
 
form_class = uic.loadUiType("apiTest.ui")[0]    # ui 파일을 로드하여 form_class 생성
 
class MyWindow(QMainWindow, form_class):    # MyWindow 클래스 QMainWindow, form_class 클래스를 상속 받아 생성됨
    def __init__(self): # MyWindow 클래스의 초기화 함수(생성자)
        super().__init__()  # 부모클래스 QMainWindow 클래스의 초기화 함수(생성자)를 호출
        self.setupUi(self)  # ui 파일 화면 출력
 
        self.kiwoom = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")  # 키움증권 Open API+의 ProgID를 사용하여 생성된 QAxWidget을 kiwoom 변수에 할당
 
        self.lineEditCode.setDisabled(True) # 종목코드 입력란을 비활성화 상태로 변경
        self.btnSearch.setDisabled(True)    # 조회 버튼을 비활성화 상태로 변경
        self.pteLog.setDisabled(True)       # plainTextEdit를 비활성화 상태로 변경
 
        self.btnLogin.clicked.connect(self.btn_login)   # ui 파일을 생성할때 작성한 로그인 버튼의 objectName 으로 클릭 이벤트가 발생할 경우 btn_login 함수를 호출
        self.kiwoom.OnEventConnect.connect(self.event_connect)  # 키움 서버 접속 관련 이벤트가 발생할 경우 event_connect 함수 호출
 
    def btn_login(self): # Login 버튼 클릭 시 실행되는 함수
        ret = self.kiwoom.dynamicCall("CommConnect()")  # 키움 로그인 윈도우를 실행
 
    def event_connect(self, err_code):  # 키움 서버 접속 관련 이벤트가 발생할 경우 실행되는 함수
        if err_code == 0:   # err_code가 0이면 로그인 성공 그외 실패
            self.lineEditCode.setDisabled(False)    # 종목코드 입력란을 활성화 상태로 변경
            self.btnSearch.setDisabled(False)   # 조회 버튼을 활성화 상태로 변경
            self.pteLog.setDisabled(False)  # plainTextEdit를 활성화 상태로 변경
            self.pteLog.appendPlainText("로그인 성공")    # ui 파일을 생성할때 작성한 plainTextEdit의 objectName 으로 해당 plainTextEdit에 텍스트를 추가함
 
            account_num = self.kiwoom.dynamicCall("GetLoginInfo(QString)", ["ACCNO"])   # 키움 dynamicCall 함수를 통해 GetLoginInfo 함수를 호출하여 계좌번호를 가져옴
            self.pteLog.appendPlainText("계좌번호: " + account_num.rstrip(';')) # 키움은 전체 계좌를 반환하며 각 계좌 번호 끝에 세미콜론(;)이 붙어 있음으로 제거하여 plainTextEdit에 텍스트를 추가함
        else:
            self.lineEditCode.setDisabled(True)  # 종목코드 입력란을 비활성화 상태로 변경
            self.btnSearch.setDisabled(True)  # 조회 버튼을 비활성화 상태로 변경
            self.pteLog.setDisabled(True)  # plainTextEdit를 비활성화 상태로 변경
            self.pteLog.appendPlainText("로그인 실패")    # ui 파일을 생성할때 작성한 plainTextEdit의 objectName 으로 해당 plainTextEdit에 텍스트를 추가함
 
# py 파일 실행시 제일 먼저 동작
if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWindow = MyWindow()  # MyWindow 클래스를 생성하여 myWondow 변수에 할당
    myWindow.show()  # MyWindow 클래스를 노출
    app.exec_()  # 메인 이벤트 루프에 진입 후 프로그램이 종료될 때까지 무한 루프 상태 대기



소스 코드 중 추가된 부분은 로그인 성공 이후 아래와 같이 계좌번호를 가져와서 출력해주는 부분이 추가되었습니다.


1
2
account_num = self.kiwoom.dynamicCall("GetLoginInfo(QString)", ["ACCNO"])   # 키움 dynamicCall 함수를 통해 GetLoginInfo 함수를 호출하여 계좌번호를 가져옴
self.pteLog.appendPlainText("계좌번호: " + account_num.rstrip(';')) # 키움은 전체 계좌를 반환하며 각 계좌 번호 끝에 세미콜론(;)이 붙어 있음으로 제거하여 plainTextEdit에 텍스트를 추가함



수정된 소스 코드를  Ctrl + Shift + F10 을 눌러 실행하거나

apiTest.py 파일을 우클릭 후 Run 'apiTest' 버튼을 클릭하여 실행후 로그인에 성공할 경우

아래와 같이 계좌 정보가 노출되는 것을 확인할 수 있습니다.




종목코드로 기본정보 요청하기 


이제 종목코드로 주식의 기본 정보를 가져오는 방법을 확인하겠습니다.

이전에 설치한 KOA Studio를 실행 후 로그인 하도록 합니다.

그리고 왼쪽 하단에 TR 목록 탭을 클릭 하고 TR 목록 중 opt10001 : 주식기본정보요청 항목을 클릭 합니다.

이후 오른쪽 상단에 종목코드 부분에 조회하고 싶은 종목코드를 입력 후 조회 버튼을 클릭 합니다.

그럼 중앙 하단 출력란에 해당 종목의 정보가 노출되는 것을 확인할 수 있습니다.


Tip. 아래의 화면처럼 왼쪽 TR 목록을 보면 INPUT, OUTPUT 항목 좌측에 + 버튼을 클릭하면

아래 값들이 노출됩니다.

INPUT은 넣어줘야 하는 값이며, OUTPUT은 제공받는 값입니다.

(해당 조회는 장시간에만 가능합니다. 장시간 외에 조회 요청 시 반환값이 없을 수도 있습니다.)




KOA Studio 에서 주식기본정보요청에 INPUT, OUTPUT 값을 확인해 보았습니다.

그럼 저는 종목코드를 입력하여 종목명, 거래량을 출력해보도록 하겠습니다.

다음 소스 코드로 기존 apiTest.py 파일 전체를 변경하거나,

변경된 부분만 추가 하도록 하겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic
from PyQt5.QAxContainer import *
 
form_class = uic.loadUiType("apiTest.ui")[0]    # ui 파일을 로드하여 form_class 생성
 
class MyWindow(QMainWindow, form_class):    # MyWindow 클래스 QMainWindow, form_class 클래스를 상속 받아 생성됨
    def __init__(self): # MyWindow 클래스의 초기화 함수(생성자)
        super().__init__()  # 부모클래스 QMainWindow 클래스의 초기화 함수(생성자)를 호출
        self.setupUi(self)  # ui 파일 화면 출력
 
        self.kiwoom = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")  # 키움증권 Open API+의 ProgID를 사용하여 생성된 QAxWidget을 kiwoom 변수에 할당
 
        self.lineEditCode.setDisabled(True) # 종목코드 입력란을 비활성화 상태로 변경
        self.btnSearch.setDisabled(True)    # 조회 버튼을 비활성화 상태로 변경
        self.pteLog.setDisabled(True)       # plainTextEdit를 비활성화 상태로 변경
 
        self.btnLogin.clicked.connect(self.btn_login)   # ui 파일을 생성할때 작성한 로그인 버튼의 objectName 으로 클릭 이벤트가 발생할 경우 btn_login 함수를 호출
        self.kiwoom.OnEventConnect.connect(self.event_connect)  # 키움 서버 접속 관련 이벤트가 발생할 경우 event_connect 함수 호출
 
        self.btnSearch.clicked.connect(self.btn_search)  # ui 파일을 생성할때 작성한 조회 버튼의 objectName 으로 클릭 이벤트가 발생할 경우 btn_search 함수를 호출
        self.kiwoom.OnReceiveTrData.connect(self.receive_trdata)    # 키움 데이터 수신 관련 이벤트가 발생할 경우 receive_trdata 함수 호출
 
    def btn_login(self): # Login 버튼 클릭 시 실행되는 함수
        ret = self.kiwoom.dynamicCall("CommConnect()")  # 키움 로그인 윈도우를 실행
 
    def event_connect(self, err_code):  # 키움 서버 접속 관련 이벤트가 발생할 경우 실행되는 함수
        if err_code == 0:   # err_code가 0이면 로그인 성공 그외 실패
            self.lineEditCode.setDisabled(False)    # 종목코드 입력란을 활성화 상태로 변경
            self.btnSearch.setDisabled(False)   # 조회 버튼을 활성화 상태로 변경
            self.pteLog.setDisabled(False)  # plainTextEdit를 활성화 상태로 변경
            self.pteLog.appendPlainText("로그인 성공")    # ui 파일을 생성할때 작성한 plainTextEdit의 objectName 으로 해당 plainTextEdit에 텍스트를 추가함
 
            account_num = self.kiwoom.dynamicCall("GetLoginInfo(QString)", ["ACCNO"])   # 키움 dynamicCall 함수를 통해 GetLoginInfo 함수를 호출하여 계좌번호를 가져옴
            self.pteLog.appendPlainText("계좌번호: " + account_num.rstrip(';')) # 키움은 전체 계좌를 반환하며 각 계좌 번호 끝에 세미콜론(;)이 붙어 있음으로 제거하여 plainTextEdit에 텍스트를 추가함
        else:
            self.lineEditCode.setDisabled(True)  # 종목코드 입력란을 비활성화 상태로 변경
            self.btnSearch.setDisabled(True)  # 조회 버튼을 비활성화 상태로 변경
            self.pteLog.setDisabled(True)  # plainTextEdit를 비활성화 상태로 변경
            self.pteLog.appendPlainText("로그인 실패")    # ui 파일을 생성할때 작성한 plainTextEdit의 objectName 으로 해당 plainTextEdit에 텍스트를 추가함
 
    def btn_search(self):   # 조회 버튼 클릭 시 실행되는 함수
        code = self.lineEditCode.text() # ui 파일을 생성할때 작성한 종목코드 입력란의 objectName 으로 사용자가 입력한 종목코드의 텍스트를 가져옴
        self.pteLog.appendPlainText("종목코드: " + code)    # ui 파일을 생성할때 작성한 plainTextEdit의 objectName 으로 해당 plainTextEdit에 텍스트를 추가함
        self.kiwoom.dynamicCall("SetInputValue(QString, QString)""종목코드", code)    # 키움 dynamicCall 함수를 통해 SetInputValue 함수를 호출하여 종목코드를 셋팅함
        self.kiwoom.dynamicCall("CommRqData(QString, QString, int, QString)""opt10001_req""opt10001"0"0101")    # 키움 dynamicCall 함수를 통해 CommRqData 함수를 호출하여 opt10001 API를 구분명 opt10001_req, 화면번호 0101으로 호출함
 
    def receive_trdata(self, screen_no, rqname, trcode, recordname, prev_next, data_len, err_code, msg1, msg2): # 키움 데이터 수신 함수
        if rqname == "opt10001_req":    # 수신된 데이터 구분명이 opt10001_req 일 경우
            name = self.kiwoom.dynamicCall("CommGetData(QString, QString, QString, int, QString)", trcode, "", rqname, 0"종목명")    # 구분명 opt10001_req 의 종목명을 가져와서 name에 셋팅
            volume = self.kiwoom.dynamicCall("CommGetData(QString, QString, QString, int, QString)", trcode, "", rqname, 0"거래량")  # 구분명 opt10001_req 의 거래량을 가져와서 volume에 셋팅
 
            self.pteLog.appendPlainText("종목명: " + name.strip()) # 종목명을 공백 제거해서 plainTextEdit에 텍스트를 추가함
            self.pteLog.appendPlainText("거래량: " + volume.strip())   # 거래량을 공백 제거해서 plainTextEdit에 텍스트를 추가함
 
# py 파일 실행시 제일 먼저 동작
if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWindow = MyWindow()  # MyWindow 클래스를 생성하여 myWondow 변수에 할당
    myWindow.show()  # MyWindow 클래스를 노출
    app.exec_()  # 메인 이벤트 루프에 진입 후 프로그램이 종료될 때까지 무한 루프 상태 대기



소스 코드 중 추가된 부분은 아래와 같이 조회 버튼을 클릭하면 주식기본정보요청 API를 요청 하고

수신된 데이터를 받을 수 있도록 연결하여 데이터가 수신되면

plainTextEdit에 수신된 데이터 중 종목명, 거래량만 출력되도록 하였습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
self.btnSearch.clicked.connect(self.btn_search)  # ui 파일을 생성할때 작성한 조회 버튼의 objectName 으로 클릭 이벤트가 발생할 경우 btn_search 함수를 호출
self.kiwoom.OnReceiveTrData.connect(self.receive_trdata)    # 키움 데이터 수신 관련 이벤트가 발생할 경우 receive_trdata 함수 호출
 
def btn_search(self):   # 조회 버튼 클릭 시 실행되는 함수
    code = self.lineEditCode.text() # ui 파일을 생성할때 작성한 종목코드 입력란의 objectName 으로 사용자가 입력한 종목코드의 텍스트를 가져옴
    self.pteLog.appendPlainText("종목코드: " + code)    # ui 파일을 생성할때 작성한 plainTextEdit의 objectName 으로 해당 plainTextEdit에 텍스트를 추가함
    self.kiwoom.dynamicCall("SetInputValue(QString, QString)""종목코드", code)    # 키움 dynamicCall 함수를 통해 SetInputValue 함수를 호출하여 종목코드를 셋팅함
    self.kiwoom.dynamicCall("CommRqData(QString, QString, int, QString)""opt10001_req""opt10001"0"0101")    # 키움 dynamicCall 함수를 통해 CommRqData 함수를 호출하여 opt10001 API를 구분명 opt10001_req, 화면번호 0101으로 호출함
 
def receive_trdata(self, screen_no, rqname, trcode, recordname, prev_next, data_len, err_code, msg1, msg2): # 키움 데이터 수신 함수
    if rqname == "opt10001_req":    # 수신된 데이터 구분명이 opt10001_req 일 경우
        name = self.kiwoom.dynamicCall("CommGetData(QString, QString, QString, int, QString)", trcode, "", rqname, 0"종목명")    # 구분명 opt10001_req 의 종목명을 가져와서 name에 셋팅
        volume = self.kiwoom.dynamicCall("CommGetData(QString, QString, QString, int, QString)", trcode, "", rqname, 0"거래량")  # 구분명 opt10001_req 의 거래량을 가져와서 volume에 셋팅
 
        self.pteLog.appendPlainText("종목명: " + name.strip()) # 종목명을 공백 제거해서 plainTextEdit에 텍스트를 추가함
        self.pteLog.appendPlainText("거래량: " + volume.strip())   # 거래량을 공백 제거해서 plainTextEdit에 텍스트를 추가함



수정된 소스 코드를  Ctrl + Shift + F10 을 눌러 실행하거나

apiTest.py 파일을 우클릭 후 Run 'apiTest' 버튼을 클릭하여 실행후 로그인 이후

종목코드를 입력 후 조회 버튼을 클릭할 경우

아래의 화면 처럼 해당 종목의 종목명과 거래량이 출력되는 것을 확인할 수 있습니다.




이상으로 키움 API 사용법에 대해 알아보았습니다.

다음 챕터에서부터는 주식 자동 거래 테스트로 상한가 종목 거래 방식 일명 상따 거래에 대한

주식 자동 프로그램을 만들도록 하겠습니다.





주식 자동매매, 주식 어플, 주식 정보 웹 스크래이핑, 공시 정보 연동 등

주식에 관심이 있는 사람들에게 도움이 될 정보를 기본부터 차근차근 정리할 예정입니다.

해당 글을 보고 지적 사항, 수정 사항이 있다면 언제든지 댓글, 또는 메일로 연락 부탁드립니다.

여러분의 관심이 글을 보는 다음 누군가에겐 큰 도움이 될 것입니다. 감사합니다.