Simple Python Wrapper for Kiwoom Open API+
-
키움증권에서 제공하는 Open API+ 인터페이스 사용을 위한 간단한 Python Wrapper 모듈
-
PyQt5를 이용해 직접 개발하고자 하는 사람을 위한 모듈로 부가적인 기능은 최대한 배제
- 함수명과 변수명을 깔끔하게 Python 방식으로 통일
# Before OnReceiveTrCondition(BSTR sScrNo, BSTR strCodeList, BSTR strConditionName, int nIndex, int nNext) # After on_receive_tr_condition(scr_no, code_list, condition_name, index, next)
- 반복되는 dynamicCall 제거
# Before self.dynamicCall("CommRqData(QString, QString, Int, QString)", rq_name, tr_code, prev_next, scr_no) # After self.comm_rq_data(rq_name, tr_code, prev_next, scr_no)
- 로그인 기능
from kiwoom import * api = Kiwoom() api.login()
- loop / unloop 함수를 통해 간단히 코드 실행 / 대기 제어
from kiwoom import * # QEventLoop 활용 api = Kiwoom() api.loop() api.unloop()
- 요청 후 처리 결과를 반환하는 함수에 한해 에러 발생 시 메세지 자동 발생
# 구현되어있는 메인 클래스 class Kiwoom(API): ... # 만일 send_order() 실행 후 정상처리 되지 않았다면 @catch_error 에서 에러 메세지 자동 발생 # ex) An error occured from send_order, "-308 : OP_ERR_ORD_OVERFLOW (주문전송과부하)" @catch_error def send_order(self, rq_name, scr_no, acc_no, ord_type, code, qty, price, hoga_gb, org_order_no): return super().send_order(rq_name, scr_no, acc_no, ord_type, code, qty, price, hoga_gb, org_order_no) ...
from kiwoom import * # 지정번호 확인 print(config.MARKETS) # {'0': 'KOSPI', '3': 'ELW', ... } print(config.SECTORS) # {'001': '종합(KOSPI)', '002': '대형주', ... } # 다운로드 api = Kiwoom() api.histories(market='0', period='tick', start='20201001', merge=True) # KOSPI Stocks api.histories(sector='2', period='tick', start='20201001', merge=True) # KOSPI200 Index
- 순수한 API 기능만을 사용해 직접 개발하고 싶은 경우
from kiwoom import API # API 파이썬 래핑 class Kiwoom(API): # Overriding Here def __init__(self): super().__init__()
-
데이터를 요청하는 함수와 데이터를 받는 함수를 분리해서 작성
-
Signal에 해당하는 'Bot' 클래스와 Slot에 해당하는 'Server' 클래스
-
작성 후 Kiwoom.connect() 함수로 서로 연결시켜 서버에서 응답 시 자동 호출 지원
from kiwoom import Bot # 서버에 데이터를 요청하는 클래스 (사용자 작성) class MyBot(Bot): def __init__(self, server): super().__init__(server) # 1) Kiwoom.set_connect_hook(event, param) # 이벤트 OnReceiveTrData 발생 시 주어진 rq_name 인자값에 따라 slot을 호출하도록 설정 # 만일 설정하지 않는다면, 하나의 이벤트에는 하나의 slot만 연결가능 self.api.set_connect_hook('on_receive_tr_data', 'rq_name') # 2) Kiwoom.connect(event, signal, slot, key=None) # OnReceiveTrData 이벤트에 대하여 1)에 의해 특정 rq_name 값에 따라 signal과 slot을 연결 # key 값이 주어지지 않을 시, rq_name은 signal과 slot의 함수 이름 'balance'로 자동 설정 self.api.connect( event='on_receive_tr_data', signal=self.balance, slot=self.server.balance, ) # 1)과 2) 연결 설정 후에는 다음과 같이 활용할 수 있다. # on_receive_tr_data(..., rq_name='balance', ...) 이벤트 수신 시 server.balance 자동 호출됨 # self.api.signal('on_receive_tr_event', 'balance') 호출 시 bot.balance 함수 핸들 반환 # self.api.slot('on_receive_tr_event', 'balance') 호출 시 server.balance 함수 핸들 반환 # 참고 가이드 # 1) print(config.events) # 이벤트 목록 # 2) print(Kiwoom.api_arg_spec('on_receive_tr_data')) # 함수인자 목록 # 3) help(Kiwoom.connect) and help(Kiwoom.set_connect_hook) # Doc String # 4) Github 튜토리얼 (https://github.com/breadum/kiwoom/tree/main/tutorials) def balance(self, prev_next='0'): ... # '계좌평가잔고내역'을 받기 위해 서버로 rq_name='balance'로 요청 전송 self.api.comm_rq_data(rq_name='balance', tr_code='opw00018', prev_next='0', scr_no='0000') self.api.loop() # 이벤트가 호출 될 때까지 대기 ... def run(self): # 버전처리 및 로그인 self.login() # 계좌평가잔고내역 요청 self.balance() # 전송된 데이터 확인 print(self.share['balance']['예탁금'])from kiwoom import Server # 서버에서 데이터를 받아 처리하는 클래스 (사용자 작성) class MyServer(Server): def __init__(self): super().__init__() self.downloading = False def balance(self, scr_no, rq_name, tr_code, record_name, prev_next): ... # 만일 데이터가 더 있을 경우 연결했던 Signal 함수 다시 호출 if prev_next == '2': fn = self.api.signal('on_receive_tr_data', rq_name) # rq_name='balance' fn(prev_next) # Bot.balance(prev_next='2') # 데이터를 다 받았다면 unloop을 통해 대기중인 코드 실행 else: ... self.downloading = False self.api.unloop()# 구현되어있는 메인 클래스 class Kiwoom(API): ... # rq_name = 'balance'라면, @map 데코레이터가 매핑된 함수를 자동 호출 # >> slot.balance(scr_no, rq_name, tr_code, record_name, prev_next, *args) @map def on_receive_tr_data(self, scr_no, rq_name, tr_code, record_name, prev_next, *args): pass
- 간단한 실행 스크립트 예시 (여러가지 방식 가능)
from PyQt5.QtWidgets import QApplication from kiwoom import * import sys if __name__ == '__main__': # 통신을 위해 QApplication 활용 app = QApplication(sys.argv) # 인스턴스 생성 bot = MyBot(MyServer()) # 봇 작동시작 bot.run() # 데이터 통신을 위해 스크립트 종료 방지 app.exec()
- PyQt5 모듈을 사용하는 경우 Pycharm과 같은 IDE 사용 시 에러 메세지가 발생하지 않는 문제 해결
-
키움 Open API+ 활용 시 필수조건
-
Anaconda 64-bit 에서 32-bit 가상환경 생성 시 유의사항
네이버 블로그 참고 페이지 (https://m.blog.naver.com/haanoon/221814660104)
# 실제로 잘 작동하지 않는 방식 set CONDA_FORCE_32BIT=1 # 권장하는 방식 conda create -n your_awesome_bot # 가상환경 생성 conda activate your_awesome_bot # 가상환경 실행 conda config --env --set subdir win-32 # 현위치에서 32bit 설정 conda install python=3.7 # Python 3.7 설치
- 아래 코드로 '32Bit'인지 반드시 확인 후 설치
import platform; print(platform.architecture())
-
키움에서 Open API+ 모듈을 받아도 처음 실행 시 여러가지 오류 발생
키움 OpenAPI 등록, 타인계좌 사용불가, AhnLab Safe Transaction 설치 등등
-
먼저 KOA Studio를 통해 오류 확인 및 해결 후 파이썬 모듈 설치
-
키움 OpenAPI 등록, 모의투자 신청, 버전처리, 계좌비밀번호 저장(AUTO) 등을 확인
pip install kiwoom
# After git clone and cd into the dir git clone https://github.com/breadum/kiwoom.git && cd kiwoom python3 setup.py install
-
본 프로젝트의 개발자는 키움증권과 아무런 관련이 없습니다.
-
엉망인 키움 Open API를 활용하여 시스템을 직접 개발할 때 도움이 되고자 개발했습니다.
-
발생한 어떠한 손실에 대하여 어떻게 발생하였든지 개발자는 이에 대해 아무런 책임이 없음을 알립니다.
-
버그, 기능요청, 문의사항 등은 Github 이슈 게시판 및 E-mail을 통해 남겨주세요.