파이썬을 모르는 내가 파이썬을 활용하여 키움 자동 매매 시스템을 구현하는 과정을 정리하고자 한다. 1인칭 시점으로 이해한걸 정리하는 것으로 혹시나 잘못 이해하고 정리된 부분이 있을 수 있다.
KOA에서 설명하는 GetLoginInfo 함수는 다음과 같다.
[LONG GetLoginInfo()]
로그인 후 사용할 수 있으며 인자값에 대응하는 정보를 얻을 수 있습니다.
인자는 다음값을 사용할 수 있습니다.
"ACCOUNT_CNT" : 보유계좌 갯수를 반환합니다.
"ACCLIST" 또는 "ACCNO" : 구분자 ';'로 연결된 보유계좌 목록을 반환합니다.
"USER_ID" : 사용자 ID를 반환합니다.
"USER_NAME" : 사용자 이름을 반환합니다.
"GetServerGubun" : 접속서버 구분을 반환합니다.(1 : 모의투자, 나머지 : 실거래서버)
"KEY_BSECGB" : 키보드 보안 해지여부를 반환합니다.(0 : 정상, 1 : 해지)
"FIREW_SECGB" : 방화벽 설정여부를 반환합니다.(0 : 미설정, 1 : 설정, 2 : 해지)
리턴값 인자값에 대응하는 정보를 얻을 수 있습니다.
-------------------------------------------------------------
[보유계좌 목록 예시]
CString strAcctList = GetLoginInfo("ACCLIST"); 여기서 strAcctList는 ';'로 분리한 보유계좌 목록임
예) "3040525910;5678905510;3040526010"
-------------------------------------------------------------
앞의 단계까지 잘 작성되었다면 이 부분은 쉽게 진행할 수 있다.
- 함수 생성 - Login 정보를 반환하는 함수 (get_login_info) 생성 - 얻고자 하는 정보 유형을 받는 파라미터 필요
- 함수 호출 - Login 정보를 반환하는 함수 호출
1. 함수 생성 - Login 정보를 반환하는 함수 생성
파라미터 값 및 결과 값 출력을 위해 print 구문을 2번 넣었다.
def get_login_info(self, info_type):
print("info_type: ", info_type)
return_value = self.dynamicCall("GetLoginInfo(QString)", info_type)
if info_type == "ACCLIST" or info_type == "ACCNO":
return_value = return_value.split(';')
print(return_value)
return return_value
kiwoom.py 전체 코드
from PyQt5.QAxContainer import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Kiwoom(QAxWidget): # PyQt5 패키지의 QAxContainer 모듈에 있는 QAxWidget 클래스를 상속받아 Kiwoom 클래스 객체를 정의한다.
def __init__(self): # Kiwoom 클래스의 생성자 : Kiwoom 클래스 객체가 생성될 때 호출되어 내부 정의된 구문 실행
super().__init__() # 상속받은 QAxWidget 객체 초기화
self.create_kiwoom_instance() # 키움 인스턴스 생성
self.comm_login() # 키움 연결 설정 / 로그인 실행
def create_kiwoom_instance(self):
self.setControl("KHOPENAPI.KHOpenAPICtrl.1") # Kiwoom Open API+를 설치하면서 registry에 등록된 값으로 Kiwoom 인스턴스 생성
def comm_login(self):
self.OnEventConnect.connect(self.login_slot) # OnEventConnect 이벤트와 slot 을 메모리에 적재
self.dynamicCall("CommConnect()") # signal 함수 호출 (login)
self.login_event_loop = QEventLoop() # login event loop 정의
self.login_event_loop.exec_() # login event loop 실행
def login_slot(self, err_code): # OnEventConnect 함수의 return 값을 err_code로 받음
if err_code == 0:
print("login success")
else:
print("login failed")
self.login_event_loop.exit() # loging event loop 종료
def get_login_info(self, info_type):
return_value = self.dynamicCall("GetLoginInfo(QString)", info_type)
if info_type == "ACCLIST" or info_type == "ACCNO":
return_value = return_value.split(';')
print(info_type, ": ", return_value)
return return_value
2. 함수 호출 - Login 정보를 반환하는 함수 호출
main에 각 타입으로 호출하는 구문을 추가한다.
main.py 전체 코드
from api.kiwoom import *
import sys
# app 객체 생성
app = QApplication(sys.argv)
# import 한 Kiwoom class object 생성 (인스턴스화)
kiwoom = Kiwoom()
# kiwoom 객체의 get_login_info 함수 호출
kiwoom.get_login_info("ACCOUNT_CNT")
kiwoom.get_login_info("ACCLIST")
kiwoom.get_login_info("ACCNO")
kiwoom.get_login_info("USER_ID")
kiwoom.get_login_info("USER_NAME")
kiwoom.get_login_info("GetServerGubun")
kiwoom.get_login_info("KEY_BSECGB")
kiwoom.get_login_info("FIREW_SECGB")
# app 객체의 exec_() 함수 실행
app.exec_()
출력 결과를 보면 뭔가 이상한 부분을 확인할 수 있다.
총 계좌 수는 2개로 나오는데 계좌 번호는 배열로 반환하면서 3개를 반환했다. 물론 배열의 마지막은 빈 값 ('') 으로 되어 있어 계좌로 인식할 수 없을 것 같지만 뭔가 이상한 점은 있다. 이건 split 하면서 의미없는 마지막 값이 붙은 것이라고 한다. 이걸 빼는 방법은 배열을 활용할 때 [:-1]을 뒤에 붙여주면 된다.
다음 예시에서 ACCNO 를 출력한 결과에는 마지막에 빈 값이 없는것을 확인할 수 있다.
kiwoom.py 전체 코드 (수정)
from PyQt5.QAxContainer import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Kiwoom(QAxWidget): # PyQt5 패키지의 QAxContainer 모듈에 있는 QAxWidget 클래스를 상속받아 Kiwoom 클래스 객체를 정의한다.
def __init__(self): # Kiwoom 클래스의 생성자 : Kiwoom 클래스 객체가 생성될 때 호출되어 내부 정의된 구문 실행
super().__init__() # 상속받은 QAxWidget 객체 초기화
self.create_kiwoom_instance() # 키움 인스턴스 생성
self.comm_login() # 키움 연결 설정 / 로그인 실행
def create_kiwoom_instance(self):
self.setControl("KHOPENAPI.KHOpenAPICtrl.1") # Kiwoom Open API+를 설치하면서 registry에 등록된 값으로 Kiwoom 인스턴스 생성
def comm_login(self):
self.OnEventConnect.connect(self.login_slot) # OnEventConnect 이벤트와 slot 을 메모리에 적재
self.dynamicCall("CommConnect()") # signal 함수 호출 (login)
self.login_event_loop = QEventLoop() # login event loop 정의
self.login_event_loop.exec_() # login event loop 실행
def login_slot(self, err_code): # OnEventConnect 함수의 return 값을 err_code로 받음
if err_code == 0:
print("login success")
else:
print("login failed")
self.login_event_loop.exit() # loging event loop 종료
def get_login_info(self, info_type):
return_value = self.dynamicCall("GetLoginInfo(QString)", info_type)
if info_type == "ACCLIST":
return_value = return_value.split(';')
elif info_type == "ACCNO":
return_value = return_value.split(';')[:-1]
print(info_type, ": ", return_value)
return return_value
계좌 번호, 내 계정, 이름 등등 출력이 되니 뭔가 진행된 느낌이다.
로그인 버전처리 관련 함수
함수 명 | 내용 |
LONG CommConnect() | OnReceiveMsg( BSTR sScrNo, // 화면번호 BSTR sRQName, // 사용자 구분명 BSTR sTrCode, // TR이름 BSTR sMsg // 서버에서 전달하는 메시지 ) 데이터 요청 또는 주문전송 후에 서버가 보낸 메시지를 수신합니다. 예) "조회가 완료되었습니다" 예) "계좌번호 입력을 확인해주세요" 예) "조회할 자료가 없습니다." 예) "증거금 부족으로 주문이 거부되었습니다." ※ 주의할 점 : 메시지에 포함된 6자리 코드번호는 변경될 수 있으니, 여기에 수신된 코드번호를 특정 용도로 사용하지 마시기 바랍니다. |
void CommTerminate() | 프로그램 종료없이 서버와의 접속만 단절시키는 함수입니다. ※ 함수 사용 후 사용자의 오해소지가 생기는 이유로 더 이상 사용할 수 없는 함수입니다. |
LONG GetConnectState() | 서버와 현재 접속 상태를 알려줍니다. 리턴값 1:연결, 0:연결안됨 |
BSTR GetLoginInfo(BSTR sTag) | 로그인 후 사용할 수 있으며 인자값에 대응하는 정보를 얻을 수 있습니다. 인자는 다음값을 사용할 수 있습니다. "ACCOUNT_CNT" : 보유계좌 갯수를 반환합니다. "ACCLIST" 또는 "ACCNO" : 구분자 ';'로 연결된 보유계좌 목록을 반환합니다. "USER_ID" : 사용자 ID를 반환합니다. "USER_NAME" : 사용자 이름을 반환합니다. "GetServerGubun" : 접속서버 구분을 반환합니다.(1 : 모의투자, 나머지 : 실거래서버) "KEY_BSECGB" : 키보드 보안 해지여부를 반환합니다.(0 : 정상, 1 : 해지) "FIREW_SECGB" : 방화벽 설정여부를 반환합니다.(0 : 미설정, 1 : 설정, 2 : 해지) 리턴값 인자값에 대응하는 정보를 얻을 수 있습니다. ------------------------------------------------------------------- [보유계좌 목록 예시] CString strAcctList = GetLoginInfo("ACCLIST"); 여기서 strAcctList는 ';'로 분리한 보유계좌 목록임 예) "3040525910;5678905510;3040526010" ------------------------------------------------------------------- |
void OnEventConnect(long nErrCode) | OnEventConnect( long nErrCode // 로그인 상태를 전달하는데 자세한 내용은 아래 상세내용 참고 ) 로그인 처리 이벤트입니다. 성공이면 인자값 nErrCode가 0이며 에러는 다음과 같은 값이 전달됩니다. nErrCode별 상세내용 -100 사용자 정보교환 실패 -101 서버접속 실패 -102 버전처리 실패 |
void OnReceiveMsg(BSTR sScrNo, BSTR sRQName, BSTR sTrCode, BSTR sMsg) | OnReceiveMsg( BSTR sScrNo, // 화면번호 BSTR sRQName, // 사용자 구분명 BSTR sTrCode, // TR이름 BSTR sMsg // 서버에서 전달하는 메시지 ) 데이터 요청 또는 주문전송 후에 서버가 보낸 메시지를 수신합니다. 예) "조회가 완료되었습니다" 예) "계좌번호 입력을 확인해주세요" 예) "조회할 자료가 없습니다." 예) "증거금 부족으로 주문이 거부되었습니다." ※ 주의할 점 : 메시지에 포함된 6자리 코드번호는 변경될 수 있으니, 여기에 수신된 코드번호를 특정 용도로 사용하지 마시기 바랍니다. |
2022.03.21 - [정보] - [파이썬] 주식 자동 매매 시스템 구현 #3 - 시스템트레이딩 프로젝트 생성 및 키움증권 로그인
2022.03.16 - [정보] - [파이썬] 주식 자동 매매 시스템 구현 #2 - 키움 증권 API 활용 환경 구성
2022.03.16 - [정보] - [파이썬] 주식 자동 매매 시스템 구현 #1 - 관련 프로그램 설치 (개발 환경 구성)
'정보' 카테고리의 다른 글
[파이썬] 주식 자동 매매 시스템 구현 #5 - 종목 정보 가져오기 (0) | 2022.03.22 |
---|---|
맥북 특정 포트 사용 여부 확인 및 Kill (0) | 2022.03.21 |
[파이썬] 주식 자동 매매 시스템 구현 #3 - 시스템트레이딩 프로젝트 생성 및 키움증권 로그인 (2) | 2022.03.21 |
[파이썬] 주식 자동 매매 시스템 구현 #2 - 키움 증권 API 활용 환경 구성 (0) | 2022.03.16 |
[파이썬] 주식 자동 매매 시스템 구현 #1 - 관련 프로그램 설치 (개발 환경 구성) (0) | 2022.03.16 |