import datetime as dtm
from decimal import Decimal
from pyqqq.brokerage.kis.oauth import KISAuth
from pyqqq.brokerage.kis.tr_client import KISTRClient
BALANCE_STR_KEYS = ["cano", "acnt_prdt_cd", "pdno", "prdt_type_cd", "shtn_pdno", "prdt_name", "sll_buy_dvsn_name"]
BALANCE_DECIMAL_KEYS = ["excc_unpr", "ccld_avg_unpr1", "idx_clpr"]
SETTLEMENT_STR_KEYS = ["pdno", "prdt_name", "trad_dvsn_name"]
DAILY_AMOUNT_FEE_STR_KEYS = ["pdno", "item_name"]
DAILY_AMOUNT_FEE_DATE_KEYS = ["ord_dt"]
CCNL_STR_KEYS = [
"ord_gno_brno",
"cano",
"csac_name",
"acnt_prdt_cd",
"odno",
"orgn_odno",
"sll_buy_dvsn_cd",
"trad_dvsn_name",
"nmpr_type_cd",
"nmpr_type_name",
"pdno",
"prdt_name",
"prdt_type_cd",
"ingr_trad_rjct_rson_cd",
"ingr_trad_rjct_rson_name",
"ord_stfno",
"sprd_item_yn",
"ord_ip_addr",
"ctac_tlno",
]
CCNL_DECIMAL_KEYS = ["ord_idx", "avg_idx"]
NGT_CCNL_DECIMAL_KEYS = ["ord_idx4", "avg_idx"]
CCNL_DATE_KEYS = ["ord_dt"]
CCNL_TIME_KEYS = ["ord_tmd"]
DEPOSIT_DECIMAL_KEYS = ["mtnc_rt"]
MARGIN_DIVISION_VALUES = ["01", "02"]
SETTLEMENT_STATUS_VALUES = ["1", "2"]
SELL_BUY_DIVISION_VALUES = ["00", "01", "02"]
FILLED_UNFILLED_DIVISION_VALUES = ["00", "01", "02"]
SORT_SEQUENCE_VALUES = ["AS", "DS"]
NGT_SORT_SEQUENCE_VALUES = ["", "AS", "DS"]
FUOP_DIVISION_VALUES = ["", "01", "02"]
NGT_SCREEN_DIVISION_DEFAULT = "02"
def _convert_fields(record: dict, str_keys: list, decimal_keys: list = (), date_keys: list = (), time_keys: list = ()) -> dict:
"""KIS 응답 레코드의 문자열 값을 타입에 맞게 변환한다. 변환 불가한 값은 문자열로 남긴다."""
for key, value in record.items():
if key in str_keys or len(value) == 0:
continue
if key in decimal_keys:
record[key] = Decimal(value)
continue
if key in date_keys:
record[key] = dtm.datetime.strptime(value, "%Y%m%d").date()
continue
if key in time_keys:
record[key] = dtm.datetime.strptime(value, "%H%M%S").time()
continue
try:
record[key] = int(value)
except ValueError:
pass
return record
[docs]
class KISDomesticFutureOption:
"""
한국투자증권 국내선물옵션 API (시세 + 주문/계좌)
"""
[docs]
def __init__(self, auth: KISAuth, corp_data: dict = None):
self.auth = auth
self.corp_data = corp_data
self.tr_client = KISTRClient(auth, corp_data)
def _tr_request(self, *args, **kwargs):
return self.tr_client.request(*args, **kwargs)
[docs]
def inquire_time_fuopchartprice(
self,
fid_input_iscd: str,
fid_input_date_1: dtm.date,
fid_input_hour_1: dtm.time | str,
fid_cond_mrkt_div_code: str = "F",
fid_hour_cls_code: str = "60",
fid_pw_data_incu_yn: str = "Y",
fid_fake_tick_incu_yn: str = "N",
):
"""
(국내선물옵션시세) 선물옵션 분봉조회[v1_국내선물-012]
선물옵션 분봉조회 API입니다.
실전계좌의 경우, 한 번의 호출에 최대 102건까지 확인 가능하며, FID_INPUT_DATE_1(입력날짜), FID_INPUT_HOUR_1(입력시간)을 이용하여 다음조회 가능합니다.
tr_cont를 이용한 다음조회는 불가능한 API입니다.
CM(야간선물), EU(야간옵션)의 경우 자정 이후 시간은 +24시간으로 입력/표시됩니다. (ex. "253000" = 새벽 1시 30분)
자정 이후 봉은 stck_bsop_date(영업일자)와 실제 달력상 일자가 다릅니다.
Args:
fid_input_iscd (str): 종목번호 (지수선물 6자리, 지수옵션 9자리. ex. A01609 - KOSPI200 선물 2026년 9월물)
fid_input_date_1 (dtm.date): 조회 기준일자 - 입력 날짜 기준으로 이전 기간 역순 조회
fid_input_hour_1 (dtm.time | str): 조회 기준시간 - 입력 시간 기준으로 역순 조회. 야간시장(CM/EU)의 자정 이후 시간은 +24시간 HHMMSS 문자열로 입력 (ex. "253000")
fid_cond_mrkt_div_code (str): FID 조건시장분류코드 - F:지수선물 O:지수옵션 JF:주식선물 JO:주식옵션 CF:상품선물(금),금리선물(국채),통화선물(달러) CM:야간선물 EU:야간옵션
fid_hour_cls_code (str): FID 시간구분코드 - 30:30초 60:1분 3600:1시간
fid_pw_data_incu_yn (str): 과거 데이터 포함 여부 - Y:과거 N:당일
fid_fake_tick_incu_yn (str): 허봉 포함 여부 - N으로 입력
Returns:
dict:
- rt_cd (str): 응답코드
- msg_cd (str): 메시지코드
- msg1 (str): 메시지1
- tr_cont (str): 연속거래여부
- output1 (dict): 응답상세1
- futs_prdy_vrss: 선물 전일 대비
- prdy_vrss_sign: 전일 대비 부호 - 1:상한 2:상승 3:보합 4:하한 5:하락
- futs_prdy_ctrt: 선물 전일 대비율
- futs_prdy_clpr: 선물 전일 종가
- prdy_nmix: 전일 지수
- acml_vol: 누적 거래량
- acml_tr_pbmn: 누적 거래 대금
- hts_kor_isnm: HTS 한글 종목명
- futs_prpr: 선물 현재가
- futs_shrn_iscd: 선물 단축 종목코드
- prdy_vol: 전일 거래량
- futs_mxpr: 선물 상한가
- futs_llam: 선물 하한가
- futs_oprc: 선물 시가2
- futs_hgpr: 선물 최고가
- futs_lwpr: 선물 최저가
- futs_prdy_oprc: 선물 전일 시가
- futs_prdy_hgpr: 선물 전일 최고가
- futs_prdy_lwpr: 선물 전일 최저가
- futs_askp: 선물 매도호가
- futs_bidp: 선물 매수호가
- basis: 베이시스
- kospi200_nmix: KOSPI200 지수
- kospi200_prdy_vrss: KOSPI200 전일 대비
- kospi200_prdy_ctrt: KOSPI200 전일 대비율
- kospi200_prdy_vrss_sign: KOSPI200 전일 대비 부호
- hts_otst_stpl_qty: HTS 미결제 약정 수량
- otst_stpl_qty_icdc: 미결제 약정 수량 증감
- tday_rltv: 당일 체결강도
- hts_thpr: HTS 이론가
- dprt: 괴리율
- output2 (list): 응답상세2
- stck_bsop_date: 주식 영업 일자
- stck_cntg_hour: 주식 체결 시간 - 야간시장(CM/EU)의 자정 이후 시간은 +24시간에서 24시간을 뺀 시간으로 변환됨
- futs_prpr: 선물 현재가
- futs_oprc: 선물 시가2
- futs_hgpr: 선물 최고가
- futs_lwpr: 선물 최저가
- cntg_vol: 체결 거래량
- acml_tr_pbmn: 누적 거래 대금
Raise:
ValueError: API 에러 발생시
"""
assert not self.auth.paper_trading, "실전계좌에서만 사용 가능한 API입니다."
assert fid_cond_mrkt_div_code in ["F", "O", "JF", "JO", "CF", "CM", "EU"], 'fid_cond_mrkt_div_code must be one of "F", "O", "JF", "JO", "CF", "CM", or "EU"'
assert fid_hour_cls_code in ["30", "60", "3600"], 'fid_hour_cls_code must be one of "30", "60", or "3600"'
assert fid_pw_data_incu_yn in ["Y", "N"], 'fid_pw_data_incu_yn must be "Y" or "N"'
assert fid_fake_tick_incu_yn in ["Y", "N"], 'fid_fake_tick_incu_yn must be "Y" or "N"'
url_path = "/uapi/domestic-futureoption/v1/quotations/inquire-time-fuopchartprice"
tr_id = "FHKIF03020200"
params = {
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code,
"FID_INPUT_ISCD": fid_input_iscd,
"FID_HOUR_CLS_CODE": fid_hour_cls_code,
"FID_PW_DATA_INCU_YN": fid_pw_data_incu_yn,
"FID_FAKE_TICK_INCU_YN": fid_fake_tick_incu_yn,
"FID_INPUT_DATE_1": fid_input_date_1.strftime("%Y%m%d"),
"FID_INPUT_HOUR_1": fid_input_hour_1.strftime("%H%M%S") if isinstance(fid_input_hour_1, dtm.time) else fid_input_hour_1,
}
res_body, res_headers = self._tr_request(url_path, tr_id, params=params)
if res_body["rt_cd"] != "0":
raise ValueError(f"Error: ({res_body['msg_cd']}) {res_body['msg1']}")
output1 = res_body["output1"]
for k in output1.keys():
if k in ["hts_kor_isnm", "futs_shrn_iscd"]:
pass
elif k in ["prdy_vrss_sign", "kospi200_prdy_vrss_sign", "acml_vol", "prdy_vol", "acml_tr_pbmn", "hts_otst_stpl_qty", "otst_stpl_qty_icdc"]:
output1[k] = int(output1[k])
else:
output1[k] = Decimal(output1[k])
output2 = []
for el in res_body["output2"]:
for k in el.keys():
if k == "stck_bsop_date":
el[k] = dtm.datetime.strptime(el[k], "%Y%m%d").date()
elif k == "stck_cntg_hour":
hour = int(el[k][:2])
if hour >= 24:
el[k] = dtm.time(hour - 24, int(el[k][2:4]), int(el[k][4:6]))
else:
el[k] = dtm.datetime.strptime(el[k], "%H%M%S").time()
elif k in ["cntg_vol", "acml_tr_pbmn"]:
el[k] = int(el[k])
else:
el[k] = Decimal(el[k])
output2.append(el)
result = {
"rt_cd": res_body["rt_cd"],
"msg_cd": res_body["msg_cd"],
"msg1": res_body["msg1"],
"tr_cont": res_headers["tr_cont"],
"output1": output1,
"output2": output2,
}
return result
[docs]
def inquire_daily_fuopchartprice(
self,
fid_input_iscd: str,
fid_input_date_1: dtm.date,
fid_input_date_2: dtm.date,
fid_period_div_code: str = "D",
fid_cond_mrkt_div_code: str = "F",
):
"""
(국내선물옵션시세) 선물옵션 기간별시세(일/주/월/년)[v1_국내선물-008]
(지수)선물옵션 기간별시세 데이터(일/주/월/년) 조회 API입니다.
한 번의 호출에 최대 100건까지 확인 가능하며, 그 이상의 기간은 조회 기간을 나누어 요청해야 합니다.
Args:
fid_input_iscd (str): 종목번호 (지수선물 6자리, 지수옵션 9자리. ex. A01609 - KOSPI200 선물 2026년 9월물)
fid_input_date_1 (dtm.date): 조회 시작일자
fid_input_date_2 (dtm.date): 조회 종료일자
fid_period_div_code (str): FID 기간분류코드 - D:일봉 W:주봉 M:월봉 Y:년봉
fid_cond_mrkt_div_code (str): FID 조건시장분류코드 - F:지수선물 O:지수옵션 CM:야간선물 EU:야간옵션 (CM/EU는 공식 문서에 없으나 실측 확인됨. 야간세션 봉의 stck_bsop_date는 거래일 기준)
Returns:
dict:
- rt_cd (str): 응답코드
- msg_cd (str): 메시지코드
- msg1 (str): 메시지1
- tr_cont (str): 연속거래여부
- output1 (dict): 응답상세1
- futs_prdy_vrss: 선물 전일 대비
- prdy_vrss_sign: 전일 대비 부호 - 1:상한 2:상승 3:보합 4:하한 5:하락
- futs_prdy_ctrt: 선물 전일 대비율
- futs_prdy_clpr: 선물 전일 종가
- acml_vol: 누적 거래량
- acml_tr_pbmn: 누적 거래 대금
- hts_kor_isnm: HTS 한글 종목명
- futs_prpr: 선물 현재가
- futs_shrn_iscd: 선물 단축 종목코드
- prdy_vol: 전일 거래량
- futs_mxpr: 선물 상한가
- futs_llam: 선물 하한가
- futs_oprc: 선물 시가2
- futs_hgpr: 선물 최고가
- futs_lwpr: 선물 최저가
- futs_prdy_oprc: 선물 전일 시가
- futs_prdy_hgpr: 선물 전일 최고가
- futs_prdy_lwpr: 선물 전일 최저가
- futs_askp: 선물 매도호가
- futs_bidp: 선물 매수호가
- basis: 베이시스
- kospi200_nmix: KOSPI200 지수
- kospi200_prdy_vrss: KOSPI200 전일 대비
- kospi200_prdy_ctrt: KOSPI200 전일 대비율
- kospi200_prdy_vrss_sign: KOSPI200 전일 대비 부호
- hts_otst_stpl_qty: HTS 미결제 약정 수량
- otst_stpl_qty_icdc: 미결제 약정 수량 증감
- tday_rltv: 당일 체결강도
- hts_thpr: HTS 이론가
- dprt: 괴리율
- output2 (list): 응답상세2
- stck_bsop_date: 주식 영업 일자
- futs_prpr: 선물 현재가 (해당 기간 종가)
- futs_oprc: 선물 시가2
- futs_hgpr: 선물 최고가
- futs_lwpr: 선물 최저가
- acml_vol: 누적 거래량
- acml_tr_pbmn: 누적 거래 대금
- mod_yn: 변경 여부
Raise:
ValueError: API 에러 발생시
"""
assert fid_period_div_code in ["D", "W", "M", "Y"], 'fid_period_div_code must be one of "D", "W", "M", or "Y"'
assert fid_cond_mrkt_div_code in ["F", "O", "CM", "EU"], 'fid_cond_mrkt_div_code must be one of "F", "O", "CM", or "EU"'
url_path = "/uapi/domestic-futureoption/v1/quotations/inquire-daily-fuopchartprice"
tr_id = "FHKIF03020100"
params = {
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code,
"FID_INPUT_ISCD": fid_input_iscd,
"FID_INPUT_DATE_1": fid_input_date_1.strftime("%Y%m%d"),
"FID_INPUT_DATE_2": fid_input_date_2.strftime("%Y%m%d"),
"FID_PERIOD_DIV_CODE": fid_period_div_code,
}
res_body, res_headers = self._tr_request(url_path, tr_id, params=params)
if res_body["rt_cd"] != "0":
raise ValueError(f"Error: ({res_body['msg_cd']}) {res_body['msg1']}")
str_keys = ["hts_kor_isnm", "futs_shrn_iscd"]
int_keys = ["prdy_vrss_sign", "kospi200_prdy_vrss_sign", "acml_vol", "prdy_vol", "acml_tr_pbmn", "hts_otst_stpl_qty", "otst_stpl_qty_icdc"]
output1 = res_body["output1"]
for k in output1.keys():
if k in str_keys or len(output1[k]) == 0:
pass
elif k in int_keys:
output1[k] = int(output1[k])
else:
output1[k] = Decimal(output1[k])
output2 = []
for el in res_body["output2"]:
if not el:
continue
for k in el.keys():
if k == "stck_bsop_date":
el[k] = dtm.datetime.strptime(el[k], "%Y%m%d").date()
elif k == "mod_yn" or len(el[k]) == 0:
pass
elif k in ["acml_vol", "acml_tr_pbmn"]:
el[k] = int(el[k])
else:
el[k] = Decimal(el[k])
output2.append(el)
result = {
"rt_cd": res_body["rt_cd"],
"msg_cd": res_body["msg_cd"],
"msg1": res_body["msg1"],
"tr_cont": res_headers["tr_cont"],
"output1": output1,
"output2": output2,
}
return result
def inquire_balance(
self,
cano: str,
acnt_prdt_cd: str,
mgna_dvsn: str = "01",
excc_stat_cd: str = "1",
ctx_area_fk200: str = "",
ctx_area_nk200: str = "",
tr_cont: str = "",
):
"""
(국내선물옵션주문/계좌) 선물옵션 잔고현황[v1_국내선물-004]
Args:
cano (str): 종합계좌번호 (8자리)
acnt_prdt_cd (str): 계좌상품코드 (선물옵션 계좌는 "03")
mgna_dvsn (str): 증거금 구분 - 01:개시 02:유지
excc_stat_cd (str): 정산상태코드 - 1:정산 2:본정산
ctx_area_fk200 (str): 연속조회검색조건200
ctx_area_nk200 (str): 연속조회키200
tr_cont (str): 연속거래여부 - 공백:최초조회 N:다음조회
Returns:
dict:
- rt_cd (str): 응답코드
- msg_cd (str): 메시지코드
- msg1 (str): 메시지1
- tr_cont (str): 연속거래여부 - F/M:다음 데이터 있음 D/E:마지막
- ctx_area_fk200 (str): 연속조회검색조건200
- ctx_area_nk200 (str): 연속조회키200
- output1 (list): 종목별 잔고
- cano: 종합계좌번호
- acnt_prdt_cd: 계좌상품코드
- pdno: 상품번호
- prdt_type_cd: 상품유형코드
- shtn_pdno: 단축상품번호
- prdt_name: 상품명
- sll_buy_dvsn_name: 매도매수구분명
- cblc_qty: 잔고수량
- excc_unpr: 정산단가 (Decimal)
- ccld_avg_unpr1: 체결평균단가1 (Decimal)
- idx_clpr: 지수종가 (Decimal)
- pchs_amt: 매입금액
- evlu_amt: 평가금액
- evlu_pfls_amt: 평가손익금액
- trad_pfls_amt: 매매손익금액
- lqd_psbl_qty: 청산가능수량
- output2 (dict): 계좌 합계
- dnca_cash: 예수금현금
- frcr_dncl_amt: 외화예수금액
- dnca_sbst: 예수금대용
- tot_dncl_amt: 총예수금액
- tot_ccld_amt: 총체결금액
- cash_mgna: 현금증거금
- sbst_mgna: 대용증거금
- mgna_tota: 증거금총액
- opt_dfpa: 옵션차금
- thdt_dfpa: 당일차금
- rnwl_dfpa: 갱신차금
- fee: 수수료
- nxdy_dnca: 익일예수금
- nxdy_dncl_amt: 익일예수금액
- prsm_dpast: 추정예탁자산
- prsm_dpast_amt: 추정예탁자산금액
- pprt_ord_psbl_cash: 적정주문가능현금
- add_mgna_cash: 추가증거금현금
- add_mgna_tota: 추가증거금총액
- futr_trad_pfls_amt: 선물매매손익금액
- opt_trad_pfls_amt: 옵션매매손익금액
- futr_evlu_pfls_amt: 선물평가손익금액
- opt_evlu_pfls_amt: 옵션평가손익금액
- trad_pfls_amt_smtl: 매매손익금액합계
- evlu_pfls_amt_smtl: 평가손익금액합계
- wdrw_psbl_tot_amt: 인출가능총금액
- ord_psbl_cash: 주문가능현금
- ord_psbl_sbst: 주문가능대용
- ord_psbl_tota: 주문가능총액
- pchs_amt_smtl: 매입금액합계
- evlu_amt_smtl: 평가금액합계
Raise:
ValueError: API 에러 발생시
"""
assert mgna_dvsn in MARGIN_DIVISION_VALUES, f"mgna_dvsn must be one of {MARGIN_DIVISION_VALUES}"
assert excc_stat_cd in SETTLEMENT_STATUS_VALUES, f"excc_stat_cd must be one of {SETTLEMENT_STATUS_VALUES}"
url_path = "/uapi/domestic-futureoption/v1/trading/inquire-balance"
tr_id = "VTFO6118R" if self.auth.paper_trading else "CTFO6118R"
params = {
"CANO": cano,
"ACNT_PRDT_CD": acnt_prdt_cd,
"MGNA_DVSN": mgna_dvsn,
"EXCC_STAT_CD": excc_stat_cd,
"CTX_AREA_FK200": ctx_area_fk200,
"CTX_AREA_NK200": ctx_area_nk200,
}
res_body, res_headers = self._tr_request(url_path, tr_id, tr_cont, params=params)
if res_body["rt_cd"] != "0":
raise ValueError(f"Error: ({res_body['msg_cd']}) {res_body['msg1']}")
output1 = [_convert_fields(el, BALANCE_STR_KEYS, BALANCE_DECIMAL_KEYS) for el in res_body["output1"]]
output2 = _convert_fields(res_body["output2"], BALANCE_STR_KEYS)
return self._build_result(res_body, res_headers, output1, output2)
def inquire_balance_valuation_pl(
self,
cano: str,
acnt_prdt_cd: str,
mgna_dvsn: str = "01",
excc_stat_cd: str = "1",
ctx_area_fk200: str = "",
ctx_area_nk200: str = "",
tr_cont: str = "",
):
"""
(국내선물옵션주문/계좌) 선물옵션 잔고평가손익내역[v1_국내선물-015]
보유 종목별 평가금액/평가손익/매매손익과 계좌 합계를 조회한다. 실전계좌 전용.
Args:
cano (str): 종합계좌번호 (8자리)
acnt_prdt_cd (str): 계좌상품코드 (선물옵션 계좌는 "03")
mgna_dvsn (str): 증거금 구분 - 01:개시 02:유지
excc_stat_cd (str): 정산상태코드 - 1:정산 2:본정산
ctx_area_fk200 (str): 연속조회검색조건200
ctx_area_nk200 (str): 연속조회키200
tr_cont (str): 연속거래여부 - 공백:최초조회 N:다음조회
Returns:
dict:
- rt_cd (str): 응답코드
- msg_cd (str): 메시지코드
- msg1 (str): 메시지1
- tr_cont (str): 연속거래여부 - F/M:다음 데이터 있음 D/E:마지막
- ctx_area_fk200 (str): 연속조회검색조건200
- ctx_area_nk200 (str): 연속조회키200
- output1 (list): 종목별 잔고 평가손익
- cano: 종합계좌번호
- acnt_prdt_cd: 계좌상품코드
- pdno: 상품번호
- prdt_type_cd: 상품유형코드
- shtn_pdno: 단축상품번호
- prdt_name: 상품명
- sll_buy_dvsn_name: 매도매수구분명
- cblc_qty1: 잔고수량1
- excc_unpr: 정산단가 (Decimal)
- ccld_avg_unpr1: 체결평균단가1 (Decimal)
- idx_clpr: 지수종가 (Decimal)
- pchs_amt: 매입금액
- evlu_amt: 평가금액
- evlu_pfls_amt: 평가손익금액
- trad_pfls_amt: 매매손익금액
- lqd_psbl_qty: 청산가능수량
- output2 (dict): 계좌 합계
- dnca_cash: 예수금현금
- frcr_dncl_amt: 외화예수금액
- dnca_sbst: 예수금대용
- tot_dncl_amt: 총예수금액
- tot_ccld_amt: 총체결금액
- cash_mgna: 현금증거금
- sbst_mgna: 대용증거금
- mgna_tota: 증거금총액
- opt_dfpa: 옵션차금
- thdt_dfpa: 당일차금
- rnwl_dfpa: 갱신차금
- fee: 수수료
- nxdy_dnca: 익일예수금
- nxdy_dncl_amt: 익일예수금액
- prsm_dpast: 추정예탁자산
- prsm_dpast_amt: 추정예탁자산금액
- pprt_ord_psbl_cash: 적정주문가능현금
- add_mgna_cash: 추가증거금현금
- add_mgna_tota: 추가증거금총액
- futr_trad_pfls_amt: 선물매매손익금액
- opt_trad_pfls_amt: 옵션매매손익금액
- futr_evlu_pfls_amt: 선물평가손익금액
- opt_evlu_pfls_amt: 옵션평가손익금액
- trad_pfls_amt_smtl: 매매손익금액합계
- evlu_pfls_amt_smtl: 평가손익금액합계
- wdrw_psbl_tot_amt: 인출가능총금액
- ord_psbl_cash: 주문가능현금
- ord_psbl_sbst: 주문가능대용
- ord_psbl_tota: 주문가능총액
Raise:
ValueError: API 에러 발생시
"""
assert not self.auth.paper_trading, "실전계좌에서만 사용 가능한 API입니다."
assert mgna_dvsn in MARGIN_DIVISION_VALUES, f"mgna_dvsn must be one of {MARGIN_DIVISION_VALUES}"
assert excc_stat_cd in SETTLEMENT_STATUS_VALUES, f"excc_stat_cd must be one of {SETTLEMENT_STATUS_VALUES}"
url_path = "/uapi/domestic-futureoption/v1/trading/inquire-balance-valuation-pl"
tr_id = "CTFO6159R"
params = {
"CANO": cano,
"ACNT_PRDT_CD": acnt_prdt_cd,
"MGNA_DVSN": mgna_dvsn,
"EXCC_STAT_CD": excc_stat_cd,
"CTX_AREA_FK200": ctx_area_fk200,
"CTX_AREA_NK200": ctx_area_nk200,
}
res_body, res_headers = self._tr_request(url_path, tr_id, tr_cont, params=params)
if res_body["rt_cd"] != "0":
raise ValueError(f"Error: ({res_body['msg_cd']}) {res_body['msg1']}")
output1 = [_convert_fields(el, BALANCE_STR_KEYS, BALANCE_DECIMAL_KEYS) for el in res_body["output1"]]
output2 = _convert_fields(res_body["output2"], BALANCE_STR_KEYS)
return self._build_result(res_body, res_headers, output1, output2)
def inquire_balance_settlement_pl(
self,
cano: str,
acnt_prdt_cd: str,
inqr_dt: dtm.date,
ctx_area_fk200: str = "",
ctx_area_nk200: str = "",
tr_cont: str = "",
):
"""
(국내선물옵션주문/계좌) 선물옵션 잔고정산손익내역[v1_국내선물-013]
조회일 기준 종목별 매매손익/평가손익과 계좌 정산 요약을 조회한다.
Args:
cano (str): 종합계좌번호 (8자리)
acnt_prdt_cd (str): 계좌상품코드 (선물옵션 계좌는 "03")
inqr_dt (dtm.date): 조회일자
ctx_area_fk200 (str): 연속조회검색조건200
ctx_area_nk200 (str): 연속조회키200
tr_cont (str): 연속거래여부 - 공백:최초조회 N:다음조회
Returns:
dict:
- rt_cd (str): 응답코드
- msg_cd (str): 메시지코드
- msg1 (str): 메시지1
- tr_cont (str): 연속거래여부 - F/M:다음 데이터 있음 D/E:마지막
- ctx_area_fk200 (str): 연속조회검색조건200
- ctx_area_nk200 (str): 연속조회키200
- output1 (list): 종목별 정산손익
- pdno: 상품번호
- prdt_name: 상품명
- trad_dvsn_name: 매매구분명
- bfdy_cblc_qty: 전일잔고수량
- new_qty: 신규수량
- mnpl_rpch_qty: 전매환매수량
- cblc_qty: 잔고수량
- cblc_amt: 잔고금액
- trad_pfls_amt: 매매손익금액
- evlu_amt: 평가금액
- evlu_pfls_amt: 평가손익금액
- output2 (dict): 계좌 정산 요약
- nxdy_dnca: 익일예수금
- mmga_cash: 유지증거금현금
- brkg_mgna_cash: 위탁증거금현금
- opt_buy_chgs: 옵션매수대금
- opt_lqd_evlu_amt: 옵션청산평가금액
- dnca_sbst: 예수금대용
- mmga_tota: 유지증거금총액
- brkg_mgna_tota: 위탁증거금총액
- opt_sll_chgs: 옵션매도대금
- fee: 수수료
- thdt_dfpa: 당일차금
- rnwl_dfpa: 갱신차금
- dnca_cash: 예수금현금
Raise:
ValueError: API 에러 발생시
"""
url_path = "/uapi/domestic-futureoption/v1/trading/inquire-balance-settlement-pl"
tr_id = "CTFO6117R"
params = {
"CANO": cano,
"ACNT_PRDT_CD": acnt_prdt_cd,
"INQR_DT": inqr_dt.strftime("%Y%m%d"),
"CTX_AREA_FK200": ctx_area_fk200,
"CTX_AREA_NK200": ctx_area_nk200,
}
res_body, res_headers = self._tr_request(url_path, tr_id, tr_cont, params=params)
if res_body["rt_cd"] != "0":
raise ValueError(f"Error: ({res_body['msg_cd']}) {res_body['msg1']}")
output1 = [_convert_fields(el, SETTLEMENT_STR_KEYS) for el in res_body["output1"]]
output2 = _convert_fields(res_body["output2"], SETTLEMENT_STR_KEYS)
return self._build_result(res_body, res_headers, output1, output2)
def inquire_daily_amount_fee(
self,
cano: str,
acnt_prdt_cd: str,
inqr_strt_day: dtm.date,
inqr_end_day: dtm.date,
ctx_area_fk200: str = "",
ctx_area_nk200: str = "",
tr_cont: str = "",
):
"""
(국내선물옵션주문/계좌) 선물옵션 기간약정수수료일별[v1_국내선물-017]
조회 기간의 일자·종목별 매도/매수 약정금액, 수수료, 매매손익과 기간 합계를 조회한다. 같은 날짜에 종목 수만큼 행이 내려온다.
조회 기간이 3개월을 넘으면 에러가 발생하므로, 더 긴 기간은 3개월 이내로 나누어 조회한다.
Args:
cano (str): 종합계좌번호 (8자리)
acnt_prdt_cd (str): 계좌상품코드 (선물옵션 계좌는 "03")
inqr_strt_day (dtm.date): 조회시작일
inqr_end_day (dtm.date): 조회종료일
ctx_area_fk200 (str): 연속조회검색조건200
ctx_area_nk200 (str): 연속조회키200
tr_cont (str): 연속거래여부 - 공백:최초조회 N:다음조회
Returns:
dict:
- rt_cd (str): 응답코드
- msg_cd (str): 메시지코드
- msg1 (str): 메시지1
- tr_cont (str): 연속거래여부 - F/M:다음 데이터 있음 D/E:마지막
- ctx_area_fk200 (str): 연속조회검색조건200
- ctx_area_nk200 (str): 연속조회키200
- output1 (list): 일자별 약정/수수료/손익
- ord_dt: 주문일자 (date)
- pdno: 상품번호
- item_name: 종목명
- sll_agrm_amt: 매도약정금액
- sll_fee: 매도수수료
- buy_agrm_amt: 매수약정금액
- buy_fee: 매수수수료
- tot_fee_smtl: 총수수료합계
- trad_pfls: 매매손익
- output2 (dict): 기간 합계
- futr_agrm: 선물약정
- futr_agrm_amt: 선물약정금액
- futr_agrm_amt_smtl: 선물약정금액합계
- futr_sll_fee_smtl: 선물매도수수료합계
- futr_buy_fee_smtl: 선물매수수수료합계
- futr_fee_smtl: 선물수수료합계
- opt_agrm: 옵션약정
- opt_agrm_amt: 옵션약정금액
- opt_agrm_amt_smtl: 옵션약정금액합계
- opt_sll_fee_smtl: 옵션매도수수료합계
- opt_buy_fee_smtl: 옵션매수수수료합계
- opt_fee_smtl: 옵션수수료합계
- prdt_futr_agrm: 상품선물약정
- prdt_fuop: 상품선물옵션
- prdt_futr_evlu_amt: 상품선물평가금액
- futr_fee: 선물수수료
- opt_fee: 옵션수수료
- fee: 수수료
- sll_agrm_amt: 매도약정금액
- buy_agrm_amt: 매수약정금액
- agrm_amt_smtl: 약정금액합계
- sll_fee: 매도수수료
- buy_fee: 매수수수료
- fee_smtl: 수수료합계
- trad_pfls_smtl: 매매손익합계
Raise:
ValueError: API 에러 발생시
"""
url_path = "/uapi/domestic-futureoption/v1/trading/inquire-daily-amount-fee"
tr_id = "CTFO6119R"
params = {
"CANO": cano,
"ACNT_PRDT_CD": acnt_prdt_cd,
"INQR_STRT_DAY": inqr_strt_day.strftime("%Y%m%d"),
"INQR_END_DAY": inqr_end_day.strftime("%Y%m%d"),
"CTX_AREA_FK200": ctx_area_fk200,
"CTX_AREA_NK200": ctx_area_nk200,
}
res_body, res_headers = self._tr_request(url_path, tr_id, tr_cont, params=params)
if res_body["rt_cd"] != "0":
raise ValueError(f"Error: ({res_body['msg_cd']}) {res_body['msg1']}")
output1 = [_convert_fields(el, DAILY_AMOUNT_FEE_STR_KEYS, date_keys=DAILY_AMOUNT_FEE_DATE_KEYS) for el in res_body["output1"]]
output2 = _convert_fields(res_body["output2"], DAILY_AMOUNT_FEE_STR_KEYS)
return self._build_result(res_body, res_headers, output1, output2)
def inquire_ccnl(
self,
cano: str,
acnt_prdt_cd: str,
strt_ord_dt: dtm.date,
end_ord_dt: dtm.date,
sll_buy_dvsn_cd: str = "00",
ccld_nccs_dvsn: str = "00",
sort_sqn: str = "DS",
pdno: str = "",
strt_odno: str = "",
mket_id_cd: str = "",
ctx_area_fk200: str = "",
ctx_area_nk200: str = "",
tr_cont: str = "",
):
"""
(국내선물옵션주문/계좌) 선물옵션 주문체결내역조회[v1_국내선물-005]
Args:
cano (str): 종합계좌번호 (8자리)
acnt_prdt_cd (str): 계좌상품코드 (선물옵션 계좌는 "03")
strt_ord_dt (dtm.date): 주문 조회 시작일자
end_ord_dt (dtm.date): 주문 조회 종료일자
sll_buy_dvsn_cd (str): 매도매수구분코드 - 00:전체 01:매도 02:매수
ccld_nccs_dvsn (str): 체결미체결구분 - 00:전체 01:체결 02:미체결
sort_sqn (str): 정렬순서 - AS:정순 DS:역순
pdno (str): 상품번호 (공백:전체)
strt_odno (str): 시작주문번호 (공백:전체)
mket_id_cd (str): 시장ID코드 (공백:전체)
ctx_area_fk200 (str): 연속조회검색조건200
ctx_area_nk200 (str): 연속조회키200
tr_cont (str): 연속거래여부 - 공백:최초조회 N:다음조회
Returns:
dict:
- rt_cd (str): 응답코드
- msg_cd (str): 메시지코드
- msg1 (str): 메시지1
- tr_cont (str): 연속거래여부 - F/M:다음 데이터 있음 D/E:마지막
- ctx_area_fk200 (str): 연속조회검색조건200
- ctx_area_nk200 (str): 연속조회키200
- output1 (list): 주문체결내역
- ord_gno_brno: 주문채번지점번호
- cano: 종합계좌번호
- csac_name: 종합계좌명
- acnt_prdt_cd: 계좌상품코드
- ord_dt: 주문일자 (date)
- odno: 주문번호
- orgn_odno: 원주문번호
- sll_buy_dvsn_cd: 매도매수구분코드 - 01:매도 02:매수
- trad_dvsn_name: 매매구분명
- nmpr_type_cd: 호가유형코드
- nmpr_type_name: 호가유형명
- pdno: 상품번호
- prdt_name: 상품명
- prdt_type_cd: 상품유형코드
- ord_qty: 주문수량
- ord_idx: 주문지수 (Decimal)
- qty: 잔량
- ord_tmd: 주문시각 (time)
- tot_ccld_qty: 총체결수량
- avg_idx: 평균지수 (Decimal)
- tot_ccld_amt: 총체결금액
- rjct_qty: 거부수량
- ingr_trad_rjct_rson_cd: 장내매매거부사유코드
- ingr_trad_rjct_rson_name: 장내매매거부사유명
- ord_stfno: 주문직원번호
- sprd_item_yn: 스프레드종목여부
- ord_ip_addr: 주문IP주소
- output2 (dict): 합계
- tot_ord_qty: 총주문수량
- tot_ccld_amt_smtl: 총체결금액합계
- tot_ccld_qty_smtl: 총체결수량합계
- fee_smtl: 수수료합계
- ctac_tlno: 연락전화번호
Raise:
ValueError: API 에러 발생시
"""
assert sll_buy_dvsn_cd in SELL_BUY_DIVISION_VALUES, f"sll_buy_dvsn_cd must be one of {SELL_BUY_DIVISION_VALUES}"
assert ccld_nccs_dvsn in FILLED_UNFILLED_DIVISION_VALUES, f"ccld_nccs_dvsn must be one of {FILLED_UNFILLED_DIVISION_VALUES}"
assert sort_sqn in SORT_SEQUENCE_VALUES, f"sort_sqn must be one of {SORT_SEQUENCE_VALUES}"
url_path = "/uapi/domestic-futureoption/v1/trading/inquire-ccnl"
tr_id = "VTTO5201R" if self.auth.paper_trading else "TTTO5201R"
params = {
"CANO": cano,
"ACNT_PRDT_CD": acnt_prdt_cd,
"STRT_ORD_DT": strt_ord_dt.strftime("%Y%m%d"),
"END_ORD_DT": end_ord_dt.strftime("%Y%m%d"),
"SLL_BUY_DVSN_CD": sll_buy_dvsn_cd,
"CCLD_NCCS_DVSN": ccld_nccs_dvsn,
"SORT_SQN": sort_sqn,
"PDNO": pdno,
"STRT_ODNO": strt_odno,
"MKET_ID_CD": mket_id_cd,
"CTX_AREA_FK200": ctx_area_fk200,
"CTX_AREA_NK200": ctx_area_nk200,
}
res_body, res_headers = self._tr_request(url_path, tr_id, tr_cont, params=params)
if res_body["rt_cd"] != "0":
raise ValueError(f"Error: ({res_body['msg_cd']}) {res_body['msg1']}")
output1 = [_convert_fields(el, CCNL_STR_KEYS, CCNL_DECIMAL_KEYS, CCNL_DATE_KEYS, CCNL_TIME_KEYS) for el in res_body["output1"]]
output2 = _convert_fields(res_body["output2"], CCNL_STR_KEYS)
return self._build_result(res_body, res_headers, output1, output2)
def inquire_ngt_ccnl(
self,
cano: str,
acnt_prdt_cd: str,
strt_ord_dt: dtm.date,
end_ord_dt: dtm.date,
sll_buy_dvsn_cd: str = "00",
ccld_nccs_dvsn: str = "00",
sort_sqn: str = "",
strt_odno: str = "",
pdno: str = "",
mket_id_cd: str = "",
fuop_dvsn_cd: str = "",
ctx_area_fk200: str = "",
ctx_area_nk200: str = "",
tr_cont: str = "",
):
"""
(국내선물옵션주문/계좌) (야간)선물옵션 주문체결 내역조회[국내선물-010]
야간시장(18:00~익일 06:00) 주문체결 내역을 조회한다. 실전계좌 전용.
Args:
cano (str): 종합계좌번호 (8자리)
acnt_prdt_cd (str): 계좌상품코드 (선물옵션 계좌는 "03")
strt_ord_dt (dtm.date): 주문 조회 시작일자
end_ord_dt (dtm.date): 주문 조회 종료일자 (해당일 포함 조회는 다음날로 지정)
sll_buy_dvsn_cd (str): 매도매수구분코드 - 00:전체 01:매도 02:매수
ccld_nccs_dvsn (str): 체결미체결구분 - 00:전체 01:체결 02:미체결
sort_sqn (str): 정렬순서 - 공백:기본 AS:정순 DS:역순
strt_odno (str): 시작주문번호 (공백:전체)
pdno (str): 상품번호 (공백:전체)
mket_id_cd (str): 시장ID코드 (공백:전체)
fuop_dvsn_cd (str): 선물옵션구분코드 - 공백:전체 01:선물 02:옵션
ctx_area_fk200 (str): 연속조회검색조건200
ctx_area_nk200 (str): 연속조회키200
tr_cont (str): 연속거래여부 - 공백:최초조회 N:다음조회
Returns:
dict:
- rt_cd (str): 응답코드
- msg_cd (str): 메시지코드
- msg1 (str): 메시지1
- tr_cont (str): 연속거래여부 - F/M:다음 데이터 있음 D/E:마지막
- ctx_area_fk200 (str): 연속조회검색조건200
- ctx_area_nk200 (str): 연속조회키200
- output1 (list): 주문체결내역
- ord_gno_brno: 주문채번지점번호
- cano: 종합계좌번호
- csac_name: 종합계좌명
- acnt_prdt_cd: 계좌상품코드
- ord_dt: 주문일자 (date)
- odno: 주문번호
- orgn_odno: 원주문번호
- sll_buy_dvsn_cd: 매도매수구분코드 - 01:매도 02:매수
- trad_dvsn_name: 매매구분명
- nmpr_type_name: 호가유형명
- pdno: 상품번호
- prdt_name: 상품명
- prdt_type_cd: 상품유형코드
- ord_qty: 주문수량
- ord_idx4: 주문지수 (Decimal)
- qty: 잔량
- ord_tmd: 주문시각 (time)
- tot_ccld_qty: 총체결수량
- avg_idx: 평균지수 (Decimal)
- tot_ccld_amt: 총체결금액
- rjct_qty: 거부수량
- ingr_trad_rjct_rson_cd: 장내매매거부사유코드
- ingr_trad_rjct_rson_name: 장내매매거부사유명
- ord_stfno: 주문직원번호
- sprd_item_yn: 스프레드종목여부
- ord_ip_addr: 주문IP주소
- output2 (dict): 합계
- tot_ord_qty: 총주문수량
- fee: 수수료
- ctac_tlno: 연락전화번호
Raise:
ValueError: API 에러 발생시
"""
assert not self.auth.paper_trading, "실전계좌에서만 사용 가능한 API입니다."
assert sll_buy_dvsn_cd in SELL_BUY_DIVISION_VALUES, f"sll_buy_dvsn_cd must be one of {SELL_BUY_DIVISION_VALUES}"
assert ccld_nccs_dvsn in FILLED_UNFILLED_DIVISION_VALUES, f"ccld_nccs_dvsn must be one of {FILLED_UNFILLED_DIVISION_VALUES}"
assert sort_sqn in NGT_SORT_SEQUENCE_VALUES, f"sort_sqn must be one of {NGT_SORT_SEQUENCE_VALUES}"
assert fuop_dvsn_cd in FUOP_DIVISION_VALUES, f"fuop_dvsn_cd must be one of {FUOP_DIVISION_VALUES}"
url_path = "/uapi/domestic-futureoption/v1/trading/inquire-ngt-ccnl"
tr_id = "STTN5201R"
params = {
"CANO": cano,
"ACNT_PRDT_CD": acnt_prdt_cd,
"STRT_ORD_DT": strt_ord_dt.strftime("%Y%m%d"),
"END_ORD_DT": end_ord_dt.strftime("%Y%m%d"),
"SLL_BUY_DVSN_CD": sll_buy_dvsn_cd,
"CCLD_NCCS_DVSN": ccld_nccs_dvsn,
"SORT_SQN": sort_sqn,
"STRT_ODNO": strt_odno,
"PDNO": pdno,
"MKET_ID_CD": mket_id_cd,
"FUOP_DVSN_CD": fuop_dvsn_cd,
"SCRN_DVSN": NGT_SCREEN_DIVISION_DEFAULT,
"CTX_AREA_FK200": ctx_area_fk200,
"CTX_AREA_NK200": ctx_area_nk200,
}
res_body, res_headers = self._tr_request(url_path, tr_id, tr_cont, params=params)
if res_body["rt_cd"] != "0":
raise ValueError(f"Error: ({res_body['msg_cd']}) {res_body['msg1']}")
output1 = [_convert_fields(el, CCNL_STR_KEYS, NGT_CCNL_DECIMAL_KEYS, CCNL_DATE_KEYS, CCNL_TIME_KEYS) for el in res_body["output1"]]
output2 = _convert_fields(res_body["output2"], CCNL_STR_KEYS)
return self._build_result(res_body, res_headers, output1, output2)
def inquire_deposit(self, cano: str, acnt_prdt_cd: str):
"""
(국내선물옵션주문/계좌) 선물옵션 총자산현황[v1_국내선물-014]
예수금, 증거금, 매매/평가손익, 추정예탁자산 등 계좌 단위 자산 현황을 조회한다. 실전계좌 전용.
Args:
cano (str): 종합계좌번호 (8자리)
acnt_prdt_cd (str): 계좌상품코드 (선물옵션 계좌는 "03")
Returns:
dict:
- rt_cd (str): 응답코드
- msg_cd (str): 메시지코드
- msg1 (str): 메시지1
- tr_cont (str): 연속거래여부
- output (dict): 총자산현황
- dnca_tota: 예수금총액
- bfdy_chck_amt: 전일수표금액
- thdt_chck_amt: 당일수표금액
- rlth_uwdl_dpos_amt: 실물인수도예치금액
- brkg_mgna_cash: 위탁증거금현금
- wdrw_psbl_tot_amt: 인출가능총금액
- ord_psbl_cash: 주문가능현금
- ord_psbl_tota: 주문가능총액
- dnca_sbst: 예수금대용
- scts_sbst_amt: 유가증권대용금액
- frcr_evlu_amt: 외화평가금액
- brkg_mgna_sbst: 위탁증거금대용
- sbst_rlse_psbl_amt: 대용해제가능금액
- mtnc_rt: 유지비율 (Decimal)
- add_mgna_tota: 추가증거금총액
- add_mgna_cash: 추가증거금현금
- rcva: 미수금
- futr_trad_pfls: 선물매매손익
- opt_trad_pfls_amt: 옵션매매손익금액
- trad_pfls_smtl: 매매손익합계
- futr_evlu_pfls_amt: 선물평가손익금액
- opt_evlu_pfls_amt: 옵션평가손익금액
- evlu_pfls_smtl: 평가손익합계
- excc_dfpa: 정산차금
- opt_dfpa: 옵션차금
- brkg_fee: 위탁수수료
- nxdy_dnca: 익일예수금
- prsm_dpast_amt: 추정예탁자산금액
- cash_mntn_amt: 현금유지금액
- hack_acdt_acnt_move_amt: 해킹사고계좌이전금액
Raise:
ValueError: API 에러 발생시
"""
assert not self.auth.paper_trading, "실전계좌에서만 사용 가능한 API입니다."
url_path = "/uapi/domestic-futureoption/v1/trading/inquire-deposit"
tr_id = "CTRP6550R"
params = {
"CANO": cano,
"ACNT_PRDT_CD": acnt_prdt_cd,
}
res_body, res_headers = self._tr_request(url_path, tr_id, params=params)
if res_body["rt_cd"] != "0":
raise ValueError(f"Error: ({res_body['msg_cd']}) {res_body['msg1']}")
return {
"rt_cd": res_body["rt_cd"],
"msg_cd": res_body["msg_cd"],
"msg1": res_body["msg1"].strip(),
"tr_cont": res_headers.get("tr_cont", "").strip(),
"output": _convert_fields(res_body["output"], [], DEPOSIT_DECIMAL_KEYS),
}
def _build_result(self, res_body: dict, res_headers: dict, output1: list, output2: dict) -> dict:
return {
"rt_cd": res_body["rt_cd"],
"msg_cd": res_body["msg_cd"],
"msg1": res_body["msg1"].strip(),
"tr_cont": res_headers.get("tr_cont", "").strip(),
"ctx_area_fk200": res_body.get("ctx_area_fk200", "").strip(),
"ctx_area_nk200": res_body.get("ctx_area_nk200", "").strip(),
"output1": output1,
"output2": output2,
}