"Pykioom"의 두 판 사이의 차이
DB CAFE
(→opw0004) |
|||
(같은 사용자의 중간 판 2개는 보이지 않습니다) | |||
1번째 줄: | 1번째 줄: | ||
+ | === pykiwoom api === | ||
+ | https://github.com/sharebook-kr/pykiwoom/tree/master/pykiwoom | ||
+ | |||
+ | * pykiwoom.py | ||
+ | <source lang=python> | ||
+ | import sys | ||
+ | from PyQt5.QtWidgets import * | ||
+ | from PyQt5.QAxContainer import * | ||
+ | import pythoncom | ||
+ | import datetime | ||
+ | from pykiwoom import parser | ||
+ | import pandas as pd | ||
+ | import time | ||
+ | import logging | ||
+ | |||
+ | logging.basicConfig(filename="log.txt", level=logging.ERROR) | ||
+ | |||
+ | |||
+ | class Kiwoom: | ||
+ | def __init__(self, login=False): | ||
+ | self.ocx = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1") | ||
+ | self.connected = False # for login event | ||
+ | self.received = False # for tr event | ||
+ | self.tr_items = None # tr input/output items | ||
+ | self.tr_data = None # tr output data | ||
+ | self.tr_record = None | ||
+ | self.tr_remained = False | ||
+ | self.condition_loaded = False | ||
+ | self._set_signals_slots() | ||
+ | |||
+ | if login: | ||
+ | self.CommConnect() | ||
+ | |||
+ | def _handler_login(self, err_code): | ||
+ | logging.info(f"hander login {err_code}") | ||
+ | if err_code == 0: | ||
+ | self.connected = True | ||
+ | |||
+ | def _handler_condition_load(self, ret, msg): | ||
+ | if ret == 1: | ||
+ | self.condition_loaded = True | ||
+ | |||
+ | def _handler_tr_condition(self, screen_no, code_list, cond_name, cond_index, next): | ||
+ | codes = code_list.split(';')[:-1] | ||
+ | self.tr_condition_data = codes | ||
+ | self.tr_condition_loaded= True | ||
+ | |||
+ | def _handler_tr(self, screen, rqname, trcode, record, next): | ||
+ | logging.info(f"OnReceiveTrData {screen} {rqname} {trcode} {record} {next}") | ||
+ | try: | ||
+ | record = None | ||
+ | items = None | ||
+ | |||
+ | # remained data | ||
+ | if next == '2': | ||
+ | self.tr_remained = True | ||
+ | else: | ||
+ | self.tr_remained = False | ||
+ | |||
+ | for output in self.tr_items['output']: | ||
+ | record = list(output.keys())[0] | ||
+ | items = list(output.values())[0] | ||
+ | if record == self.tr_record: | ||
+ | break | ||
+ | |||
+ | rows = self.GetRepeatCnt(trcode, rqname) | ||
+ | if rows == 0: | ||
+ | rows = 1 | ||
+ | |||
+ | data_list = [] | ||
+ | for row in range(rows): | ||
+ | row_data = [] | ||
+ | for item in items: | ||
+ | data = self.GetCommData(trcode, rqname, row, item) | ||
+ | row_data.append(data) | ||
+ | data_list.append(row_data) | ||
+ | |||
+ | # data to DataFrame | ||
+ | df = pd.DataFrame(data=data_list, columns=items) | ||
+ | self.tr_data = df | ||
+ | self.received = True | ||
+ | except: | ||
+ | pass | ||
+ | |||
+ | def _handler_msg(self, screen, rqname, trcode, msg): | ||
+ | logging.info(f"OnReceiveMsg {screen} {rqname} {trcode} {msg}") | ||
+ | |||
+ | def _handler_chejan(self, gubun, item_cnt, fid_list): | ||
+ | logging.info(f"OnReceiveChejanData {gubun} {item_cnt} {fid_list}") | ||
+ | |||
+ | def _set_signals_slots(self): | ||
+ | self.ocx.OnEventConnect.connect(self._handler_login) | ||
+ | self.ocx.OnReceiveTrData.connect(self._handler_tr) | ||
+ | self.ocx.OnReceiveConditionVer.connect(self._handler_condition_load) | ||
+ | self.ocx.OnReceiveTrCondition.connect(self._handler_tr_condition) | ||
+ | self.ocx.OnReceiveMsg.connect(self._handler_msg) | ||
+ | self.ocx.OnReceiveChejanData.connect(self._handler_chejan) | ||
+ | |||
+ | #------------------------------------------------------------------------------------------------------------------- | ||
+ | # OpenAPI+ 메서드 | ||
+ | #------------------------------------------------------------------------------------------------------------------- | ||
+ | def CommConnect(self, block=True): | ||
+ | """ | ||
+ | 로그인 윈도우를 실행합니다. | ||
+ | :param block: True: 로그인완료까지 블록킹 됨, False: 블록킹 하지 않음 | ||
+ | :return: None | ||
+ | """ | ||
+ | self.ocx.dynamicCall("CommConnect()") | ||
+ | if block: | ||
+ | while not self.connected: | ||
+ | pythoncom.PumpWaitingMessages() | ||
+ | |||
+ | def CommRqData(self, rqname, trcode, next, screen): | ||
+ | """ | ||
+ | TR을 서버로 송신합니다. | ||
+ | :param rqname: 사용자가 임의로 지정할 수 있는 요청 이름 | ||
+ | :param trcode: 요청하는 TR의 코드 | ||
+ | :param next: 0: 처음 조회, 2: 연속 조회 | ||
+ | :param screen: 화면번호 ('0000' 또는 '0' 제외한 숫자값으로 200개로 한정된 값 | ||
+ | :return: None | ||
+ | """ | ||
+ | self.ocx.dynamicCall("CommRqData(QString, QString, int, QString)", rqname, trcode, next, screen) | ||
+ | |||
+ | def GetLoginInfo(self, tag): | ||
+ | """ | ||
+ | 로그인한 사용자 정보를 반환하는 메서드 | ||
+ | :param tag: ("ACCOUNT_CNT, "ACCNO", "USER_ID", "USER_NAME", "KEY_BSECGB", "FIREW_SECGB") | ||
+ | :return: tag에 대한 데이터 값 | ||
+ | """ | ||
+ | data = self.ocx.dynamicCall("GetLoginInfo(QString)", tag) | ||
+ | |||
+ | if tag == "ACCNO": | ||
+ | return data.split(';')[:-1] | ||
+ | else: | ||
+ | return data | ||
+ | |||
+ | def SendOrder(self, rqname, screen, accno, order_type, code, quantity, price, hoga, order_no): | ||
+ | """ | ||
+ | 주식 주문을 서버로 전송하는 메서드 | ||
+ | 시장가 주문시 주문단가는 0으로 입력해야 함 (가격을 입력하지 않음을 의미) | ||
+ | :param rqname: 사용자가 임의로 지정할 수 있는 요청 이름 | ||
+ | :param screen: 화면번호 ('0000' 또는 '0' 제외한 숫자값으로 200개로 한정된 값 | ||
+ | :param accno: 계좌번호 10자리 | ||
+ | :param order_type: 1: 신규매수, 2: 신규매도, 3: 매수취소, 4: 매도취소, 5: 매수정정, 6: 매도정정 | ||
+ | :param code: 종목코드 | ||
+ | :param quantity: 주문수량 | ||
+ | :param price: 주문단가 | ||
+ | :param hoga: 00: 지정가, 03: 시장가, | ||
+ | 05: 조건부지정가, 06: 최유리지정가, 07: 최우선지정가, | ||
+ | 10: 지정가IOC, 13: 시장가IOC, 16: 최유리IOC, | ||
+ | 20: 지정가FOK, 23: 시장가FOK, 26: 최유리FOK, | ||
+ | 61: 장전시간외종가, 62: 시간외단일가, 81: 장후시간외종가 | ||
+ | :param order_no: 원주문번호로 신규 주문시 공백, 정정이나 취소 주문시에는 원주문번호를 입력 | ||
+ | :return: | ||
+ | """ | ||
+ | ret = self.ocx.dynamicCall("SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)", | ||
+ | [rqname, screen, accno, order_type, code, quantity, price, hoga, order_no]) | ||
+ | return ret | ||
+ | |||
+ | def SetInputValue(self, id, value): | ||
+ | """ | ||
+ | TR 입력값을 설정하는 메서드 | ||
+ | :param id: TR INPUT의 아이템명 | ||
+ | :param value: 입력 값 | ||
+ | :return: None | ||
+ | """ | ||
+ | self.ocx.dynamicCall("SetInputValue(QString, QString)", id, value) | ||
+ | |||
+ | def DisconnectRealData(self, screen): | ||
+ | """ | ||
+ | 화면번호에 대한 리얼 데이터 요청을 해제하는 메서드 | ||
+ | :param screen: 화면번호 | ||
+ | :return: None | ||
+ | """ | ||
+ | self.ocx.dynamicCall("DisconnectRealData(QString)", screen) | ||
+ | |||
+ | def GetRepeatCnt(self, trcode, rqname): | ||
+ | """ | ||
+ | 멀티데이터의 행(row)의 개수를 얻는 메서드 | ||
+ | :param trcode: TR코드 | ||
+ | :param rqname: 사용자가 설정한 요청이름 | ||
+ | :return: 멀티데이터의 행의 개수 | ||
+ | """ | ||
+ | count = self.ocx.dynamicCall("GetRepeatCnt(QString, QString)", trcode, rqname) | ||
+ | return count | ||
+ | |||
+ | def CommKwRqData(self, arr_code, next, code_count, type, rqname, screen): | ||
+ | """ | ||
+ | 여러 종목 (한 번에 100종목)에 대한 TR을 서버로 송신하는 메서드 | ||
+ | :param arr_code: 여러 종목코드 예: '000020:000040' | ||
+ | :param next: 0: 처음조회 | ||
+ | :param code_count: 종목코드의 개수 | ||
+ | :param type: 0: 주식종목 3: 선물종목 | ||
+ | :param rqname: 사용자가 설정하는 요청이름 | ||
+ | :param screen: 화면번호 | ||
+ | :return: | ||
+ | """ | ||
+ | ret = self.ocx.dynamicCall("CommKwRqData(QString, bool, int, int, QString, QString)", arr_code, next, code_count, type, rqname, screen); | ||
+ | return ret | ||
+ | |||
+ | def GetAPIModulePath(self): | ||
+ | """ | ||
+ | OpenAPI 모듈의 경로를 반환하는 메서드 | ||
+ | :return: 모듈의 경로 | ||
+ | """ | ||
+ | ret = self.ocx.dynamicCall("GetAPIModulePath()") | ||
+ | return ret | ||
+ | |||
+ | def GetCodeListByMarket(self, market): | ||
+ | """ | ||
+ | 시장별 상장된 종목코드를 반환하는 메서드 | ||
+ | :param market: 0: 코스피, 3: ELW, 4: 뮤추얼펀드 5: 신주인수권 6: 리츠 | ||
+ | 8: ETF, 9: 하이일드펀드, 10: 코스닥, 30: K-OTC, 50: 코넥스(KONEX) | ||
+ | :return: 종목코드 리스트 예: ["000020", "000040", ...] | ||
+ | """ | ||
+ | data = self.ocx.dynamicCall("GetCodeListByMarket(QString)", market) | ||
+ | tokens = data.split(';')[:-1] | ||
+ | return tokens | ||
+ | |||
+ | def GetConnectState(self): | ||
+ | """ | ||
+ | 현재접속 상태를 반환하는 메서드 | ||
+ | :return: 0:미연결, 1: 연결완료 | ||
+ | """ | ||
+ | ret = self.ocx.dynamicCall("GetConnectState()") | ||
+ | return ret | ||
+ | |||
+ | def GetMasterCodeName(self, code): | ||
+ | """ | ||
+ | 종목코드에 대한 종목명을 얻는 메서드 | ||
+ | :param code: 종목코드 | ||
+ | :return: 종목명 | ||
+ | """ | ||
+ | data = self.ocx.dynamicCall("GetMasterCodeName(QString)", code) | ||
+ | return data | ||
+ | |||
+ | def GetMasterListedStockCnt(self, code): | ||
+ | """ | ||
+ | 종목에 대한 상장주식수를 리턴하는 메서드 | ||
+ | :param code: 종목코드 | ||
+ | :return: 상장주식수 | ||
+ | """ | ||
+ | data = self.ocx.dynamicCall("GetMasterListedStockCnt(QString)", code) | ||
+ | return data | ||
+ | |||
+ | def GetMasterConstruction(self, code): | ||
+ | """ | ||
+ | 종목코드에 대한 감리구분을 리턴 | ||
+ | :param code: 종목코드 | ||
+ | :return: 감리구분 (정상, 투자주의 투자경고, 투자위험, 투자주의환기종목) | ||
+ | """ | ||
+ | data = self.ocx.dynamicCall("GetMasterConstruction(QString)", code) | ||
+ | return data | ||
+ | |||
+ | def GetMasterListedStockDate(self, code): | ||
+ | """ | ||
+ | 종목코드에 대한 상장일을 반환 | ||
+ | :param code: 종목코드 | ||
+ | :return: 상장일 예: "20100504" | ||
+ | """ | ||
+ | data = self.ocx.dynamicCall("GetMasterListedStockDate(QString)", code) | ||
+ | return datetime.datetime.strptime(data, "%Y%m%d") | ||
+ | |||
+ | def GetMasterLastPrice(self, code): | ||
+ | """ | ||
+ | 종목코드의 전일가를 반환하는 메서드 | ||
+ | :param code: 종목코드 | ||
+ | :return: 전일가 | ||
+ | """ | ||
+ | data = self.ocx.dynamicCall("GetMasterLastPrice(QString)", code) | ||
+ | return int(data) | ||
+ | |||
+ | def GetMasterStockState(self, code): | ||
+ | """ | ||
+ | 종목의 종목상태를 반환하는 메서드 | ||
+ | :param code: 종목코드 | ||
+ | :return: 종목상태 | ||
+ | """ | ||
+ | data = self.ocx.dynamicCall("GetMasterStockState(QString)", code) | ||
+ | return data.split("|") | ||
+ | |||
+ | def GetDataCount(self, record): | ||
+ | count = self.ocx.dynamicCall("GetDataCount(QString)", record) | ||
+ | return count | ||
+ | |||
+ | def GetOutputValue(self, record, repeat_index, item_index): | ||
+ | count = self.ocx.dynamicCall("GetOutputValue(QString, int, int)", record, repeat_index, item_index) | ||
+ | return count | ||
+ | |||
+ | def GetCommData(self, trcode, rqname, index, item): | ||
+ | """ | ||
+ | 수순 데이터를 가져가는 메서드 | ||
+ | :param trcode: TR 코드 | ||
+ | :param rqname: 요청 이름 | ||
+ | :param index: 멀티데이터의 경우 row index | ||
+ | :param item: 얻어오려는 항목 이름 | ||
+ | :return: | ||
+ | """ | ||
+ | data = self.ocx.dynamicCall("GetCommData(QString, QString, int, QString)", trcode, rqname, index, item) | ||
+ | return data.strip() | ||
+ | |||
+ | def GetCommRealData(self, code, fid): | ||
+ | data = self.ocx.dynamicCall("GetCommRealData(QString, int)", code, fid) | ||
+ | return data | ||
+ | |||
+ | def GetChejanData(self, fid): | ||
+ | data = self.ocx.dynamicCall("GetChejanData(int)", fid) | ||
+ | return data | ||
+ | |||
+ | def GetThemeGroupList(self, type=1): | ||
+ | data = self.ocx.dynamicCall("GetThemeGroupList(int)", type) | ||
+ | tokens = data.split(';') | ||
+ | if type == 0: | ||
+ | grp = {x.split('|')[0]:x.split('|')[1] for x in tokens} | ||
+ | else: | ||
+ | grp = {x.split('|')[1]: x.split('|')[0] for x in tokens} | ||
+ | return grp | ||
+ | |||
+ | def GetThemeGroupCode(self, theme_code): | ||
+ | data = self.ocx.dynamicCall("GetThemeGroupCode(QString)", theme_code) | ||
+ | data = data.split(';') | ||
+ | return [x[1:] for x in data] | ||
+ | |||
+ | def GetFutureList(self): | ||
+ | data = self.ocx.dynamicCall("GetFutureList()") | ||
+ | return data | ||
+ | |||
+ | def GetCommDataEx(self, trcode, record): | ||
+ | data = self.ocx.dynamicCall("GetCommDataEx(QString, QString)", trcode, record) | ||
+ | return data | ||
+ | |||
+ | def block_request(self, *args, **kwargs): | ||
+ | trcode = args[0].lower() | ||
+ | lines = parser.read_enc(trcode) | ||
+ | self.tr_items = parser.parse_dat(trcode, lines) | ||
+ | self.tr_record = kwargs["output"] | ||
+ | next = kwargs["next"] | ||
+ | |||
+ | # set input | ||
+ | for id in kwargs: | ||
+ | if id.lower() != "output" and id.lower() != "next": | ||
+ | self.SetInputValue(id, kwargs[id]) | ||
+ | |||
+ | # initialize | ||
+ | self.received = False | ||
+ | self.tr_remained = False | ||
+ | |||
+ | # request | ||
+ | self.CommRqData(trcode, trcode, next, "0101") | ||
+ | while not self.received: | ||
+ | pythoncom.PumpWaitingMessages() | ||
+ | |||
+ | return self.tr_data | ||
+ | |||
+ | def SetRealReg(self, screen, code_list, fid_list, real_type): | ||
+ | ret = self.ocx.dynamicCall("SetRealReg(QString, QString, QString, QString)", screen, code_list, fid_list, real_type) | ||
+ | return ret | ||
+ | |||
+ | def SetRealRemove(self, screen, del_code): | ||
+ | ret = self.ocx.dynamicCall("SetRealRemove(QString, QString)", screen, del_code) | ||
+ | return ret | ||
+ | |||
+ | def GetConditionLoad(self, block=True): | ||
+ | self.condition_loaded = False | ||
+ | self.ocx.dynamicCall("GetConditionLoad()") | ||
+ | if block: | ||
+ | while not self.condition_loaded: | ||
+ | pythoncom.PumpWaitingMessages() | ||
+ | |||
+ | def GetConditionNameList(self): | ||
+ | data = self.ocx.dynamicCall("GetConditionNameList()") | ||
+ | conditions = data.split(";")[:-1] | ||
+ | |||
+ | # [('000', 'perpbr'), ('001', 'macd'), ...] | ||
+ | result = [] | ||
+ | for condition in conditions: | ||
+ | cond_index, cond_name = condition.split('^') | ||
+ | result.append((cond_index, cond_name)) | ||
+ | |||
+ | return result | ||
+ | |||
+ | def SendCondition(self, screen, cond_name, cond_index, search): | ||
+ | self.tr_condition_loaded = False | ||
+ | self.ocx.dynamicCall("SendCondition(QString, QString, int, int)", screen, cond_name, cond_index, search) | ||
+ | |||
+ | while not self.tr_condition_loaded: | ||
+ | pythoncom.PumpWaitingMessages() | ||
+ | |||
+ | return self.tr_condition_data | ||
+ | |||
+ | def SendConditionStop(self, screen, cond_name, index): | ||
+ | self.ocx.dynamicCall("SendConditionStop(QString, QString, int)", screen, cond_name, index) | ||
+ | |||
+ | def GetCommDataEx(self, trcode, rqname): | ||
+ | data = self.ocx.dynamicCall("GetCommDataEx(QString, QString)", trcode, rqname) | ||
+ | return data | ||
+ | |||
+ | def SendOrder(self, rqname, screen, accno, order_type, code, quantity, price, hoga, order_no): | ||
+ | self.ocx.dynamicCall("SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)", | ||
+ | [rqname, screen, accno, order_type, code, quantity, price, hoga, order_no]) | ||
+ | # 주문 후 0.2초 대기 | ||
+ | time.sleep(0.2) | ||
+ | |||
+ | |||
+ | if not QApplication.instance(): | ||
+ | app = QApplication(sys.argv) | ||
+ | |||
+ | |||
+ | if __name__ == "__main__": | ||
+ | # 로그인 | ||
+ | kiwoom = Kiwoom() | ||
+ | kiwoom.CommConnect(block=True) | ||
+ | |||
+ | # 조건식 load | ||
+ | kiwoom.GetConditionLoad() | ||
+ | |||
+ | conditions = kiwoom.GetConditionNameList() | ||
+ | |||
+ | # 0번 조건식에 해당하는 종목 리스트 출력 | ||
+ | condition_index = conditions[0][0] | ||
+ | condition_name = conditions[0][1] | ||
+ | codes = kiwoom.SendCondition("0101", condition_name, condition_index, 0) | ||
+ | |||
+ | print(codes) | ||
+ | </source> | ||
=== opw0004 === | === opw0004 === | ||
82번째 줄: | 507번째 줄: | ||
df.to_excel("opw00018.xlsx") | df.to_excel("opw00018.xlsx") | ||
</source> | </source> | ||
+ | |||
+ | [[category:python]] |
2020년 11월 19일 (목) 16:56 기준 최신판
thumb_up 추천메뉴 바로가기
- DBA { Oracle DBA 명령어 > DBA 초급 과정 > DBA 고급 과정 }
- 튜닝 { 오라클 튜닝 목록 }
- 모델링 { 데이터 모델링 가이드 }
1 pykiwoom api[편집]
https://github.com/sharebook-kr/pykiwoom/tree/master/pykiwoom
- pykiwoom.py
import sys
from PyQt5.QtWidgets import *
from PyQt5.QAxContainer import *
import pythoncom
import datetime
from pykiwoom import parser
import pandas as pd
import time
import logging
logging.basicConfig(filename="log.txt", level=logging.ERROR)
class Kiwoom:
def __init__(self, login=False):
self.ocx = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")
self.connected = False # for login event
self.received = False # for tr event
self.tr_items = None # tr input/output items
self.tr_data = None # tr output data
self.tr_record = None
self.tr_remained = False
self.condition_loaded = False
self._set_signals_slots()
if login:
self.CommConnect()
def _handler_login(self, err_code):
logging.info(f"hander login {err_code}")
if err_code == 0:
self.connected = True
def _handler_condition_load(self, ret, msg):
if ret == 1:
self.condition_loaded = True
def _handler_tr_condition(self, screen_no, code_list, cond_name, cond_index, next):
codes = code_list.split(';')[:-1]
self.tr_condition_data = codes
self.tr_condition_loaded= True
def _handler_tr(self, screen, rqname, trcode, record, next):
logging.info(f"OnReceiveTrData {screen} {rqname} {trcode} {record} {next}")
try:
record = None
items = None
# remained data
if next == '2':
self.tr_remained = True
else:
self.tr_remained = False
for output in self.tr_items['output']:
record = list(output.keys())[0]
items = list(output.values())[0]
if record == self.tr_record:
break
rows = self.GetRepeatCnt(trcode, rqname)
if rows == 0:
rows = 1
data_list = []
for row in range(rows):
row_data = []
for item in items:
data = self.GetCommData(trcode, rqname, row, item)
row_data.append(data)
data_list.append(row_data)
# data to DataFrame
df = pd.DataFrame(data=data_list, columns=items)
self.tr_data = df
self.received = True
except:
pass
def _handler_msg(self, screen, rqname, trcode, msg):
logging.info(f"OnReceiveMsg {screen} {rqname} {trcode} {msg}")
def _handler_chejan(self, gubun, item_cnt, fid_list):
logging.info(f"OnReceiveChejanData {gubun} {item_cnt} {fid_list}")
def _set_signals_slots(self):
self.ocx.OnEventConnect.connect(self._handler_login)
self.ocx.OnReceiveTrData.connect(self._handler_tr)
self.ocx.OnReceiveConditionVer.connect(self._handler_condition_load)
self.ocx.OnReceiveTrCondition.connect(self._handler_tr_condition)
self.ocx.OnReceiveMsg.connect(self._handler_msg)
self.ocx.OnReceiveChejanData.connect(self._handler_chejan)
#-------------------------------------------------------------------------------------------------------------------
# OpenAPI+ 메서드
#-------------------------------------------------------------------------------------------------------------------
def CommConnect(self, block=True):
"""
로그인 윈도우를 실행합니다.
:param block: True: 로그인완료까지 블록킹 됨, False: 블록킹 하지 않음
:return: None
"""
self.ocx.dynamicCall("CommConnect()")
if block:
while not self.connected:
pythoncom.PumpWaitingMessages()
def CommRqData(self, rqname, trcode, next, screen):
"""
TR을 서버로 송신합니다.
:param rqname: 사용자가 임의로 지정할 수 있는 요청 이름
:param trcode: 요청하는 TR의 코드
:param next: 0: 처음 조회, 2: 연속 조회
:param screen: 화면번호 ('0000' 또는 '0' 제외한 숫자값으로 200개로 한정된 값
:return: None
"""
self.ocx.dynamicCall("CommRqData(QString, QString, int, QString)", rqname, trcode, next, screen)
def GetLoginInfo(self, tag):
"""
로그인한 사용자 정보를 반환하는 메서드
:param tag: ("ACCOUNT_CNT, "ACCNO", "USER_ID", "USER_NAME", "KEY_BSECGB", "FIREW_SECGB")
:return: tag에 대한 데이터 값
"""
data = self.ocx.dynamicCall("GetLoginInfo(QString)", tag)
if tag == "ACCNO":
return data.split(';')[:-1]
else:
return data
def SendOrder(self, rqname, screen, accno, order_type, code, quantity, price, hoga, order_no):
"""
주식 주문을 서버로 전송하는 메서드
시장가 주문시 주문단가는 0으로 입력해야 함 (가격을 입력하지 않음을 의미)
:param rqname: 사용자가 임의로 지정할 수 있는 요청 이름
:param screen: 화면번호 ('0000' 또는 '0' 제외한 숫자값으로 200개로 한정된 값
:param accno: 계좌번호 10자리
:param order_type: 1: 신규매수, 2: 신규매도, 3: 매수취소, 4: 매도취소, 5: 매수정정, 6: 매도정정
:param code: 종목코드
:param quantity: 주문수량
:param price: 주문단가
:param hoga: 00: 지정가, 03: 시장가,
05: 조건부지정가, 06: 최유리지정가, 07: 최우선지정가,
10: 지정가IOC, 13: 시장가IOC, 16: 최유리IOC,
20: 지정가FOK, 23: 시장가FOK, 26: 최유리FOK,
61: 장전시간외종가, 62: 시간외단일가, 81: 장후시간외종가
:param order_no: 원주문번호로 신규 주문시 공백, 정정이나 취소 주문시에는 원주문번호를 입력
:return:
"""
ret = self.ocx.dynamicCall("SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)",
[rqname, screen, accno, order_type, code, quantity, price, hoga, order_no])
return ret
def SetInputValue(self, id, value):
"""
TR 입력값을 설정하는 메서드
:param id: TR INPUT의 아이템명
:param value: 입력 값
:return: None
"""
self.ocx.dynamicCall("SetInputValue(QString, QString)", id, value)
def DisconnectRealData(self, screen):
"""
화면번호에 대한 리얼 데이터 요청을 해제하는 메서드
:param screen: 화면번호
:return: None
"""
self.ocx.dynamicCall("DisconnectRealData(QString)", screen)
def GetRepeatCnt(self, trcode, rqname):
"""
멀티데이터의 행(row)의 개수를 얻는 메서드
:param trcode: TR코드
:param rqname: 사용자가 설정한 요청이름
:return: 멀티데이터의 행의 개수
"""
count = self.ocx.dynamicCall("GetRepeatCnt(QString, QString)", trcode, rqname)
return count
def CommKwRqData(self, arr_code, next, code_count, type, rqname, screen):
"""
여러 종목 (한 번에 100종목)에 대한 TR을 서버로 송신하는 메서드
:param arr_code: 여러 종목코드 예: '000020:000040'
:param next: 0: 처음조회
:param code_count: 종목코드의 개수
:param type: 0: 주식종목 3: 선물종목
:param rqname: 사용자가 설정하는 요청이름
:param screen: 화면번호
:return:
"""
ret = self.ocx.dynamicCall("CommKwRqData(QString, bool, int, int, QString, QString)", arr_code, next, code_count, type, rqname, screen);
return ret
def GetAPIModulePath(self):
"""
OpenAPI 모듈의 경로를 반환하는 메서드
:return: 모듈의 경로
"""
ret = self.ocx.dynamicCall("GetAPIModulePath()")
return ret
def GetCodeListByMarket(self, market):
"""
시장별 상장된 종목코드를 반환하는 메서드
:param market: 0: 코스피, 3: ELW, 4: 뮤추얼펀드 5: 신주인수권 6: 리츠
8: ETF, 9: 하이일드펀드, 10: 코스닥, 30: K-OTC, 50: 코넥스(KONEX)
:return: 종목코드 리스트 예: ["000020", "000040", ...]
"""
data = self.ocx.dynamicCall("GetCodeListByMarket(QString)", market)
tokens = data.split(';')[:-1]
return tokens
def GetConnectState(self):
"""
현재접속 상태를 반환하는 메서드
:return: 0:미연결, 1: 연결완료
"""
ret = self.ocx.dynamicCall("GetConnectState()")
return ret
def GetMasterCodeName(self, code):
"""
종목코드에 대한 종목명을 얻는 메서드
:param code: 종목코드
:return: 종목명
"""
data = self.ocx.dynamicCall("GetMasterCodeName(QString)", code)
return data
def GetMasterListedStockCnt(self, code):
"""
종목에 대한 상장주식수를 리턴하는 메서드
:param code: 종목코드
:return: 상장주식수
"""
data = self.ocx.dynamicCall("GetMasterListedStockCnt(QString)", code)
return data
def GetMasterConstruction(self, code):
"""
종목코드에 대한 감리구분을 리턴
:param code: 종목코드
:return: 감리구분 (정상, 투자주의 투자경고, 투자위험, 투자주의환기종목)
"""
data = self.ocx.dynamicCall("GetMasterConstruction(QString)", code)
return data
def GetMasterListedStockDate(self, code):
"""
종목코드에 대한 상장일을 반환
:param code: 종목코드
:return: 상장일 예: "20100504"
"""
data = self.ocx.dynamicCall("GetMasterListedStockDate(QString)", code)
return datetime.datetime.strptime(data, "%Y%m%d")
def GetMasterLastPrice(self, code):
"""
종목코드의 전일가를 반환하는 메서드
:param code: 종목코드
:return: 전일가
"""
data = self.ocx.dynamicCall("GetMasterLastPrice(QString)", code)
return int(data)
def GetMasterStockState(self, code):
"""
종목의 종목상태를 반환하는 메서드
:param code: 종목코드
:return: 종목상태
"""
data = self.ocx.dynamicCall("GetMasterStockState(QString)", code)
return data.split("|")
def GetDataCount(self, record):
count = self.ocx.dynamicCall("GetDataCount(QString)", record)
return count
def GetOutputValue(self, record, repeat_index, item_index):
count = self.ocx.dynamicCall("GetOutputValue(QString, int, int)", record, repeat_index, item_index)
return count
def GetCommData(self, trcode, rqname, index, item):
"""
수순 데이터를 가져가는 메서드
:param trcode: TR 코드
:param rqname: 요청 이름
:param index: 멀티데이터의 경우 row index
:param item: 얻어오려는 항목 이름
:return:
"""
data = self.ocx.dynamicCall("GetCommData(QString, QString, int, QString)", trcode, rqname, index, item)
return data.strip()
def GetCommRealData(self, code, fid):
data = self.ocx.dynamicCall("GetCommRealData(QString, int)", code, fid)
return data
def GetChejanData(self, fid):
data = self.ocx.dynamicCall("GetChejanData(int)", fid)
return data
def GetThemeGroupList(self, type=1):
data = self.ocx.dynamicCall("GetThemeGroupList(int)", type)
tokens = data.split(';')
if type == 0:
grp = {x.split('|')[0]:x.split('|')[1] for x in tokens}
else:
grp = {x.split('|')[1]: x.split('|')[0] for x in tokens}
return grp
def GetThemeGroupCode(self, theme_code):
data = self.ocx.dynamicCall("GetThemeGroupCode(QString)", theme_code)
data = data.split(';')
return [x[1:] for x in data]
def GetFutureList(self):
data = self.ocx.dynamicCall("GetFutureList()")
return data
def GetCommDataEx(self, trcode, record):
data = self.ocx.dynamicCall("GetCommDataEx(QString, QString)", trcode, record)
return data
def block_request(self, *args, **kwargs):
trcode = args[0].lower()
lines = parser.read_enc(trcode)
self.tr_items = parser.parse_dat(trcode, lines)
self.tr_record = kwargs["output"]
next = kwargs["next"]
# set input
for id in kwargs:
if id.lower() != "output" and id.lower() != "next":
self.SetInputValue(id, kwargs[id])
# initialize
self.received = False
self.tr_remained = False
# request
self.CommRqData(trcode, trcode, next, "0101")
while not self.received:
pythoncom.PumpWaitingMessages()
return self.tr_data
def SetRealReg(self, screen, code_list, fid_list, real_type):
ret = self.ocx.dynamicCall("SetRealReg(QString, QString, QString, QString)", screen, code_list, fid_list, real_type)
return ret
def SetRealRemove(self, screen, del_code):
ret = self.ocx.dynamicCall("SetRealRemove(QString, QString)", screen, del_code)
return ret
def GetConditionLoad(self, block=True):
self.condition_loaded = False
self.ocx.dynamicCall("GetConditionLoad()")
if block:
while not self.condition_loaded:
pythoncom.PumpWaitingMessages()
def GetConditionNameList(self):
data = self.ocx.dynamicCall("GetConditionNameList()")
conditions = data.split(";")[:-1]
# [('000', 'perpbr'), ('001', 'macd'), ...]
result = []
for condition in conditions:
cond_index, cond_name = condition.split('^')
result.append((cond_index, cond_name))
return result
def SendCondition(self, screen, cond_name, cond_index, search):
self.tr_condition_loaded = False
self.ocx.dynamicCall("SendCondition(QString, QString, int, int)", screen, cond_name, cond_index, search)
while not self.tr_condition_loaded:
pythoncom.PumpWaitingMessages()
return self.tr_condition_data
def SendConditionStop(self, screen, cond_name, index):
self.ocx.dynamicCall("SendConditionStop(QString, QString, int)", screen, cond_name, index)
def GetCommDataEx(self, trcode, rqname):
data = self.ocx.dynamicCall("GetCommDataEx(QString, QString)", trcode, rqname)
return data
def SendOrder(self, rqname, screen, accno, order_type, code, quantity, price, hoga, order_no):
self.ocx.dynamicCall("SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)",
[rqname, screen, accno, order_type, code, quantity, price, hoga, order_no])
# 주문 후 0.2초 대기
time.sleep(0.2)
if not QApplication.instance():
app = QApplication(sys.argv)
if __name__ == "__main__":
# 로그인
kiwoom = Kiwoom()
kiwoom.CommConnect(block=True)
# 조건식 load
kiwoom.GetConditionLoad()
conditions = kiwoom.GetConditionNameList()
# 0번 조건식에 해당하는 종목 리스트 출력
condition_index = conditions[0][0]
condition_name = conditions[0][1]
codes = kiwoom.SendCondition("0101", condition_name, condition_index, 0)
print(codes)
2 opw0004[편집]
# TR/opw00004
from pykiwoom.kiwoom import *
# 로그인
kiwoom = Kiwoom()
kiwoom.CommConnect(block=True)
# 계좌번호는 11을 붙여서 10자리임
account_list = kiwoom.GetLoginInfo("ACCNO")
account = account_list[0]
print(account)
# opw00001 요청
df = kiwoom.block_request("opw00004",
계좌번호=account,
비밀번호="",
상장폐지조회구분=0,
비밀번호입력매체구분="00",
output="계좌평가현황",
next=0)
print(df)
for column in df.columns:
print(column, df.loc[0][column])
3 opw00018 single[편집]
# TR/opw00018
from pykiwoom.kiwoom import *
# 로그인
kiwoom = Kiwoom()
kiwoom.CommConnect(block=True)
# 계좌번호는 11을 붙여서 10자리임
account_list = kiwoom.GetLoginInfo("ACCNO")
account = account_list[0]
print(account)
# opw00018 요청 (싱글데이터)
df = kiwoom.block_request("opw00018",
계좌번호=account,
비밀번호="",
비밀번호입력매체구분="00",
조회구분=2,
output="계좌평가결과",
next=0)
print(df)
4 opw00018 multi[편집]
# TR/opw00018
from pykiwoom.kiwoom import *
# 로그인
kiwoom = Kiwoom()
kiwoom.CommConnect(block=True)
# 계좌번호는 11을 붙여서 10자리임
account_list = kiwoom.GetLoginInfo("ACCNO")
account = account_list[0]
print(account)
# opw00018 요청
df = kiwoom.block_request("opw00018",
계좌번호=account,
비밀번호="",
비밀번호입력매체구분="00",
조회구분=2,
output="계좌평가잔고개별합산",
next=0)
print(df)
df.to_excel("opw00018.xlsx")