def get_multi_response(self, tr_code, tr_name, pre_next, output_format): list = [] count = self.dynamicCall("GetRepeatCnt(QString, QString)", tr_code, tr_name) code = None log.instance().logger().debug("LIST COUNT: {0}".format(count)) for i in range(0, count): data = {} for key, value in output_format["output_list"].items(): kr = value["kr"] type = value["type"] value = self.kiwoom_GetCommData(tr_code, tr_name, i, kr).strip() data[key] = self.tr_util.parse_response(value, type) if i == 0: if 'code' in data.keys(): code = data["code"] else: if code: data["code"] = code list.append(data) log.instance().logger().debug("TR: {0}\tDATA: {1}".format( tr_name, list)) return list
def get(self): """ get real time stock info :return: """ table_name = "stock" list_temp = self.db.dist(table_name, "code") size = 100 page = 1 count = len(list_temp) def isNotEmpty(x): return len(x) > 0 # self.hts.get_daily_stock_open_status() # time.sleep(2) for i in range(0, count, size): code_list = list_temp[i: i + size if size + i <= count else count] log.instance().logger().debug("SET REAL RES: {0} {1}".format(page, code_list)) self.hts.set_real_stocks(code_list) code_list = list(filter(isNotEmpty, code_list)) if page == 1: self.hts.set_check_market_state("{0:05}".format(page), ";".join(code_list), "0") else: self.hts.set_check_market_state("{0:05}".format(page), ";".join(code_list), "1") # print("") time.sleep(2) page += 1 self.hts.multiEvents["STOCK"] = QEventLoop() self.hts.multiEvents["STOCK"].exec_()
def get(self): """ restore kospi code """ log.instance().logger().debug("code handler") # query = self.get_argument('query', None) # if query is not None: """ [시장구분값] 0 : 장내 10 : 코스닥 3 : ELW 8 : ETF 50 : KONEX 4 : 뮤추얼펀드 5 : 신주인수권 6 : 리츠 9 : 하이얼펀드 30 : K-OTC """ self.time = datetime.datetime.now().strftime("%H") if self.time < "09": d = datetime.datetime.now().date() self.today = "{0}{1:02}{2:02}".format(datetime.datetime.now().year, datetime.datetime.now().month, datetime.datetime.now().day - 1) else: self.today = datetime.datetime.now().strftime("%Y%m%d") # KOSPI ks = self.reload_kospi("0", self.today) index = 1 size = len(ks) for i in ks: print("{0}/{1}: {3}-{2}".format(index, size, i["code"], i["market"])) index = index + 1 try: self.loadYahooHistory(i["code"], i["market"]) except: print("Oops! That was no valid number. Try again...") # KOSDAQ kq = self.reload_kospi("10", self.today) index = 1 size = len(kq) for i in kq: print("{0}/{1}: {3}-{2}".format(index, size, i["code"], i["market"])) index = index + 1 try: self.loadYahooHistory(i["code"], i["market"]) except: print("Oops! That was no valid number. Try again...") self.store() return { "ks": ks, "kq": kq }
def check_market_open(self): fid = "215;20;214" res = self.dynamicCall( "SetRealReg(QString, QString, QString, QString)", "1000", "", fid, "0") log.instance().logger().debug("SetRealReg RES: {0}".format(res)) if res < 0: log.instance().logger().debug("SetRealReg RES: {0}".format( errors(res))) self.event.exit()
def get_single_response(self, tr_code, tr_name, pre_next, output_format): data = {} for key, value in output_format["output"].items(): kr = value["kr"] type = value["type"] value = self.kiwoom_GetCommData(tr_code, tr_name, 0, kr).strip() data[key] = self.tr_util.parse_response(value, type) log.instance().logger().debug("TR: {0}\tDATA: {1}".format( tr_name, data)) # self.dict_callback[tr_name] = data return data
def kiwoom_CommRqData(self, sRQName, sTrCode, nPrevNext, sScreenNo): """ :param sRQName: :param sTrCode: :param nPrevNext: :param sScreenNo: :return: """ res = self.dynamicCall("CommRqData(QString, QString, int, QString)", sRQName, sTrCode, nPrevNext, sScreenNo) log.instance().logger().debug("CommRqData RES: {0}".format(res)) if res < 0: log.instance().logger().debug("CommRqData RES: {0}".format( errors(res))) self.event.exit() return res
def get(self): """ restore kospi code """ log.instance().logger().debug("stock daily handler") code = self.get_argument('code', None) today = self.get_argument('today', None) if today is None: today = datetime.datetime.now().strftime("%Y%m%d") result = None if code is not None: result = self.hts.get_daily_stock_info_detail(code, today) # self.hts.save_daily_stock_info(code, result) self.write(json.dumps(result))
def get(self): """ restore kospi code """ log.instance().logger().debug("code handler") code = self.get_argument('code', None) # query = self.get_argument('query', None) result = None # if query is not None: if code is None: result = self.reload_kospi() else: result = self.get_stock_info(code) self.write(json.dumps(result))
def func_wrapper(self, *args, **kwargs): # self.request_thread_worker.request_queue.append((func, args, kwargs)) arg_names = inspect.getfullargspec(func).args if 'pre_next' in arg_names: index = arg_names.index('pre_next') - 1 else: index = -1 log.instance().logger().debug("요청 실행: %s %s %s" % (func.__name__, args, kwargs)) res = func(self, *args, **kwargs) if index < 0 or len(args) <= index or args[index] != '2': log.instance().logger().debug("EVENT INIT") self.event = QEventLoop() self.params = {} self.result = {} self.event.exec_() self.result['res'] = res return self.result # 콜백 결과 반환
def commKwRqData(self, codes, codeCount, requestName, screenNo, inquiry=0, typeFlag=0): """ 복수종목조회 메서드(관심종목조회 메서드라고도 함). 이 메서드는 setInputValue() 메서드를 이용하여, 사전에 필요한 값을 지정하지 않는다. 단지, 메서드의 매개변수에서 직접 종목코드를 지정하여 호출하며, 데이터 수신은 receiveTrData() 이벤트에서 아래 명시한 항목들을 1회 수신하며, 이후 receiveRealData() 이벤트를 통해 실시간 데이터를 얻을 수 있다. 복수종목조회 TR 코드는 OPTKWFID 이며, 요청 성공시 아래 항목들의 정보를 얻을 수 있다. 종목코드, 종목명, 현재가, 기준가, 전일대비, 전일대비기호, 등락율, 거래량, 거래대금, 체결량, 체결강도, 전일거래량대비, 매도호가, 매수호가, 매도1~5차호가, 매수1~5차호가, 상한가, 하한가, 시가, 고가, 저가, 종가, 체결시간, 예상체결가, 예상체결량, 자본금, 액면가, 시가총액, 주식수, 호가시간, 일자, 우선매도잔량, 우선매수잔량,우선매도건수, 우선매수건수, 총매도잔량, 총매수잔량, 총매도건수, 총매수건수, 패리티, 기어링, 손익분기, 잔본지지, ELW행사가, 전환비율, ELW만기일, 미결제약정, 미결제전일대비, 이론가, 내재변동성, 델타, 감마, 쎄타, 베가, 로 :param codes: string - 한번에 100종목까지 조회가능하며 종목코드사이에 세미콜론(;)으로 구분. :param inquiry: int - api 문서는 bool 타입이지만, int로 처리(0: 조회, 1: 남은 데이터 이어서 조회) :param codeCount: int - codes에 지정한 종목의 갯수. :param requestName: string :param screenNo: string :param typeFlag: int - 주식과 선물옵션 구분(0: 주식, 3: 선물옵션), 주의: 매개변수의 위치를 맨 뒤로 이동함. :return: list - 중첩 리스트 [[종목코드, 종목명 ... 종목 정보], [종목코드, 종목명 ... 종목 정보]] """ if not (isinstance(codes, str) and isinstance(inquiry, int) and isinstance(codeCount, int) and isinstance(requestName, str) and isinstance(screenNo, str) and isinstance(typeFlag, int)): raise ParameterTypeError() res = self.dynamicCall( "CommKwRqData(QString, QBoolean, int, int, QString, QString)", codes, inquiry, codeCount, typeFlag, requestName, screenNo) log.instance().logger().debug("CommKwRqData RES: {0}".format(res)) if res < 0: log.instance().logger().debug("CommKwRqData RES: {0}".format( errors(res))) self.event.exit()
def get(self): """ Request data must contain accno : account number the transaction will happen """ accno = self.get_argument('accno', None) # data = tornado.escape.json_decode(self.request.body) log.instance().logger().debug("BalanceHandler: incoming") # log.instance().logger().debug(data) hts = self.hts hts.deposit = None result = hts.kiwoom_tr_account_balance(accno, "1000") while not hts.deposit: time.sleep(self.SLEEP_TIME) cash = hts.deposit result = {} result["cash"] = cash log.instance().logger().debug("Response to client:") log.instance().logger().debug(str(result)) self.write(json.dumps(result))
def kiwoom_tr_recall(self, tr_name, tr_code, screen_no, pre_next): time.sleep(3.6) time.sleep(self.LONG_SLEEP_TIME) log.instance().logger().debug("연속조회") if tr_code.lower() == 'OPT10081'.lower(): log.instance().logger().debug("OPT10081는 안 함") # self.kiwoom_tr_daily_stock_info(self.dict_callback_temp[0]["code"], self.dict_callback_temp[len(self.dict_callback_temp)-1]["date"], pre_next, '0') elif tr_code.lower() == 'OPT10086'.lower(): param = self.dict_call_param[tr_code] if param: # {"종목코드": code, "조회일자": date, "수정주가구분": type, 'last_date': last_date} response = self.dict_callback_temp last_date = param['last_date'] selected_list = list( filter(lambda x: (x['date'] < last_date), response)) if len(selected_list) == 0: self.kiwoom_tr_daily_stock_info_detail( param["종목코드"], param["조회일자"], param['last_date'], pre_next, param["수정주가구분"]) else: pre_next = '0' return pre_next
def kiwoom_OnEventConnect(self, nErrCode, **kwargs): """로그인 결과 수신 로그인 성공시 [조건목록 요청]GetConditionLoad() 실행 :param nErrCode: 0: 로그인 성공, 100: 사용자 정보교환 실패, 101: 서버접속 실패, 102: 버전처리 실패 :param kwargs: :return: """ if nErrCode == 0: log.instance().logger().debug("로그인 성공") elif nErrCode == 100: log.instance().logger().debug("사용자 정보교환 실패") elif nErrCode == 101: log.instance().logger().debug("서버접속 실패") elif nErrCode == 102: log.instance().logger().debug("버전처리 실패") self.result['result'] = nErrCode if self.event is not None: self.event.exit()
def check_market_state(self, screenId, codes, addType="1"): # fid = "10;20;11;12;15;13;14;15;29;567;568;" fid = "10;20" res = self.dynamicCall( "SetRealReg(QString, QString, QString, QString)", screenId, codes, fid, addType) log.instance().logger().debug( "SetRealReg RES: {0} {1} {2} {3} {4}".format( res, screenId, codes, fid, addType)) if res < 0: log.instance().logger().debug("SetRealReg RES ERROR: {0}".format( errors(res))) # self.event.exit() else: log.instance().logger().debug("SetRealReg RES SUCCESS: {0}".format( errors(res))) # self.multiEvents[screenId] = QEventLoop() # self.multiEvents[screenId].exec_() # self.event.exit() return res
def __init__(self): log.instance().logger().debug("Kiwoom_tr_parse_util init")
def get_kospi_list(self, today=None, market_type="0"): """ KOSPI 정보만 불러옴 나중에는 코스닥도 한번 """ table_name = 'stock' ret = self.dynamicCall("GetCodeListByMarket(QString)", [market_type]) temp_kospi_code_list = ret.split(';') kospi_code_list = [] kospi_list = [] if today is None: today = datetime.datetime.now().strftime("%Y%m%d") for v in temp_kospi_code_list: if not v: continue if int(v[:2]) <= 12: kospi_code_list.append(v) print(temp_kospi_code_list) print(kospi_code_list) # return kospi_code_list pre = self.db.find(table_name, {'date': today}) # pre = self.db.find('code', {'date': '20200529'}) print(len(pre)) pre_code_list = [] # { "address": { "$regex": "^S" } } codes = [] if pre is not None: for x in pre: if 'code' in x.keys(): pre_code_list.append(x['code']) for code in kospi_code_list: if code in pre_code_list: log.instance().logger().debug( "IT WAS STORED: {0}".format(code)) continue time.sleep(self.SLEEP_TIME) last_price = self.dynamicCall("GetMasterLastPrice(QString)", [code]) if last_price == '': last_price = 0 else: last_price = int(last_price) item = { "code": code, "date": today # , "name": self.dynamicCall("GetMasterCodeName(QString)", [code]) # , "stock_count": int(self.dynamicCall("GetMasterListedStockCnt(QString)", [code])) # (정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목) , "company_state": self.dynamicCall("GetMasterConstruction(QString)", [code]) # , "listing_date": self.dynamicCall("GetMasterListedStockDate(QString)", [code]) # , "last_price": last_price # (정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목) , "stock_state": self.dynamicCall("GetMasterStockState(QString)", [code]) } time.sleep(self.SLEEP_TIME * 16) print("종목 정보: ", item) # if '투자주의' in item["stock_state"] or '투자경고' in item["company_state"] or '투자위험' in item["company_state"] or '투자주의환기종목' in item["company_state"]: # continue tr_code = self.kiwoom_tr_stock_info(code)['res'] keys = self.dict_callback.keys() count = 0 while tr_code not in keys and count < 20: time.sleep(self.SLEEP_TIME) count += 1 # print("count ", count) if count >= 20: break detail = self.dict_callback.pop(tr_code, None) for key, value in detail.items(): item[key] = value if market_type == "0": item["market"] = "KS" elif market_type == "10": item["market"] = "KQ" print("종목 상세 정보: ", item) kospi_list.append(item) self.db.add(table_name, item) # self.db.add('code', kospi_list) stored_list = self.db.find(table_name, {'date': today}) # pre = self.db.find('code', {'date': '20200529'}) # { "address": { "$regex": "^S" } } return stored_list
def func_wrapper(self, *args, **kwargs): log.instance().logger().debug("요청 콜백: %s %s %s" % (func.__name__, args, kwargs)) func(self, *args, **kwargs) # 콜백 함수 호출
("/real", RealTimeHandler, dict(SLEEP_TIME=SLEEP_TIME, hts=hts, db=db)), ("/remove", RealTimeRemoveHandler, dict(SLEEP_TIME=SLEEP_TIME, hts=hts, db=db)), ("/code", StockCodeHandler, dict(SLEEP_TIME=SLEEP_TIME, hts=hts, db=db)), ("/store", FileStoreHandler, dict(db=db)) ] # Autoreload seems troublesome. return Application(urls, debug=True, autoreload=False) if __name__ == "__main__": # login if hts.kiwoom_GetConnectState() != 0: log.instance().logger().debug('Connection failed') sys.exit() log.instance().logger().debug('로그인 시도') res = hts.kiwoom_CommConnect() if res.get('result') != 0: log.instance().logger().debug('Login failed') sys.exit() # To see list of your accounts... if True: accounts = hts.kiwoom_GetAccList() log.instance().logger().debug("Your accounts:") for acc in accounts: log.instance().logger().debug(acc)
def kiwoom_OnReceiveTrData(self, screen_no, tr_name, tr_code, record_name, pre_next, data_length, error_code, message, sSPlmMsg, **kwargs): """TR 요청에 대한 결과 수신 데이터 얻어오기 위해 내부에서 GetCommData() 호출 GetCommData( BSTR tr_code, // TR 이름 BSTR tr_name, // 레코드이름 long nIndex, // TR반복부 BSTR strItemName) // TR에서 얻어오려는 출력항목이름 :param screen_no: 화면번호 :param tr_name: 사용자 구분명 :param tr_code: TR이름 :param record_name: 레코드 이름 :param pre_next: 연속조회 유무를 판단하는 값 0: 연속(추가조회)데이터 없음, 2:연속(추가조회) 데이터 있음 :param data_length: 사용안함 :param error_code: 사용안함 :param message: 사용안함 :param sSPlmMsg: 사용안함 :param kwargs: :return: """ log.instance().logger().debug("TR name : {0} | code : {1}".format( tr_name, tr_code)) if tr_name == "예수금상세현황요청": self.deposit = int( self.kiwoom_GetCommData(tr_code, tr_name, 0, "주문가능금액")) log.instance().logger().debug("예수금상세현황요청: %s" % (self.deposit, )) if "예수금상세현황요청" in self.dict_callback: self.dict_callback["예수금상세현황요청"](self.deposit) response = None if self.code.in_code(tr_name): code_info = self.code.get_code_info(tr_name) if 'output' in code_info.keys(): response = self.get_single_response(tr_code, tr_name, pre_next, code_info) elif 'output_list' in code_info.keys(): response = self.get_multi_response(tr_code, tr_name, pre_next, code_info) # 임시 코드 if tr_code.lower() == 'OPT10081'.lower(): pre_next = '0' if isinstance(response, (dict)): self.dict_callback[tr_name] = response self.dict_callback_temp = None elif isinstance(response, (list)) and len(response) == 0: if self.dict_callback_temp is None: self.dict_callback[tr_name] = [] else: self.dict_callback[tr_name] = self.dict_callback_temp.copy() self.dict_callback_temp = None pre_next = '0' elif pre_next == '0': if self.dict_callback_temp is None: self.dict_callback[tr_name] = response else: prev = self.dict_callback_temp.copy() self.dict_callback_temp = None prev.extend(response) self.dict_callback[tr_name] = prev elif pre_next == '': log.instance().logger().debug("다음이 없음") else: if self.dict_callback_temp is None: self.dict_callback_temp = response else: self.dict_callback_temp.extend(response) pre_next = self.kiwoom_tr_recall(tr_name, tr_code, screen_no, pre_next) if pre_next == '0': if self.dict_callback_temp: temp = self.dict_callback_temp.copy() self.dict_callback_temp = None self.dict_callback[tr_name] = temp else: self.dict_callback[tr_name] = [] if self.event and pre_next != '2': self.event.exit()
def clear_market_state(self, screen=""): res = self.dynamicCall("DisconnectRealData(QString)", screen) res = 1 log.instance().logger().debug( "DisconnectRealData RES: {0}".format(res))
def remove_real(self): res = self.dynamicCall("SetRealRemove(QString, QString)", "ALL", "ALL") log.instance().logger().debug("SetRealRemove RES: {0}".format(res))
def set_input(self, data): for key, value in data.items(): log.instance().logger().debug("K : {0} | V : {1}".format( key, value)) self.kiwoom_SetInputValue(key, value)