Source code for pyqqq.brokerage.ebest.domestic_stock

from pyqqq.brokerage.ebest.oauth import EBestAuth
from pyqqq.brokerage.ebest.tr_client import (
    EBestTRClient,
    EBestTRWebsocketClient,
    EBestTRWebsocketKeepConnectionStatus,
)
from pyqqq.utils.limiter import CallLimiter
from pyqqq.utils.market_schedule import get_market_schedule
from typing import AsyncGenerator
import asyncio
import datetime as dtm
import json
import websockets


[docs] class EBestDomesticStock: """ LS(구 이베스트투자)증권 국내주식 API """
[docs] def __init__(self, auth: EBestAuth, corp_data: dict = None): self.auth = auth self.corp_data = corp_data self.tr_client = EBestTRClient(auth)
def _tr_request(self, *args, **kwargs): return self.tr_client.request(*args, **kwargs)
[docs] def get_asset_list(self, market_type: str = "0") -> list: """ ([주식]기타) 주식종목조회 API용 (t8436) Args: market_type (str): 시장유형 (0:전체 1:코스피 2:코스닥) Returns: dict: - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - output (list): 주식 종목 리스트 - hname (str): 종목명 - shcode (str): 단축코드 - expcode (str): 확장코드 - etfgubun (str): ETF구분 (0:일반 1:ETF 2:ETN) - uplmtprice (float): 상한가 - dnlmtprice (float): 하한가 - jnilclose (float): 전일종가 - memedan (float): 주문수량단위 - recprice (int): 기준가 - gubun (str): 구분 (1:코스피 2:코스닥) - bu12gubun (str): 12월결산월 - spac_gubun (str): 기업인수목적회사여부 (Y:기업인수목적회사) - filler (str): filler """ CallLimiter().wait_limit_rate(2, scope="ebest/t8436") assert market_type in ["0", "1", "2"], "Invalid market type" tr_code = "t8436" req_body = {f"{tr_code}InBlock": {"gubun": market_type}} res_body, _ = self._tr_request("/stock/etc", tr_code, body=req_body) result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "output": res_body.get("t8436OutBlock", []), } return result
[docs] def get_price(self, asset_code: str, exchgubun: str = "K") -> dict: """ ([주식]시세) 주식현재가(시세)조회 (t1102) Args: asset_code (str): 종목 코드 exchgubun (str): 거래소 코드 (K:KRX N:NXT U:통합) Returns: dict: 종목의 현재가 정보 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - output (list): 종목의 현재가 정보 """ assert len(asset_code) == 6, "Invalid asset code" assert exchgubun in ["K", "N", "U"], "Invalid exchange code" CallLimiter().wait_limit_rate(3, scope="ebest/t1102") tr_code = "t1102" req_body = { f"{tr_code}InBlock": {"shcode": asset_code, "exchgubun": exchgubun}, } res_body, _ = self._tr_request("/stock/market-data", tr_code, body=req_body) result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "output": res_body.get("t1102OutBlock", []), } return result
[docs] def get_stock_time_conclude( self, asset_code: str, cvolume: int, start_time: dtm.time, end_time: dtm.time, cts_time: str = "", tr_cont_key: str = "", ) -> dict: """ ([주식]시세) 주식시간대별체결조회 (t1301) Args: asset_code (str): 종목 코드 cvolume (int): 특이거래량 start_time (dtm.time): 시작시간 - 장시작시간 이후 end_time (dtm.time): 종료시간 - 장종료시간 이전 cts_time (str): 연속시간 - 연속조회시 OutBlock의 동일필드 입력 Returns: dict: 주식 시간대별 체결 정보 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - tr_cont (str): 연속조회여부 - tr_cont_key (str): 연속조회키 - output (list): 주식 시간대별 체결 정보 """ CallLimiter().wait_limit_rate(2, scope="ebest/t1301") assert len(asset_code) == 6, "Invalid asset code" tr_code = "t1301" tr_cont = "Y" if cts_time else "N" req_body = { f"{tr_code}InBlock": { "shcode": asset_code, "cvolume": cvolume, "starttime": start_time.strftime("%H%M"), "endtime": end_time.strftime("%H%M"), "cts_time": cts_time, } } res_body, res_header = self._tr_request( "/stock/market-data", tr_code, tr_cont=tr_cont, tr_cont_key=tr_cont_key, body=req_body, ) result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "tr_cont": res_header.get("tr_cont", ""), "tr_cont_key": res_header.get("tr_cont_key", ""), "output": res_body.get("t1301OutBlock", []), } return result
[docs] def get_stock_minute_prices( self, shcode: str, gubun: str, cnt=900, cts_time: str = "", tr_cont_key: str = "", exchgubun: str = "K", ): """ ([주식]시세) 주식분별주가조회 (t1302) Args: shcode (str): 종목 코드 gubun (str): 주기구분 (0:30초 1:1분 2:3분 3:5분 4:10분 5:30분 6:60분) cnt (int): 조회건수 - 최대 900 cts_time (str): 연속시간 - 연속조회시 OutBlock의 동일필드 입력 tr_cont_key (str): 연속조회키 - 연속조회시 이전 응답 헤더의 동일필드 입력 exchgubun (str): 거래소 코드 (K:KRX N:NXT U:통합) Returns: dict: 주식 분별 주가 정보 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - tr_cont (str): 연속조회여부 - tr_cont_key (str): 연속조회키 - output1 (dict): 연속 조회를 위한 cts_time 필드를 포함 - output2 (list): 주식 분별 주가 정보 """ CallLimiter().wait_limit_rate(1, scope="ebest/t1302") assert len(shcode) == 6, "Invalid asset code" assert gubun in ["0", "1", "2", "3", "4", "5", "6"], "Invalid gubun" assert exchgubun in ["K", "N", "U"], "Invalid exchange code" tr_code = "t1302" tr_cont = "Y" if cts_time else "N" req_body = { f"{tr_code}InBlock": { "shcode": shcode, "gubun": gubun, "cnt": cnt, "time": cts_time, "exchgubun": exchgubun, } } res_body, res_header = self._tr_request( "/stock/market-data", tr_code, tr_cont=tr_cont, tr_cont_key=tr_cont_key, body=req_body, ) result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "tr_cont": res_header.get("tr_cont", ""), "tr_cont_key": res_header.get("tr_cont_key", ""), "output1": res_body.get("t1302OutBlock", {}), "output2": res_body.get("t1302OutBlock1", []), } return result
def get_period_profit( self, start_date: dtm.date, end_date: dtm.date, term_type: str = "1", tr_cont_key: str = "", ): """ ([주식]계좌) 주식계좌 기간별 수익률 상세 (FOCCQ33600) Args: start_date (dtm.date): 시작일자 end_date (dtm.date): 종료일자 term_type (str): 기간구분 (1:일 2:주 3:월) Returns: dict: 주식 계좌 기간별 수익률 상세 정보 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - tr_cont (str): 연속조회여부 - tr_cont_key (str): 연속조회키 - output1 (dict): 조회 정보 - RecCnt (int): 레코드갯수 - AcntNo (str): 계좌번호 - QrySrtDt (str): 조회시작일자 - QryEndDt (str): 조회종료일자 - TermTp (str): 기간구분 - output2 (dict): 계좌 거래 정보 - RecCnt (int): 레코드갯수 - AcntNo (str): 계좌번호 - BnsctrAmt (int): 매매약정금액 - MnyinAmt (int): 입금금액 - MnyoutAmt (int): 출금금액 - InvstAvrbalPramt (int): 투자원금평잔금액 - InvstPlAmt (int): 투자손익금액 - InvstErnrat (float): 투자수익률 - output3 (list): 기간별 수익률 상세 정보 - BaseDt (str): 기준일자 - FdEvalAmt (int): 기초평가금액 - EotEvalAmt (int): 기말평가금액 - InvstAvrbalPramt (int): 투자원금평잔금액 - BnsctrAmt (int): 매매약정금액 - MnyinSecinAmt (int): 입금고액 - MnyoutSecoutAmt (int): 출금고액 - EvalPnlAmt (int): 평가손익금액 - TermErnrat (float): 기간수익률 - Idx (float): 지수 """ tr_code = "FOCCQ33600" tr_cont = "Y" if tr_cont_key else "N" assert term_type in ["1", "2", "3"], "Invalid term_type" CallLimiter().wait_limit_rate(1, scope=f"ebest/{tr_code}") req_body = { f"{tr_code}InBlock1": { "QrySrtDt": start_date.strftime("%Y%m%d"), "QryEndDt": end_date.strftime("%Y%m%d"), "TermTp": term_type, } } res_body, res_header = self._tr_request( "/stock/accno", tr_code, tr_cont=tr_cont, tr_cont_key=tr_cont_key, body=req_body, ) output1 = res_body.get(f"{tr_code}OutBlock1", {}) output2 = res_body.get(f"{tr_code}OutBlock2", {}) output3 = res_body.get(f"{tr_code}OutBlock3", []) result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "tr_cont": res_header.get("tr_cont", ""), "tr_cont_key": res_header.get("tr_cont_key", ""), "output1": output1, "output2": output2, "output3": output3, } return result
[docs] def get_stock_tick_data_today_yesterday( self, daygb: int, timegb: int, shcode: str, endtime: dtm.time, cts_time: str = "", tr_cont_key: str = "", exchgubun: str = "K", ): """ ([주식]시세) 주일당일전일분틱조회 (t1310) Args: daygb (int): 일자구분 (0:당일 1:전일) timegb (int): 시간구분 (0:분 1:틱) shcode (str): 종목 코드 endtime (dtm.time): 종료시간 outblock.chetime <= endtime 인 데이터 조회됨 cts_time (str): 연속시간 - 연속조회시 OutBlock의 동일필드 입력 tr_cont_key (str): 연속조회키 - 연속조회시 이전 응답 헤더의 동일필드 입력 exchgubun (str): 거래소 코드 (K:KRX N:NXT U:통합) Returns: dict: 응답 데이터 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - tr_cont (str): 연속조회여부 - tr_cont_key (str): 연속조회키 - output1 (dict): 연속 조회를 위한 cts_time 필드를 포함 - output2 (list): 분틱 정보 """ CallLimiter().wait_limit_rate(1, scope="ebest/t1310") assert daygb in [0, 1], "Invalid daygb" assert timegb in [0, 1], "Invalid timegb" assert len(shcode) >= 6, "Invalid asset code" assert isinstance(endtime, dtm.time), "Invalid endtime" assert exchgubun in ["K", "N", "U"], "Invalid exchange code" tr_code = "t1310" req_body = { f"{tr_code}InBlock": { "daygb": str(daygb), "timegb": str(timegb), "shcode": shcode, "endtime": endtime.strftime("%H%M"), "cts_time": cts_time, "exchgubun": exchgubun, } } tr_cont = "Y" if cts_time else "N" res_body, res_header = self._tr_request( "/stock/market-data", tr_code, tr_cont=tr_cont, tr_cont_key=tr_cont_key, body=req_body, ) result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "tr_cont": res_header.get("tr_cont", ""), "tr_cont_key": res_header.get("tr_cont_key", ""), "output1": res_body.get("t1310OutBlock", {}), "output2": res_body.get("t1310OutBlock1", []), } return result
[docs] def get_stock_chart_dwmy( self, shcode: str, gubun: str, edate: dtm.date, sdate: dtm.date = None, qrycnt: int = 500, cts_date: str = "", comp_yn: bool = False, sujung_yn: bool = True, tr_cont_key: str = "", ): """ ([주식]차트) API전용주식챠트(일주월년) (t8410) Args: shcode (str): 종목 코드 gubun (str): 주기구분 (d:일 w:주 m:월 y:년) edate (dtm.date): 종료일자 - 처음조회기준일(LE) 처음 조회일 경우 이 값 기준으로 조회 sdate (dtm.date): 시작일자 - 기본값(None)인 경우 edate 기준으로 qrycnt 만큼 조회. 조회구간을 설정하여 필터링하고 싶은 경우 입력. qrycnt (int): 요청건수 (최대-압축:2000비압축:500) cts_date (str): 연속일자 - 연속조회시 OutBlock의 동일필드 입력 comp_yn (bool): 압축여부 (True:압축 False:비압축) sujung_yn (bool): 수정주가적용여부 (True:수정주가적용 False:비적용) tr_cont_key (str): 연속조회키 - 연속조회시 이전 응답 헤더의 동일필드 입력 Returns: dict: 주식 차트 정보 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - tr_cont (str): 연속조회여부 - tr_cont_key (str): 연속조회키 - output1 (dict): 전일/당일 시세 정보 - shcode (str): 단축코드 - jisiga (int): 전일시가 - jihigh (int): 전일고가 - jilow (int): 전일저가 - jiclose (int): 전일종가 - jivolume (int): 전일거래량 - disiga (int): 당일시가 - dihigh (int): 당일고가 - dilow (int): 당일저가 - diclose (int): 당일종가 - highend (int): 상한가 - lowend (int): 하한가 - cts_date (str): 연속일자 - s_time (str): 장시작시간 (HHMMSS) - e_time (str): 장종료시간 (HHMMSS) - dshmin (int): 동시호가처리시간 (MM:분) - rec_count (int): 레코드카운트 - svi_uplmtprice (float): 정적VI상한가 - svi_dnlmtprice (float): 정적VI하한가 - output2 (list): 주기별 시세 정보 - date (str): 날짜 - open (int): 시가 - high (int): 고가 - low (int): 저가 - close (int): 종가 - jdiff_vol (int): 거래량 - value (int): 거래대금 - jongchk (str): 수정구분 - rate (float): 수정비율 - pricechk (int): 수정가반영항목 - ratevalue (int): 수정비율반영거래대금 - sign (str): 종가등락구분 (1:상한 2:상승 3:보합 4:하한 5:하락 주식일만사용) """ CallLimiter().wait_limit_rate(1, scope="ebest/t8410") assert len(shcode) == 6, "Invalid asset code" assert gubun.lower() in ["d", "w", "m", "y"], "Invalid gubun" tr_code = "t8410" tr_cont = "Y" if cts_date else "N" req_body = { f"{tr_code}InBlock": { "shcode": shcode, "gubun": {"d": "2", "w": "3", "m": "4", "y": "5"}[gubun.lower()], "qrycnt": qrycnt, "sdate": sdate.strftime("%Y%m%d") if sdate else "", "edate": edate.strftime("%Y%m%d"), "cts_date": cts_date, "comp_yn": "Y" if comp_yn else "N", "sujung": "Y" if sujung_yn else "N", } } res_body, res_header = self._tr_request( "/stock/chart", tr_code, tr_cont=tr_cont, tr_cont_key=tr_cont_key, body=req_body, ) result = { "tr_cont": res_header.get("tr_cont", ""), "tr_cont_key": res_header.get("tr_cont_key", ""), "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "output1": res_body.get("t8410OutBlock", {}), "output2": res_body.get("t8410OutBlock1", []), } return result
[docs] def get_stock_chart_minutes( self, shcode: str, ncnt: int, qrycnt: int, nday: int, edate: dtm.date, sdate: dtm.date = None, cts_date: str = "", cts_time: str = "", comp_yn: bool = False, tr_cont_key: str = "", ) -> dict: """ ([주식]차트) 주식분별주가조회 (t8412) Args: shcode (str): 종목 코드 ncnt (int): 단위(n분) qrycnt (int): 요청건수 (최대-압축:2000비압축:500) nday (int): 조회영업일수(0:미사용 1>=사용) edate (dtm.date): 종료일자 - 처음조회기준일(LE) 처음 조회일 경우 이 값 기준으로 조회 sdate (dtm.date): 시작일자 - 기본값(None)인 경우 edate 기준으로 qrycnt 만큼 조회. 조회구간을 설정하여 필터링하고 싶은 경우 입력. cts_date (str): 연속일자 - 연속조회시 OutBlock의 동일필드 입력 cts_time (str): 연속시간 - 연속조회시 OutBlock의 동일필드 입력 comp_yn (bool): 압축여부 (True:압축 False:비압축) tr_cont_key (str): 연속조회키 - 연속조회시 이전 응답 헤더의 동일필드 입력 Returns: dict: 주식 차트 정보 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - tr_cont (str): 연속조회여부 - tr_cont_key (str): 연속조회키 - output1 (dict): 전일/당일 시세 정보 - output2 (list): 단위 별 주식 차트 정보 """ CallLimiter().wait_limit_rate(1, scope="ebest/t8412") tr_code = "t8412" tr_cont = "Y" if cts_date else "N" req_body = { f"{tr_code}InBlock": { "shcode": shcode, "ncnt": ncnt, "qrycnt": qrycnt, "nday": str(nday), "sdate": sdate.strftime("%Y%m%d") if sdate else "", "edate": edate.strftime("%Y%m%d"), "cts_date": cts_date, "cts_time": cts_time, "comp_yn": "Y" if comp_yn else "N", } } res_body, res_header = self._tr_request( "/stock/chart", tr_code, tr_cont=tr_cont, tr_cont_key=tr_cont_key, body=req_body, ) result = { "tr_cont": res_header.get("tr_cont", ""), "tr_cont_key": res_header.get("tr_cont_key", ""), "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "output1": res_body.get("t8412OutBlock", {}), "output2": res_body.get("t8412OutBlock1", []), } return result
[docs] def get_account_deposit_orderable_total_evaluation(self) -> dict: """ ([주식]계좌) 현물계좌예수금 주문가능금액 총평가 조회 (CSPAQ12200) Returns: dict: 주문가능금액 총평가 정보 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - output1 (dict): 계좌기본정보 - output2 (dict): 주문가능금액 총평가 정보 """ CallLimiter().wait_limit_rate(1, scope="ebest/CSPAQ12200") tr_code = "CSPAQ12200" req_body = {f"{tr_code}InBlock1": {"BalCreTp": "0"}} res_body, _ = self._tr_request("/stock/accno", tr_code, body=req_body) result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "output1": res_body.get("CSPAQ12200OutBlock1", {}), "output2": res_body.get("CSPAQ12200OutBlock2", {}), } return result
[docs] def get_account_orderable_quantity( self, bns_tp_code: int, isu_no: str, ord_prc: int, ) -> dict: """ ([주식]계좌) 현물계좌증거금률별주문가능수량조회 (CSPBQ00200) Args: bns_tp_code (int): 매매구분 (1:매도 2:매수) isu_no (str): 종목번호 ord_prc (int): 주문가격 Returns: dict: 주문가능수량 정보 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - output1 (dict): 요청 정보 - output2 (dict): 계좌 및 증거금률 별 주문가능수량 정보 """ CallLimiter().wait_limit_rate(1, scope="ebest/CSPBQ00200") assert bns_tp_code in [1, 2], "Invalid bns_tp_code" assert len(isu_no) == 6 or (len(isu_no) == 7 and isu_no[0] == "A"), "Invalid isu_no" tr_code = "CSPBQ00200" req_body = { f"{tr_code}InBlock1": { "BnsTpCode": str(bns_tp_code), "IsuNo": "A" + isu_no if len(isu_no) == 6 else isu_no, "OrdPrc": ord_prc, } } res_body, _ = self._tr_request("/stock/accno", tr_code, body=req_body) result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "output1": res_body.get("CSPBQ00200OutBlock1", {}), "output2": res_body.get("CSPBQ00200OutBlock2", {}), } return result
[docs] def get_stock_balance( self, prcgb: int = 1, chegb: int = 0, dangb: int = 0, charge: int = 0, cts_expcode: str = "", tr_cont_key: str = "", ): """ ([주식]계좌) 주식잔고2조회 (t0424) Args: prcgb (int): 단가구분 (1:평균단가, 2:BEP단가) chegb (int): 체결구분 (0:결제기준잔고, 2:체결기준(잔고가 0이 아닌 종목만 조회) dangb (int): 단일가구분 (0:정규장, 1:시장외단일가) charge (int): 수수료구분 (0:제비용미포함, 1:제비용포함) cts_expcode (str): 연속종목코드 - 연속조회시 OutBlock의 동일필드 입력 Returns: dict: 주식 잔고 정보 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - tr_cont (str): 연속조회여부 - tr_cont_key (str): 연속조회키 - output1 (dict): 계좌 정보 - output2 (list): 종목 별 잔고 정보 """ CallLimiter().wait_limit_rate(1, scope="ebest/t0424") assert prcgb in [1, 2], "Invalid prcgb" assert chegb in [0, 2], "Invalid chegb" assert dangb in [0, 1], "Invalid dangb" assert charge in [0, 1], "Invalid charge" tr_code = "t0424" tr_cont = "Y" if cts_expcode else "N" req_body = { f"{tr_code}InBlock": { "prcgb": str(prcgb), "chegb": str(chegb), "dangb": str(dangb), "charge": str(charge), "cts_expcode": cts_expcode, } } res_body, res_header = self._tr_request( "/stock/accno", tr_code, tr_cont=tr_cont, tr_cont_key=tr_cont_key, body=req_body, ) result = { "tr_cont": res_header.get("tr_cont", ""), "tr_cont_key": res_header.get("tr_cont_key", ""), "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "output1": res_body.get("t0424OutBlock", []), "output2": res_body.get("t0424OutBlock1", []), } return result
def get_today_pnl_and_trades( self, tr_cont: str = "N", tr_cont_key: str = "", cts_medosu: str = "", cts_expcode: str = "", cts_price: str = "", cts_middiv: str = "", ) -> dict: """ ([주식]계좌) 주식당일실현손익/체결내역조회 (t0150) Args: tr_cont (str): 연속조회여부 tr_cont_key (str): 연속조회키 cts_medosu (str): 연속매도수구분 - 연속조회시 OutBlock의 동일필드 입력 cts_expcode (str): 연속종목코드 - 연속조회시 OutBlock의 동일필드 입력 cts_price (str): 연속가격 - 연속조회시 OutBlock의 동일필드 입력 cts_middiv (str): 연속미체결구분 - 연속조회시 OutBlock의 동일필드 입력 Returns: dict: 주식 당일 실현손익/체결 내역 정보 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - tr_cont (str): 연속조회여부 - tr_cont_key (str): 연속조회키 - output1 (dict): 당일 실현손익 정보 - output2 (list): 종목별 정보 """ CallLimiter().wait_limit_rate(2, scope="ebest/t0150") tr_code = "t0150" req_body = { f"{tr_code}InBlock": { "cts_medosu": cts_medosu, "cts_expcode": cts_expcode, "cts_price": cts_price, "cts_middiv": cts_middiv, } } res_body, res_header = self._tr_request( "/stock/accno", tr_code, tr_cont=tr_cont, tr_cont_key=tr_cont_key, body=req_body, ) result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "tr_cont": res_header.get("tr_cont", ""), "tr_cont_key": res_header.get("tr_cont_key", ""), "output1": res_body.get("t0150OutBlock", {}), "output2": res_body.get("t0150OutBlock1", []), } return result
[docs] def get_deposit_order_list( self, isu_no: str = "", ord_mkt_code: str = "00", bns_tp_code: str = "0", exec_yn: str = "0", ord_dt: str = None, srt_ord_no2: str = "999999999", bkseq_tp_code: str = "0", ord_ptn_code: str = "00", ) -> dict: """ ([주식]계좌) 현물계좌 주문체결내역 조회(API) (CSPAQ13700) """ CallLimiter().wait_limit_rate(1, scope="ebest/CSPAQ13700") tr_code = "CSPAQ13700" if ord_dt is None: ord_dt = dtm.date.today().strftime("%Y%m%d") req_body = { f"{tr_code}InBlock1": { "IsuNo": isu_no, "OrdMktCode": ord_mkt_code, "BnsTpCode": bns_tp_code, "ExecYn": exec_yn, "OrdDt": ord_dt, "SrtOrdNo2": int(srt_ord_no2), "BkseqTpCode": bkseq_tp_code, "OrdPtnCode": ord_ptn_code, } } res_body, res_header = self._tr_request("/stock/accno", tr_code, body=req_body) result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "tr_cont": res_header.get("tr_cont", ""), "tr_cont_key": res_header.get("tr_cont_key", ""), "output1": res_body.get("CSPAQ13700OutBlock1", {}), "output2": res_body.get("CSPAQ13700OutBlock2", {}), "output3": res_body.get("CSPAQ13700OutBlock3", {}), } return result
[docs] def get_order_list( self, chegb: int = 0, medosu: int = 0, sortgb: int = 2, expcode: str = "", cts_ordno: str = "", tr_cont_key: str = "", ) -> dict: """ ([주식]계좌) 주식체결/미체결 (t0425) Args: chegb (int): 체결구분 (0:전체, 1:체결, 2:미체결) medosu (int): 매도수구분 (0:전체, 1:매도, 2:매수) sortgb (int): 정렬기준 (1:주문번호 역순, 2:주문번호 순) expcode (str): 종목코드. 전체조회 시 입력값 없음 cts_ordno (str): 연속주문번호 - 연속조회시 OutBlock의 동일필드 입력 tr_cont_key (str): 연속조회키 - 연속조회시 이전 응답 헤더의 동일필드 입력 Returns: dict: 주식 체결/미체결 정보 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - tr_cont (str): 연속조회여부 - tr_cont_key (str): 연속조회키 - output1 (dict): 총 주문/체결 정보 - output2 (list): 주문 별 정보 """ CallLimiter().wait_limit_rate(1, scope="ebest/t0425") tr_code = "t0425" tr_cont = "Y" if cts_ordno else "N" req_body = { f"{tr_code}InBlock": { "chegb": str(chegb), "medosu": str(medosu), "sortgb": str(sortgb), "expcode": expcode, "cts_ordno": cts_ordno, } } res_body, res_header = self._tr_request( "/stock/accno", tr_code, tr_cont=tr_cont, tr_cont_key=tr_cont_key, body=req_body, ) res_body.update( { "tr_cont": res_header.get("tr_cont", ""), "tr_cont_key": res_header.get("tr_cont_key", ""), } ) if "t0425OutBlock" not in res_body: res_body["t0425OutBlock"] = { "tqty": 0, "tcheqty": 0, "tordrem": 0, "cmss": 0, "tamt": 0, "tmdamt": 0, "tmsamt": 0, "tax": 0, "cts_ordno": "", } if "t0425OutBlock1" not in res_body: res_body["t0425OutBlock1"] = [] result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "tr_cont": res_header.get("tr_cont", ""), "tr_cont_key": res_header.get("tr_cont_key", ""), "output1": res_body["t0425OutBlock"], "output2": res_body["t0425OutBlock1"], } return result
[docs] def create_order( self, isu_no: str, ord_qty: int, ord_prc: int, bns_tp_code: int, ord_prc_ptn_code: str, mgntrn_code: str = "000", load_dt: dtm.date = None, ord_cndi_tp_code: int = "0", ) -> dict: """ ([주식]주문) 현물주문 (CSPAT00601) Args: isu_no (str): 종목번호 | 주식/ETF: (종목코드) or A+종목코드 | ELW: J+종목코드 | ETN: Q+종목코드 ord_qty (int): 주문수량 ord_prc (int): 주문가격 bns_tp_code (int): 매매구분 (1:매도 2:매수) ord_prc_ptn_code (str): 호가유형코드 | '00: 지정가 | '03': 시장가 | '05': 조건부지정가 | '06': 최유리지정가 | '07': 최우선지정가 | '61': 장개시전시간외종가 | '81': 시간외단일가매매 | '82': 시간외종가 mgntrn_code (str): 신용거래코드 | '000': 보통 | '003': 유통/자기융자신규 | '005': 유통대주신규 | '007': 자기대주신규 | '101': 유통융자상환 | '103': 자기융자상환 | '105': 유통대주상환 | '107': 자기대주상환 | '180': 유통대주주문취소 load_dt (dtm.date): 대출일 ord_cndi_tp_code (int): 주문조건구분 (0:없음 1:IOC 2:FOK) Returns: dict: 주문 결과 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - output1 (dict): 주문 결과 - output2 (dict): 주문 결과 """ CallLimiter().wait_limit_rate(10, scope="ebest/CSPAT00601") tr_cd = "CSPAT00601" req_body = { f"{tr_cd}InBlock1": { "IsuNo": isu_no, "OrdQty": ord_qty, "OrdPrc": ord_prc, "BnsTpCode": str(bns_tp_code), "OrdprcPtnCode": ord_prc_ptn_code, "MgntrnCode": mgntrn_code, "LoanDt": load_dt.strftime("%Y%m%d") if load_dt else "", "OrdCndiTpCode": str(ord_cndi_tp_code), } } res_body, _ = self._tr_request("/stock/order", tr_cd, body=req_body) result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "output1": res_body.get(f"{tr_cd}OutBlock1", {}), "output2": res_body.get(f"{tr_cd}OutBlock2", {}), } return result
[docs] def update_order( self, org_ord_no: str, isu_no: str, ord_qty: int, ord_prc_ptn_code: str, ord_cndi_tp_code: int = 0, ord_prc: int = 0, ) -> dict: """ ([주식]주문) 현물정정주문 (CSPAT00701) Args: org_ord_no (str): 원주문번호 isu_no (str): 종목번호 ord_qty (int): 주문수량 ord_prc_ptn_code (str): 호가유형코드 | '00: 지정가 | '03': 시장가 | '05': 조건부지정가 | '06': 최유리지정가 | '07': 최우선지정가 | '61': 장개시전시간외종가 | '81': 시간외단일가매매 | '82': 시간외종가 ord_cndi_tp_code (int): 주문조건구분 (0:없음 1:IOC 2:FOK) ord_prc (int): 주문가격 Returns: dict: 주문 결과 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - output1 (dict): 원 주문 정보 - output2 (dict): 정정 주문 정보 """ CallLimiter().wait_limit_rate(3, scope="ebest/CSPAT00701") tr_cd = "CSPAT00701" req_body = { f"{tr_cd}InBlock1": { "OrgOrdNo": int(org_ord_no), "IsuNo": isu_no, "OrdQty": ord_qty, "OrdprcPtnCode": ord_prc_ptn_code, "OrdCndiTpCode": str(ord_cndi_tp_code), "OrdPrc": ord_prc, } } res_body, _ = self._tr_request("/stock/order", tr_cd, body=req_body) result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "output1": res_body.get(f"{tr_cd}OutBlock1", {}), "output2": res_body.get(f"{tr_cd}OutBlock2", {}), } return result
[docs] def cancel_order(self, org_ord_no: str, isu_no: str, ord_qty: int) -> dict: """ ([주식]주문) 현물취소주문 (CSPAT00801) Args: org_ord_no (str): 원주문번호 isu_no (str): 종목번호 ord_qty (int): 주문수량 Returns: dict: 주문 결과 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - output1 (dict): 원 주문 정보 - output2 (dict): 취소 주문 정보 """ CallLimiter().wait_limit_rate(3, scope="ebest/CSPAT00801") tr_cd = "CSPAT00801" req_body = { f"{tr_cd}InBlock1": { "OrgOrdNo": int(org_ord_no), "IsuNo": isu_no, "OrdQty": ord_qty, } } res_body, _ = self._tr_request("/stock/order", tr_cd, body=req_body) result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "output1": res_body.get(f"{tr_cd}OutBlock1", []), "output2": res_body.get(f"{tr_cd}OutBlock2", []), } return result
[docs] def get_management_stocks(self, gubun: str, jongchk: str, cts_shcode: str = "", tr_cont_key: str = ""): """ ([주식]시세) 관리/불성실/투자유의조회 (t1404) Args: gubun (str): 구분 (0:전체 1:코스피 2:코스닥) jongchk (str): 종목체크 (1:관리 2:불성실공시 3:투자유의 4.투자환기) cts_shcode (str): 연속종목코드 - 연속조회시 OutBlock의 동일필드 입력 Returns: dict: 관리/불성실/투자유의 정보 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - tr_cont (str): 연속조회여부 - tr_cont_key (str): 연속조회키 - output1 (dict): 연속조회정보 - output2 (list): 종목 별 정보 """ tr_cd = "t1404" req_body = { f"{tr_cd}InBlock": { "gubun": gubun, "jongchk": jongchk, "cts_shcode": cts_shcode, } } tr_cont = "Y" if cts_shcode else "N" res_body, _ = self._tr_request("/stock/market-data", tr_cd, tr_cont, tr_cont_key, body=req_body) result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "tr_cont": res_body.get("tr_cont", ""), "tr_cont_key": res_body.get("tr_cont_key", ""), "output1": res_body.get("t1404OutBlock", {}), "output2": res_body.get("t1404OutBlock1", []), } return result
[docs] def get_alert_stocks(self, gubun: str, jongchk: str, cts_shcode: str = "", tr_cont_key=""): """ ([주식]시세) 투자경고/매매정지/정리매매조회 (t1405) Args: gubun (str): 구분 (0:전체 1:코스피 2:코스닥) jongchk (str): 종목체크 (1:투자경고 2:매매정지 3:정리매매 4:투자주의 5:투자위험 6:위험예고 7:단기과열지정 8:이상급등종목 9:상장주식수부족) cts_shcode (str): 연속종목코드 - 연속조회시 OutBlock의 동일필드 입력 Returns: dict: 투자경고/매매정지/정리매매 정보 - rsp_cd (str): 응답코드 - rsp_msg (str): 응답메시지 - tr_cont (str): 연속조회여부 - tr_cont_key (str): 연속조회키 - output1 (dict): 연속조회정보 - output2 (list): 종목 별 정보 """ tr_cd = "t1405" req_body = { f"{tr_cd}InBlock": { "gubun": gubun, "jongchk": jongchk, "cts_shcode": cts_shcode, } } tr_cont = "Y" if cts_shcode else "N" res_body, res_header = self._tr_request("/stock/market-data", tr_cd, tr_cont, tr_cont_key, body=req_body) result = { "rsp_cd": res_body["rsp_cd"], "rsp_msg": res_body["rsp_msg"], "tr_cont": res_header.get("tr_cont", ""), "tr_cont_key": res_header.get("tr_cont_key", ""), "output1": res_body.get("t1405OutBlock", {}), "output2": res_body.get("t1405OutBlock1", []), } return result
[docs] async def listen_trade_event( self, market: str, asset_codes: list[str], stop_event: asyncio.Event = None, ) -> AsyncGenerator: """ 체결 이벤트를 수신합니다. 장/전후 시간외 종가 거래에 대한 체결 이벤트를 포함합니다. Args: market (str): 시장 (1:코스피 2:코스닥) asset_codes (list[str]): 종목 코드 리스트 """ assert market in ["1", "2"], "Invalid market" assert isinstance(asset_codes, list), "Invalid asset_codes" assert len(asset_codes) > 0, "Invalid asset_codes" def __on_ask_keep_connection() -> EBestTRWebsocketKeepConnectionStatus: now = dtm.datetime.now() today = now.date() market_schedule = get_market_schedule(today) if market_schedule.full_day_closed: return EBestTRWebsocketKeepConnectionStatus.CLOSE open_time = dtm.datetime.combine(today, market_schedule.open_time) close_time = dtm.datetime.combine(today, market_schedule.close_time) # 장전 시강외종가 거래 시작 시간 pre_market_open_time = open_time - dtm.timedelta(minutes=30) # 장후 시간외종가 거래 종료 시간 after_market_close_time = close_time + dtm.timedelta(minutes=30) time_margin = dtm.timedelta(minutes=5) if now < pre_market_open_time - time_margin: return EBestTRWebsocketKeepConnectionStatus.WAIT if now > after_market_close_time + time_margin: return EBestTRWebsocketKeepConnectionStatus.CLOSE return EBestTRWebsocketKeepConnectionStatus.KEEP async def __on_connect(ws: websockets.WebSocketClientProtocol): for asset_code in asset_codes: await ws.send( json.dumps( { "header": { "token": self.auth.get_token(), "tr_type": "3", }, "body": { "tr_cd": "S3_" if market == "1" else "K3_", "tr_key": asset_code, }, } ) ) await asyncio.sleep(0.01) client = EBestTRWebsocketClient( self.auth, on_connect=__on_connect, on_ask_keep_connection=__on_ask_keep_connection, stop_event=stop_event, ) async for data in client.listen(): yield data
[docs] async def listen_after_market_single_price_trade_event( self, market: str, asset_codes: list[str], stop_event: asyncio.Event = None, ): """ 시간외단일가 체결 이벤트를 수신합니다. 장 종료 30분 후부터 2시간 동안 시간외단일가 거래가 이루어집니다. (일반적으로 16:00~18:00) Args: market (str): 시장 (1:코스피 2:코스닥) asset_codes (list[str]): 종목 코드 리스트 """ assert market in ["1", "2"], "Invalid market" assert isinstance(asset_codes, list), "Invalid asset_codes" assert len(asset_codes) > 0, "Invalid asset_codes" def __on_ask_keep_connection() -> EBestTRWebsocketKeepConnectionStatus: now = dtm.datetime.now() today = now.date() market_schedule = get_market_schedule(today) if market_schedule.full_day_closed: return EBestTRWebsocketKeepConnectionStatus.CLOSE close_time = dtm.datetime.combine(today, market_schedule.close_time) # 장후 시간외 단일가 거래 시작 시간 after_market_open_time = close_time + dtm.timedelta(minutes=30) # 장후 시간외 단일가 거래 종료 시간 after_market_close_time = close_time + dtm.timedelta(hours=2, minutes=30) time_margin = dtm.timedelta(minutes=5) if now < after_market_open_time - time_margin: return EBestTRWebsocketKeepConnectionStatus.WAIT if now > after_market_close_time + time_margin: return EBestTRWebsocketKeepConnectionStatus.CLOSE return EBestTRWebsocketKeepConnectionStatus.KEEP async def __on_connect(ws: websockets.WebSocketClientProtocol): for asset_code in asset_codes: await ws.send( json.dumps( { "header": { "token": self.auth.get_token(), "tr_type": "3", }, "body": { "tr_cd": "DS3" if market == "1" else "DK3", "tr_key": asset_code, }, } ) ) await asyncio.sleep(0.01) client = EBestTRWebsocketClient( self.auth, on_connect=__on_connect, on_ask_keep_connection=__on_ask_keep_connection, stop_event=stop_event, ) async for data in client.listen(): yield data
[docs] async def listen_orderbook_event( self, market: str, asset_codes: list[str], stop_event: asyncio.Event = None, ) -> AsyncGenerator: """ 호가잔량 이벤트를 수신합니다. Args: market (str): 시장 (1:코스피 2:코스닥) asset_codes (list[str]): 종목 코드 리스트 """ assert market in ["1", "2"], "Invalid market" assert isinstance(asset_codes, list), "Invalid asset_codes" assert len(asset_codes) > 0, "Invalid asset_codes" def __on_ask_keep_connection() -> EBestTRWebsocketKeepConnectionStatus: now = dtm.datetime.now() today = now.date() market_schedule = get_market_schedule(today) if market_schedule.full_day_closed: return EBestTRWebsocketKeepConnectionStatus.CLOSE open_time = dtm.datetime.combine(today, market_schedule.open_time) close_time = dtm.datetime.combine(today, market_schedule.close_time) # 장전 시강외종가 거래 시작 시간 pre_market_open_time = open_time - dtm.timedelta(minutes=30) # 장후 시간외종가 거래 종료 시간 after_market_close_time = close_time + dtm.timedelta(minutes=30) time_margin = dtm.timedelta(minutes=5) if now < pre_market_open_time - time_margin: return EBestTRWebsocketKeepConnectionStatus.WAIT if now > after_market_close_time + time_margin: return EBestTRWebsocketKeepConnectionStatus.CLOSE return EBestTRWebsocketKeepConnectionStatus.KEEP async def __on_connect(ws: websockets.WebSocketClientProtocol): for asset_code in asset_codes: await ws.send( json.dumps( { "header": { "token": self.auth.get_token(), "tr_type": "3", }, "body": { "tr_cd": "H1_" if market == "1" else "HA_", "tr_key": asset_code, }, } ) ) await asyncio.sleep(0.01) client = EBestTRWebsocketClient( self.auth, on_connect=__on_connect, on_ask_keep_connection=__on_ask_keep_connection, stop_event=stop_event, ) async for data in client.listen(): yield data
[docs] async def listen_order_event(self, stop_event: asyncio.Event) -> AsyncGenerator: """ 주식 주문 이벤트를 실시간으로 수신하고 처리하는 비동기 제너레이터 함수입니다. 이 함수는 지정된 이벤트를 사용하여 웹소켓 연결을 통해 주문 이벤트를 실시간으로 수신합니다. 수신된 이벤트 데이터는 이벤트 유형에 따라 매핑된 값과 함께 반환됩니다. 이 함수는 비동기적으로 동작하며, 이벤트 데이터는 제너레이터를 통해 소비할 수 있습니다. Args: stop_event (asyncio.Event): 이벤트 리스닝을 중지하기 위한 asyncio 이벤트. Yields: dict: 주문에 관한 상세 정보를 포함하는 사전형 데이터. 각 키는 다음과 같습니다: - event_type (string): 이벤트 유형 - accepted:접수, executed:체결, updated:정정, canceled:취소, denied:거부. - accno (string): Push 키. - accno1 (string): 계좌번호 1. - accno2 (string): 계좌번호 2. - acntnm (string): 계좌명. - admbrchno (string): 관리지점번호 - agrgbrnno (string): 집계 지점 번호. - avrpchsprc (string): 평균매입가 - 실서버 데이터 미제공 필드 - avrpchsprc (string): 평균 매입 가격. - basketno (string): 바스켓번호 - bnstp (string): 매매구분 - 1:매도, 2:매수 - bpno (string): 지점 번호. - brwmgmyn (string): 차입구분 - cmsnamtexecamt (string): 수수료 체결 금액. - comid (string): COM ID. - compid (string): 이용사 번호. - compress (string): 압축 구분. - cont (string): 연속 구분. - contkey (string): 연속 키. - crdayruseexecval (string): 금일 재사용 체결 금액. - crdtexecamt (string): 신용 체결 금액. - crdtpldgruseamt (string): 신용담보재사용금 - crdtuseamt (string): 사용신용담보재사용금 - csgnmnymgn (string): 위탁증거금현금 - csgnsubstmgn (string): 위탁증거금대용 - cvrgordtp (string): 반대매매주문구분 - 0:일반 1:자동반대매매 2:지점반대매매 3:예비주문에대한 본주문 - cvrgseqno (string): 반대매매일련번호 - deposit (string): 예수금 - dummy (string): DUMMY - encrypt (string): 암호 구분. - etfhogagb (string): 호가유형코드 - 0:없음 1:IOC 2:FOK 00:지정가 03:시장가 05:조건부지정가 06:최유리지정가 07:최우선지정가 09:자사주 10:매입인도(일반) 13:시장가 (IOC) 16:최유리지정가 (IOC) 18:사용안함 20:지정가(임의) 23:시장가(임의) 26:최유리지정가 (FOK) 41:부분충족(프리보드) 42:전량충족(프리보드) 51:장중대량 52:장중바스켓 61:장개시전시간외 62:사용안함 63:경매매 66:장전시간외경쟁대량 67:장개시전시간외대량 68:장개시전시간외바스켓 69:장개시전시간외자사주 71:신고대량전장시가 72:사용안함 73:신고대량종가 76:장중경쟁대량 77:장중대량 78:장중바스켓 79:사용안함 80:매입인도(당일) 81:시간외종가 82:시간외단일가 87:시간외대량 88:바스켓주문 89:시간외자사주 91:자사주스톡옵션 A1:stop order - eventid (string): I/F이벤트ID - execno (string): 체결 번호. - execprc (string): 체결 가격. - exectime (string): 체결 시각. - filler (string): 예비영역 - fillter1 (string): 예비영역 - flctqty (string): 변동수량 - frgrunqno (string): 외국인 고유 번호. - funckey (string): 기능 키 - futaccno (string): 선물계좌번호 - futmarketgb (string): 선물상품구분 - futsmkttp (string): 선물 시장 구분. - gmhogagb (string): 공매도호가구분 - 0:일반, 1:차입주식매도, 2:기타공매도 - gmhogayn (string): 공매도가능여부 - 0:일반, 1:공매도 - groupid (string): 그룹ID - grpId (string): 그룹 ID. - gubun (string): 헤더 구분. - hname (string): 종목명 - hogagb (string): 주문조건 - 0:없음 1:IOC 2:FOK - ifid (string): I/F 일련 번호. - ifinfo (string): I/F 정보 - Isunm (string): 종목명. - Isuno (string): 종목 번호. - itemno (string): 아이템번호 - lang (string): 언어 구분 - len (string): 헤더 길이. - lineseq (string): 라인 일련 번호. - Loandt (string): 대출일. - lpgb (string): 유동성공급자구분 - 0:해당없음, 1:유동성공급자 - lptp (string): 유동성 공급자 구분. - marketgb (string): 시장 구분 - 00:비상장 10:코스피 11:채권 19:장외시장 20:코스닥 23:코넥스 30:프리보드 61:동경거래소 62:JASDAQ - mbrno (string): 회원사번호 - mdfycnfprc (string): 정정 확인 가격. - mdfycnfqty (string): 정정 확인 수량. - media (string): 접속 매체. - mgempno (string): 관리사원번호 - mgmtbrnno (string): 관리 지점 번호. - mgntrncode (string): 신용거래코드 - [신규] 000:보통 001:유통융자신규 003:자기융자신규 005:유통대주신규 007:자기대주신규 080:예탁주식담보융자신규 082:예탁채권담보융자신규 [상환] 101:유통융자상환 103:자기융자상환 105:유통대주상환 107:자기대주상환 111:유통융자전액상환 113:자기융자전액상환 180:예탁주식담보융자상환 182:예탁채권담보융자상환 188:담보대출전액상환 - mnymgnrat (string): 현금 증거금률. - mnyordamt (string): 현금주문금액 - msgcode (string): 메세지 코드 - mtordseqno (string): 복수주문일련번호 - nmcpysndno (string): 비회원사송신번호 - offset (string): 공통 시작 지점. - opdrtnno (string): 운용 지시 번호. - ordablemny (string): 주문가능현금 - ordableruseqty (string): 재사용가능수량(매도) - 실서버 데이터 미제공 필드 - ordablesubstamt (string): 주문가능대용 - ordablesubstamt (string): 주문 가능 대용. - ordacntno (string): 주문 계좌 번호. - ordamt (string): 주문금액 - ordchegb (string): 주문 체결 구분 - 01:주문 02:정정 03:취소 11:체결 12:정정확인 13:취소확인 14:거부 A1:접수중 AC:접수완료 - ordcmsnamt (string): 수수료주문금액 - ordgb (string): 주문 구분 - 01:현금매도 02:현금매수 03:신용매도 04:신용매수 05:저축매도 06:저축매수 07:상품매도(대차) 09:상품매도 10:상품매수 11:선물대용매도(일반) 12:선물대용매도(반대) 13:현금매도(프) 14:현금매수(프) 15:현금매수(유가) 16:현금매수(정리) 17:상품매도(대차.프) 19:상품매도(프) 20:상품매수(프) 30:장외매매 - ordmktcode (string): 주문 시장 코드. - ordno (string): 주문번호 - ordordcancelqty (string): 원주문취소수량 - ordprc (string): 주문 가격. - ordprcptncode (string): 호가 유형 코드 - 00:지정가 03:시장가 05:조건부지정가 06:최유리지정가 07:최우선지정가 09:자사주 10:매입인도(일반) 13:시장가 (IOC) 16:최유리지정가 (IOC) 18:사용안함 20:지정가(임의) 23:시장가(임의) 26:최유리지정가 (FOK) 41:부분충족(프리보드) 42:전량충족(프리보드) 51:장중대량 52:장중바스켓 61:장개시전시간외 62:사용안함 63:경매매 66:장전시간외경쟁대량 67:장개시전시간외대량 68:장개시전시간외바스켓 69:장개시전시간외자사주 71:신고대량전장시가 72:사용안함 73:신고대량종가 76:장중경쟁대량 77:장중대량 78:장중바스켓 79:사용안함 80:매입인도(당일) 81:시간외종가 82:시간외단일가 87:시간외대량 88:바스켓주문 89:시간외자사주 91:자사주스톡옵션 A1:stop order - ordprice (string): 주문 가격 - ordptncode (string): 주문 유형 코드 - 00 해당없음 01:현금매도 02:현금매수 03신용매도 04:신용매수 - ordqty (string): 주문수량 - ordruseqty (string): 재사용주문수량 - ordseqno (string): 주문회차 - ordsubstamt (string): 주문대용금액 - ordtm (string): 주문시각 - ordtrdptncode (string): 주문 거래 유형 코드 - 00:위탁 01:신용 04:선물대용 - ordtrxptncode (string): 주문 처리 유형 코드 - orduserId (string): 주문자 ID. - ordxctptncode (string): 주문 체결 유형 코드 - 01:주문 02:정정 03:취소 11:체결 12:정정확인 13:취소확인 14:거부 - orgordcancqty (string): 원주문 취소 수량. - orgordmdfyqty (string): 원주문 정정 수량 - orgordundrqty (string): 원주문 미체결 수량 - outgu (string): 메세지출력구분 - pcbpno (string): 처리 지점 번호. - pchsamt (string): 매입금액 - 실서버 데이터 미제공 필드 - pgmtype (string): 프로그램호가구분 - 00:일반 01:지수차익 02:지수비차익 03:주식차익 04:ETF차익(비차익제외) 05:ETF설정(비차익제외) 06:ETF차익(비차익) 07:ETF설정(비차익) 08:DR차익 09:ELW LP헷지 10:ETF LP헷지 11:주식옵션 LP헷지 12:장외파생상품헷지 - prdayruseexecval (string): 전일 재사용 체결 금액. - prntordno (string): 모주문번호 - procgb (string): 처리구분 - proctm (string): 처리 시각. - prtno (string): 포트폴리오번호 - prvip (string): 사설 IP. - pubip (string): 공인 IP. - regmktcode (string): 등록 시장 코드. - reqcnt (string): 요청 레코드 개수. - rjtqty (string): 거부 수량. - rsvordno (string): 예약주문번호 - ruseableamt (string): 재사용 가능 금액. - ruseordamt (string): 재사용주문금액 - secbalqty (string): 잔고수량 - 실서버 데이터 미제공 필드 - secbalqtyd2 (string): 잔고수량(D2) - 실서버 데이터 미제공 필드 - sellableqty (string): 매도주문가능수량 - 실서버 데이터 미제공 필드 - seq (string): 전문 일련 번호. - shtcode (string): 단축종목번호. - shtnIsuno (string): 단축 종목 번호. - singb (string): 신용구분 - 000:보통, 001:유통융자신규, 003:자기융자신규, 005:유통대주신규, 007:자기대주신규, 011:미사용, 070:매도대금담보융자신규, 080:예탁주식담보융자신규, 082:예탁채권담보융자신규, 101:유통융자상환, 103:자기융자상환, 105:유통대주상환, 107:자기대주상환, 111:유통융자전액상환, 113:자기융자전액상환, 170:매도대금담보융자상환, 180:예탁주식담보융자상환, 182:예탁채권담보융자상환, 188:담보대출전액상환, 201:유통융자현금상환, 203:자기융자현금상환, 205:유통대주현물상환, 207:자기대주현물상환, 280:예탁주식담보융자현금상환, 282:예탁채권담보융자현금상환, 301:유통융자현금상환취소, 303:자기융자현금상환취소, 305:유통대주현물상환취소, 307:자기대주현물상환취소 - spareordno (string): 예비주문번호 - spareordqty (string): 예비주문수량 - spotordableqty (string): 실물가능수량 - 실서버 데이터 미제공 필드 - spotordqty (string): 실물주문수량 - strtgcode (string): 전략코드 - substamt (string): 대용금 - termno (string): 단말번호 - tongsingb (string): 통신매체구분 - trchno (string): 트렌치 번호. - trcode (string): TR 코드. SONAT000: 신규 주문, SONAT001: 정정 주문, SONAT002: 취소 주문, SONAS100: 체결 확인. - trid (string): TR 추적 ID. - trsrc (string): 조회 발원지. - trtzxLevytp (string): 거래세 징수 구분. - unercsellordqty (string): 미체결매도주문수량 - 실서버 데이터 미제공 필드 - user (string): 조작자 ID. - userid (string): 사용자 ID. - varhdlen (string): 가변 헤더 길이. - varlen (string): 가변 시스템 길이. - varmsglen (string): 가변 메시지 길이. Examples: >>> async for order_event in listen_order_event(stop_event): >>> print(order_event) {'event_type': 'accepted', 'trchno': '0', 'spareordqty': '0', 'trcode': 'SONAT000', 'userid': '<your-user-id>', 'dummy': '', 'len': '1053', 'loandt': '00000000', 'orgordmdfyqty': '0', 'avrpchsprc': '.00', 'cont': 'N', 'hname': 'TIGER 미국S&P500', 'pgmtype': '0', 'compress': '0', 'ordprice': '18015', 'procgb': '0', 'unercsellordqty': '0', 'ruseableamt': '0', 'ordgb': '02', 'gubun': 'B', 'trid': 'C000152253562059', 'flctqty': '0', 'varmsglen': '0', 'ordno': '150151', 'passwd': '********', 'singb': '000', 'gmhogayn': '0', 'ordruseqty': '0', 'deposit': '1015853', 'trsrc': 'Z', 'gmhogagb': '0', 'reqcnt': ' ', 'accno1': '<your-acc-no>', 'strtgcode': '', 'ordchegb': '01', 'ordtm': '152253562', 'orduserid': '<your-user-id>', 'ordseqno': '0', 'ordablesubstamt': '1139350', 'pchsamt': '0', 'encrypt': '0', 'accno2': '', 'shtcode': 'A360750', 'contkey': '', 'brwmgmyn': '0', 'seq': '000000103', 'mtordseqno': '0', 'lineseq': '1300076459', 'tongsingb': '51', 'varlen': '50', 'lpgb': '0', 'rsvordno': '0', 'spotordqty': '0', 'cvrgseqno': '0', 'filler': '', 'hogagb': '0', 'secbalqty': '0', 'expcode': 'KR7360750004', 'prntordno': '150151', 'ordablemny': '961813', 'pubip': 'D180A4DE36E6', 'prvip': 'D180A4DE36E6', 'funckey': 'C', 'accno': '<your-acc-no>', 'compreq': '0', 'orgordundrqty': '0', 'ruseordamt': '0', 'crdtpldgruseamt': ' ', 'ordordcancelqty': '0', 'ordamt': '18015', 'spareordno': '0', 'termno': '', 'etfhogagb': '00', 'bpno': '202', 'substamt': '1139350', 'mgempno': '999999202', 'csgnsubstmgn': '0', 'offset': '212', 'sellableqty': '0', 'groupid': '', 'varhdlen': '0', 'mnyordamt': '18015', 'itemno': '0', 'prtno': '0', 'marketgb': '10', 'ifinfo': '', 'ordableruseqty': '0', 'crdtuseamt': '0', 'ordcmsnamt': '0', 'secbalqtyd2': '0', 'eventid': '', 'csgnmnymgn': '54040', 'pcbpno': '000', 'orgordno': '0', 'basketno': '0', 'ifid': '000', 'media': 'HT', 'filler1': '', 'mbrno': '63', 'proctm': '152253562', 'ordsubstamt': '0', 'lang': 'K', 'spotordableqty': '0', 'cvrgordtp': '0', 'ordqty': '1', 'outgu': '', 'msgcode': '0040', 'futaccno': '00000000000000000000', 'futmarketgb': '0', 'admbrchno': '202', 'comid': '063', 'bnstp': '2', 'user': '<your-user-id>', 'nmcpysndno': '0'} {'event_type': 'executed', 'grpId': 'A4000000000000000000', 'trchno': '0', 'trtzxLevytp': '1', 'ordtrxptncode': '0', 'acntnm': '<your-name>', 'trcode': 'SONAS100', 'userid': '<your-user-id>', 'agrgbrnno': '202', 'regmktcode': '10', 'len': '1294', 'opdrtnno': '', 'orgordmdfyqty': '0', 'avrpchsprc': '0', 'exectime': '153022964', 'cont': 'N', 'mnymgnrat': '1.000', 'mdfycnfqty': '0', 'orgordcancqty': '0', 'compress': '0', 'execprc': '18020', 'mdfycnfprc': '0', 'unercsellordqty': '0', 'cmsnamtexecamt': '0', 'ruseableamt': '0', 'gubun': 'B', 'trid': 'C000152305251008', 'flctqty': '1', 'execno': '36110', 'lptp': '0', 'varmsglen': '0', 'ordno': '150162', 'futsmkttp': '', 'crdtexecamt': '0', 'deposit': '1015853', 'frgrunqno': '000000', 'crdayruseexecval': '0', 'trsrc': 'Z', 'ordacntno': '<your-acc-no>', 'reqcnt': ' ', 'shtnIsuno': 'A360750', 'accno1': '<your-acc-no>', 'strtgcode': '', 'ordseqno': '0', 'Isunm': 'TIGER 미국S&P500', 'ordablesubstamt': '1139350', 'encrypt': '0', 'Isuno': 'KR7360750004', 'accno2': '', 'contkey': '', 'Loandt': '00000000', 'seq': '000000112', 'lineseq': '1300076856', 'varlen': '50', 'orduserId': '<your-user-id>', 'mgmtbrnno': '202', 'rjtqty': '0', 'ordprcptncode': '03', 'stdIsuno': 'KR7360750004', 'pchsant': '0', 'filler': '', 'secbalqty': '0', 'ordxctptncode': '11', 'canccnfqty': '0', 'ordablemny': '961808', 'pubip': 'D180A4DE36E6', 'prvip': 'D180A4DE36E6', 'funckey': 'C', 'accno': '<your-acc-no>', 'compreq': '0', 'crdtpldgruseamt': '0', 'ordamt': '0', 'termno': '', 'crdtpldgexecamt': '0', 'ordcndi': '0', 'rmndLoanamt': '0', 'bpno': '202', 'substamt': '1139350', 'mgempno': '999999202', 'csgnsubstmgn': '0', 'offset': '212', 'rcptexectime': '153022954', 'sellableqty': '0', 'spotexecqty': '0', 'varhdlen': '0', 'substmgnrat': '.0000000', 'ordavrexecprc': '18020', 'itemno': '0', 'mgntrncode': '000', 'nsavtrdqty': '0', 'ifinfo': '', 'ordableruseqty': '0', 'ptflno': '0', 'secbalqtyd2': '0', 'brwmgmtYn': '0', 'eventid': '', 'csgnmnymgn': '54045', 'pcbpno': '000', 'orgordno': '0', 'ifid': '000', 'media': 'HT', 'mtiordseqno': '0', 'filler1': '', 'orgordunercqty': '0', 'mbrnmbrno': '0', 'futsLnkbrnno': '', 'commdacode': '51', 'stslexecqty': '0', 'proctm': '153022964', 'bfstdIsuno': 'KR7360750004', 'futsLnkacntno': '', 'lang': 'K', 'unercqty': '0', 'execqty': '1', 'adduptp': '51', 'bskno': '0', 'spotordableqty': '0', 'ubstexecamt': '0', 'cvrgordtp': '0', 'ordqty': '1', 'mnyexecamt': '18020', 'outgu': '', 'msgcode': '9999', 'ordtrdptncode': '00', 'ordmktcode': '10', 'ordptncode': '02', 'prdayruseexecval': '0', 'comid': '063', 'bnstp': '2', 'user': '<your-user-id>', 'ordprc': '0'} Note: 이 함수는 비동기 I/O를 사용하므로 async for 문을 사용하여 이벤트를 소비해야 합니다. """ def __on_ask_keep_connection() -> EBestTRWebsocketKeepConnectionStatus: return EBestTRWebsocketKeepConnectionStatus.KEEP async def __on_connect(ws: websockets.WebSocketClientProtocol): tr_codes = [f"SC{i}" for i in range(5)] for tr_code in tr_codes: await ws.send( json.dumps( { "header": { "token": self.auth.get_token(), "tr_type": "1", }, "body": { "tr_cd": tr_code, }, } ) ) await asyncio.sleep(0.01) client = EBestTRWebsocketClient( self.auth, on_connect=__on_connect, on_ask_keep_connection=__on_ask_keep_connection, stop_event=stop_event, ) event_type_map = { "SC0": "accepted", "SC1": "executed", "SC2": "updated", "SC3": "cancelled", "SC5": "denied", } async for data in client.listen(): new_data = { "event_type": event_type_map[data["header"]["tr_cd"]], **data["body"], } yield new_data
async def listen_upper_under_limit_enter_event( self, stop_event: asyncio.Event = None, ) -> AsyncGenerator: """ 상 하한가 진입 이벤트를 실시간으로 수신하고 처리하는 비동기 제너레이터 함수입니다. 이 함수는 비동기적으로 동작하며, 이벤트 데이터는 제너레이터를 통해 소비할 수 있습니다. Args: stop_event (asyncio.Event): 이벤트 리스닝을 중지하기 위한 asyncio 이벤트. Yields: dict: 상한가 진입에 관한 상세 정보를 포함하는 사전형 데이터. 각 키는 다음과 같습니다: - sijanggubun (string): 거래소. 1:코스피 2:코스닥 - hname (string): 종목명 - shcode (string): 단축코드 - price (string): 현재가 - change (string): 전일대비 가격변화 - sign (string): 전일대비 구분. 1:상한가 - drate (string): 등락율 - volume (string): 누적거래량 - volincrate (string): 거래증가율 - totofferrem (string): 매도호가총수량 - totbidrem (string): 매수호가총수량 - updnlmtstime (string): 상한가/하한가최종진입시간 - updnlmtdaycnt (string): 상한가/하한가연속일수 - jnilvolume (string): 전일거래량 - gwangubun (string): 관리종목구분 - undergubun (string): 이상급등구분 - tgubun (string): 투자유의구분 - wgubun (string): 우선주구분 - dishonest (string): 불성실공시구분 - jkrate (string): 증거금률 """ def __on_ask_keep_connection() -> EBestTRWebsocketKeepConnectionStatus: now = dtm.datetime.now() today = now.date() market_schedule = get_market_schedule(today) if market_schedule.full_day_closed: return EBestTRWebsocketKeepConnectionStatus.CLOSE open_time = dtm.datetime.combine(today, market_schedule.open_time) close_time = dtm.datetime.combine(today, market_schedule.close_time) # 장전 시간외종가 거래 시작 시간 pre_market_open_time = open_time - dtm.timedelta(minutes=30) # 장후 시간외종가 거래 종료 시간 after_market_close_time = close_time + dtm.timedelta(minutes=30) time_margin = dtm.timedelta(minutes=5) if now < pre_market_open_time - time_margin: return EBestTRWebsocketKeepConnectionStatus.WAIT if now > after_market_close_time + time_margin: return EBestTRWebsocketKeepConnectionStatus.CLOSE return EBestTRWebsocketKeepConnectionStatus.KEEP async def __on_connect(ws: websockets.WebSocketClientProtocol): for asset_code in asset_codes: await ws.send( json.dumps( { "header": { "token": self.auth.get_token(), "tr_type": "3", }, "body": { "tr_cd": "SHI", }, } ) ) await asyncio.sleep(0.01) client = EBestTRWebsocketClient( self.auth, on_connect=__on_connect, on_ask_keep_connection=__on_ask_keep_connection, stop_event=stop_event, ) async for data in client.listen(): yield data async def listen_upper_under_limit_release_event( self, stop_event: asyncio.Event = None, ) -> AsyncGenerator: """ 상 하한가 이탈 이벤트를 실시간으로 수신하고 처리하는 비동기 제너레이터 함수입니다. 이 함수는 비동기적으로 동작하며, 이벤트 데이터는 제너레이터를 통해 소비할 수 있습니다. Args: stop_event (asyncio.Event): 이벤트 리스닝을 중지하기 위한 asyncio 이벤트. Yields: dict: 상한가 진입에 관한 상세 정보를 포함하는 사전형 데이터. 각 키는 다음과 같습니다: - sijanggubun (string): 거래소. 1:코스피 2:코스닥 - hname (string): 종목명 - shcode (string): 단축코드 - price (string): 현재가 - change (string): 전일대비 가격변화 - sign (string): 전일대비 구분. 1:상한가 - drate (string): 등락율 - volume (string): 누적거래량 - volincrate (string): 거래증가율 - totofferrem (string): 매도호가총수량 - totbidrem (string): 매수호가총수량 - updnlmtstime (string): 상한가/하한가최종진입시간 - updnlmtdaycnt (string): 상한가/하한가연속일수 - jnilvolume (string): 전일거래량 - gwangubun (string): 관리종목구분 - undergubun (string): 이상급등구분 - tgubun (string): 투자유의구분 - wgubun (string): 우선주구분 - dishonest (string): 불성실공시구분 - jkrate (string): 증거금률 """ def __on_ask_keep_connection() -> EBestTRWebsocketKeepConnectionStatus: now = dtm.datetime.now() today = now.date() market_schedule = get_market_schedule(today) if market_schedule.full_day_closed: return EBestTRWebsocketKeepConnectionStatus.CLOSE open_time = dtm.datetime.combine(today, market_schedule.open_time) close_time = dtm.datetime.combine(today, market_schedule.close_time) # 장전 시간외종가 거래 시작 시간 pre_market_open_time = open_time - dtm.timedelta(minutes=30) # 장후 시간외종가 거래 종료 시간 after_market_close_time = close_time + dtm.timedelta(minutes=30) time_margin = dtm.timedelta(minutes=5) if now < pre_market_open_time - time_margin: return EBestTRWebsocketKeepConnectionStatus.WAIT if now > after_market_close_time + time_margin: return EBestTRWebsocketKeepConnectionStatus.CLOSE return EBestTRWebsocketKeepConnectionStatus.KEEP async def __on_connect(ws: websockets.WebSocketClientProtocol): for asset_code in asset_codes: await ws.send( json.dumps( { "header": { "token": self.auth.get_token(), "tr_type": "3", }, "body": { "tr_cd": "SHO", }, } ) ) await asyncio.sleep(0.01) client = EBestTRWebsocketClient( self.auth, on_connect=__on_connect, on_ask_keep_connection=__on_ask_keep_connection, stop_event=stop_event, ) async for data in client.listen(): yield data