from decimal import Decimal
from pyqqq.brokerage.kis.oauth import KISAuth
from pyqqq.brokerage.kis.tr_client import KISTRClient
import datetime as dtm

class KISDomesticStock:
    '''
    한국투자증권 국내주식 API
    '''
    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)

    def get_price(self,
                  fid_input_iscd: str,
                  fid_cond_mrkt_div_code: str = 'J'):
        '''
        (국내주식시세) 주식현재가 시세[v1_국내주식-008]

        Args:
            fid_input_iscd (str): FID 입력종목코드 - 종목번호(6자리) ETN의 경우 Q로 시작(EX. Q500001)
            fid_cond_mrkt_div_code (str): FID 조건시장분류코드 - J:주식,ETF,ETN W:ELW

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output (dict): 출력

                - iscd_stat_cls_code: 종목상태구분코드 - 00:그외 51:관리종목 52:투자위험 53:투자경고 54:투자주의 55:신용가능 57:증거금 100% 58:거래정지 59:단기과열
                - marg_rate: 증거금비율
                - rprs_mrkt_kor_name: 대표시장한글명
                - new_hgpr_lwpr_cls_code: 신고가저가구분코드 - 조회하는 종목이 신고/신저에 도달했을 경우에만 조회됨
                - bstp_kor_isnm: 업종한글종목명
                - temp_stop_yn: 임시정지여부
                - oprc_rang_cont_yn: 시가범위연장여부
                - clpr_rang_cont_yn: 종가범위연장여부
                - crdt_able_yn: 신용가능여부
                - grmn_rate_cls_code: 보증금비율구분코드 - 한국투자 증거금비율 (marg_rate 참고) 40:20%,30%,40% 50:50% 60:60%
                - elw_pblc_yn: ELW발행여부
                - stck_prpr: 주식현재가
                - prdy_vrss: 전일대비
                - prdy_vrss_sign: 전일대비부호 - 1:상한 2:상승 3:보합 4:하한 5:하락
                - prdy_ctrt: 전일대비율
                - acml_tr_pbmn: 누적 거래 대금
                - acml_vol: 누적 거래량
                - prdy_vrss_vol_rate: 전일 대비 거래량 비율 - 주식현재가 일자별 API 응답값 사용
                - stck_oprc: 주식 시가
                - stck_hgpr: 주식 최고가
                - stck_lwpr: 주식 최저가
                - stck_mxpr: 주식 상한가
                - stck_llam: 주식 하한가
                - stck_sdpr: 주식 기준가
                - wghn_avrg_stck_prc: 가중 평균 주식 가격
                - hts_frgn_ehrt: HTS 외국인 소진율
                - frgn_ntby_qty: 외국인 순매수 수량
                - pgtr_ntby_qty: 프로그램매매 순매수 수량
                - pvt_scnd_dmrs_prc: 피벗 2차 디저항 가격 - 직원용 데이터
                - pvt_frst_dmrs_prc: 피벗 1차 디저항 가격 - 직원용 데이터
                - pvt_pont_val: 피벗 포인트 값 - 직원용 데이터
                - pvt_frst_dmsp_prc: 피벗 1차 디지지 가격 - 직원용 데이터
                - pvt_scnd_dmsp_prc: 피벗 2차 디지지 가격 - 직원용 데이터
                - dmrs_val: 디저항 값 - 직원용 데이터
                - dmsp_val: 디지지 값 - 직원용 데이터
                - cpfn: 자본금
                - rstc_wdth_prc: 제한 폭 가격
                - stck_fcam: 주식 액면가
                - stck_sspr: 주식 대용가
                - aspr_unit: 호가단위
                - hts_deal_qty_unit_val: HTS 매매 수량 단위 값
                - lstn_stcn: 상장 주수
                - hts_avls: HTS 시가총액
                - per: PER
                - pbr: PBR
                - stac_month: 결산 월
                - vol_tnrt: 거래량 회전율
                - eps: EPS
                - bps: BPS
                - d250_hgpr: 250일 최고가
                - d250_hgpr_date: 250일 최고가 일자
                - d250_hgpr_vrss_prpr_rate: 250일 최고가 대비 현재가 비율
                - d250_lwpr: 250일 최저가
                - d250_lwpr_date: 250일 최저가 일자
                - d250_lwpr_vrss_prpr_rate: 250일 최저가 대비 현재가 비율
                - stck_dryy_hgpr: 주식 연중 최고가
                - dryy_hgpr_vrss_prpr_rate: 연중 최고가 대비 현재가 비율
                - dryy_hgpr_date: 연중 최고가 일자
                - stck_dryy_lwpr: 주식 연중 최저가
                - dryy_lwpr_vrss_prpr_rate: 연중 최저가 대비 현재가 비율
                - dryy_lwpr_date: 연중 최저가 일자
                - w52_hgpr: 52주일 최고가
                - w52_hgpr_vrss_prpr_ctrt: 52주일 최고가 대비 현재가 대비
                - w52_hgpr_date: 52주일 최고가 일자
                - w52_lwpr: 52주일 최저가
                - w52_lwpr_vrss_prpr_ctrt: 52주일 최저가 대비 현재가 대비
                - w52_lwpr_date: 52주일 최저가 일자
                - whol_loan_rmnd_rate: 전체 융자 잔고 비율
                - ssts_yn: 공매도가능여부
                - stck_shrn_iscd: 주식 단축 종목코드
                - fcam_cnnm: 액면가 통화명
                - cpfn_cnnm: 자본금 통화명 - 외국주권은 억으로 떨어지며, 그 외에는 만으로 표시됨
                - apprch_rate: 접근도
                - frgn_hldn_qty: 외국인 보유 수량
                - vi_cls_code: VI적용구분코드
                - ovtm_vi_cls_code: 시간외단일가VI적용구분코드
                - last_ssts_cntg_qty: 최종 공매도 체결 수량
                - invt_caful_yn: 투자유의여부 - Y/N
                - mrkt_warn_cls_code: 시장경고코드 - 00:없음 01:투자주의 02:투자경고 03:투자위험
                - short_over_yn: 단기과열여부 - Y/N
                - sltr_yn: 정리매매여부 - Y/N

        Raise:
            ValueError: API 에러 발생시
        '''

        assert fid_cond_mrkt_div_code in ['J', 'W']
        assert len(fid_input_iscd) == 6 or (len(fid_input_iscd) == 7 and fid_input_iscd[0] == 'Q')

        path = '/uapi/domestic-stock/v1/quotations/inquire-price'
        tr_id = 'FHKST01010100'
        params = {
            'FID_COND_MRKT_DIV_CODE': fid_cond_mrkt_div_code,
            'FID_INPUT_ISCD': fid_input_iscd
        }

        res_body, _ = self._tr_request(path, tr_id, params=params)

        if res_body['rt_cd'] != '0':
            raise ValueError(f"Error: ({res_body['msg_cd']}) {res_body['msg1']}")

        output = res_body['output']

        decimal_keys = [
            'marg_rate', 'prdy_ctrt', 'prdy_vrss_vol_rate',
            'wghn_avrg_stck_prc', 'hts_frgn_ehrt', 'per', 'pbr',
            'vol_tnrt', 'eps', 'bps', 'd250_hgpr_vrss_prpr_rate',
            'd250_lwpr_vrss_prpr_rate', 'dryy_hgpr_vrss_prpr_rate',
            'dryy_lwpr_vrss_prpr_rate', 'w52_hgpr_vrss_prpr_ctrt',
            'w52_lwpr_vrss_prpr_ctrt', 'whol_loan_rmnd_rate']

        for k in decimal_keys:
            if k in output and len(output[k]) > 0:
                output[k] = Decimal(output[k])

        int_keys = [
            'stck_prpr', 'prdy_vrss', 'prdy_vrss_sign', 'acml_tr_pbmn',
            'acml_vol', 'stck_oprc', 'stck_hgpr', 'stck_lwpr', 'stck_mxpr',
            'stck_llam', 'stck_sdpr', 'frgn_ntby_qty', 'pgtr_ntby_qty',
            'pvt_scnd_dmrs_prc', 'pvt_frst_dmrs_prc', 'pvt_pont_val',
            'pvt_frst_dmsp_prc', 'pvt_scnd_dmsp_prc', 'dmrs_val',
            'dmsp_val', 'cpfn', 'rstc_wdth_prc', 'stck_fcam', 'stck_sspr',
            'aspr_unit', 'hts_deal_qty_unit_val', 'lstn_stcn', 'hts_avls',
            'stac_month', 'd250_hgpr', 'd250_lwpr', 'stck_dryy_hgpr',
            'stck_dryy_lwpr', 'w52_hgpr', 'w52_lwpr', 'frgn_hldn_qty',
            'last_ssts_cntg_qty']

        for k in int_keys:
            if k in output and len(output[k]) > 0:
                output[k] = int(output[k])

        date_keys = [
            'd250_hgpr_date', 'd250_lwpr_date', 'dryy_hgpr_date',
            'dryy_lwpr_date', 'w52_hgpr_date', 'w52_lwpr_date',
        ]

        for k in date_keys:
            if k in output and len(output[k]) > 0:
                output[k] = dtm.datetime.strptime(output[k], '%Y%m%d').date()

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'],
            'output': output
        }

        return result

    def inquire_ccnl(self,
                     fid_input_iscd: str,
                     fid_cond_mrkt_div_code: str = 'J',
                     tr_cont: str = ""):
        '''
        (국내주식시세) 주식현재가 체결[v1_국내주식-009]

        국내현재가 체결 API 입니다. 종목의 체결 정보를 확인할 수 있습니다.

        Args:
            fid_input_iscd (str): FID 입력종목코드 - 종목번호(6자리) ETN의 경우 Q로 시작(EX. Q500001)
            fid_cond_mrkt_div_code (str): FID 조건시장분류코드 - J:주식,ETF,ETN W:ELW

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - tr_cont (str): 연속조회가능여부
            - output (list): 출력
                - stck_cntg_hour: 주식 체결 시간
                - stck_prpr: 주식 현재가
                - prdy_vrss: 전일 대비
                - prdy_vrss_sign: 전일 대비 부호 - 1:상한 2:상승 3:보합 4:하한 5:하락
                - cntg_vol: 체결 거래량
                - tday_rltv: 당일 체결강도 - 체결거래가 발생하는 시점의 체결강도
                - prdy_ctrt: 전일 대비율

        Raise:
            ValueError: API 에러 발생시
        '''

        path = '/uapi/domestic-stock/v1/quotations/inquire-ccnl'
        tr_id = 'FHKST01010300'
        params = {
            'FID_COND_MRKT_DIV_CODE': fid_cond_mrkt_div_code,
            'FID_INPUT_ISCD': fid_input_iscd
        }

        res_body, res_headers = self._tr_request(path, tr_id, tr_cont, params=params)
        if res_body['rt_cd'] != '0':
            raise ValueError(f"Error: ({res_body['msg_cd']}) {res_body['msg1']}")

        output = []
        for el in res_body['output']:
            decimal_keys = ['tday_rltv', 'prdy_ctrt']
            for k in decimal_keys:
                if k in el and len(el[k]) > 0:
                    el[k] = Decimal(el[k])

            int_keys = ['stck_prpr', 'prdy_vrss', 'prdy_vrss_sign', 'cntg_vol']
            for k in int_keys:
                if k in el and len(el[k]) > 0:
                    el[k] = int(el[k])

            el['stck_cntg_hour'] = dtm.datetime.strptime(el['stck_cntg_hour'], '%H%M%S').time()

            output.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'],
            'output': output
        }

        return result

    def inquire_daily_price(self,
                            fid_input_iscd: str,
                            fid_cond_mrkt_div_code: str = 'J',
                            fid_period_div_code: str ='D',
                            fid_org_adj_prc: str = '0'):
        '''
        (국내주식시세) 주식현재가 일자별[v1_국내주식-010]

        주식현재가 일자별 API입니다. 일/주/월별 주가를 확인할 수 있으며 최근 30일(주,별)로 제한되어 있습니다.

        Args:
            fid_input_iscd (str): FID 입력종목코드 - 종목번호(6자리) ETN의 경우 Q로 시작(EX. Q500001)
            fid_cond_mrkt_div_code (str): FID 조건시장분류코드 - J:주식,ETF,ETN
            fid_period_div_code (str): FID 기간구분코드 - D:일별 W:주별 M:월별
            fid_org_adj_prc (str): FID 조정가구분코드 - 0:무조정 1:조정

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - tr_cont (str): 연속조회가능여부
            - output (list): 출력

                - stck_bsop_date: 주식 영업 일자
                - stck_oprc: 주식 시가
                - stck_hgpr: 주식 최고가
                - stck_lwpr: 주식 최저가
                - stck_clpr: 주식 종가
                - acml_vol: 누적 거래량
                - prdy_vrss_vol_rate: 전일 대비 거래량 비율
                - prdy_vrss: 전일 대비
                - prdy_vrss_sign: 전일 대비 부호 - 1:상한 2:상승 3:보합 4:하한 5:하락
                - prdy_ctrt: 전일 대비율
                - hts_frgn_ehrt: HTS 외국인 소진율
                - frgn_ntby_qty: 외국인 순매수 수량
                - flng_cls_code: 락 구분 코드

                    | 01:권리락
                    | 02:배당락
                    | 03:분배락
                    | 04:권배락
                    | 05:중간(분기)배당락
                    | 06:권리중간배당락
                    | 07:권리분기배당락

                - acml_prtt_rate: 누적 분할 비율

        Raise:
            ValueError: API 에러 발생시
        '''
        url_path = '/uapi/domestic-stock/v1/quotations/inquire-daily-price'
        tr_id = 'FHKST01010400'
        params = {
            'FID_COND_MRKT_DIV_CODE': fid_cond_mrkt_div_code,
            'FID_INPUT_ISCD': fid_input_iscd,
            'FID_PERIOD_DIV_CODE': fid_period_div_code,
            'FID_ORG_ADJ_PRC': fid_org_adj_prc
        }

        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']}")

        output = []
        for el in res_body['output']:
            el['stck_bsop_date'] = dtm.datetime.strptime(el['stck_bsop_date'], '%Y%m%d').date()

            int_keys = ['stck_oprc', 'stck_hgpr', 'stck_lwpr', 'stck_clpr', 'acml_vol', 'prdy_vrss', 'frgn_ntby_qty']
            for k in int_keys:
                if k in el and len(el[k]) > 0:
                    el[k] = int(el[k])

            decimal_keys = ['prdy_vrss_vol_rate', 'prdy_vrss_sign', 'prdy_ctrt', 'hts_frgn_ehrt', 'acml_prtt_rate']
            for k in decimal_keys:
                if k in el and len(el[k]) > 0:
                    el[k] = Decimal(el[k])

            output.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'],
            'output': output,
        }

        return result

    def inquire_asking_price_exp_ccn(self,
                                     fid_input_iscd: str,
                                     fid_cond_mrkt_div_code: str = 'J'):
        '''
        (국내주식시세) 주식현재가 호가/예상체결[v1_국내주식-011]

        주식현재가 호가 예상체결 API입니다. 매수 매도 호가를 확인하실 수 있습니다. 실시간 데이터를 원하신다면 웹소켓 API를 활용하세요.

        Args:
            fid_input_iscd (str): FID 입력종목코드 - 종목번호(6자리) ETN의 경우 Q로 시작(EX. Q500001)
            fid_cond_mrkt_div_code (str): FID 조건시장분류코드 - J:주식,ETF,ETN

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output1 (list): 응답상세1

                - aspr_acpt_hour: 호가 접수 시간
                - askp1: 매도호가1
                - askp2: 매도호가2
                - askp3: 매도호가3
                - askp4: 매도호가4
                - askp5: 매도호가5
                - askp6: 매도호가6
                - askp7: 매도호가7
                - askp8: 매도호가8
                - askp9: 매도호가9
                - askp10: 매도호가10
                - bidp1: 매수호가1
                - bidp2: 매수호가2
                - bidp3: 매수호가3
                - bidp4: 매수호가4
                - bidp5: 매수호가5
                - bidp6: 매수호가6
                - bidp7: 매수호가7
                - bidp8: 매수호가8
                - bidp9: 매수호가9
                - bidp10: 매수호가10
                - askp_rsqn1: 매도호가 잔량1
                - askp_rsqn2: 매도호가 잔량2
                - askp_rsqn3: 매도호가 잔량3
                - askp_rsqn4: 매도호가 잔량4
                - askp_rsqn5: 매도호가 잔량5
                - askp_rsqn6: 매도호가 잔량6
                - askp_rsqn7: 매도호가 잔량7
                - askp_rsqn8: 매도호가 잔량8
                - askp_rsqn9: 매도호가 잔량9
                - askp_rsqn10: 매도호가 잔량10
                - bidp_rsqn1: 매수호가 잔량1
                - bidp_rsqn2: 매수호가 잔량2
                - bidp_rsqn3: 매수호가 잔량3
                - bidp_rsqn4: 매수호가 잔량4
                - bidp_rsqn5: 매수호가 잔량5
                - bidp_rsqn6: 매수호가 잔량6
                - bidp_rsqn7: 매수호가 잔량7
                - bidp_rsqn8: 매수호가 잔량8
                - bidp_rsqn9: 매수호가 잔량9
                - bidp_rsqn10: 매수호가 잔량10
                - askp_rsqn_icdc1: 매도호가 잔량 증감1
                - askp_rsqn_icdc2: 매도호가 잔량 증감2
                - askp_rsqn_icdc3: 매도호가 잔량 증감3
                - askp_rsqn_icdc4: 매도호가 잔량 증감4
                - askp_rsqn_icdc5: 매도호가 잔량 증감5
                - askp_rsqn_icdc6: 매도호가 잔량 증감6
                - askp_rsqn_icdc7: 매도호가 잔량 증감7
                - askp_rsqn_icdc8: 매도호가 잔량 증감8
                - askp_rsqn_icdc9: 매도호가 잔량 증감9
                - askp_rsqn_icdc10: 매도호가 잔량 증감10
                - bidp_rsqn_icdc1: 매수호가 잔량 증감1
                - bidp_rsqn_icdc2: 매수호가 잔량 증감2
                - bidp_rsqn_icdc3: 매수호가 잔량 증감3
                - bidp_rsqn_icdc4: 매수호가 잔량 증감4
                - bidp_rsqn_icdc5: 매수호가 잔량 증감5
                - bidp_rsqn_icdc6: 매수호가 잔량 증감6
                - bidp_rsqn_icdc7: 매수호가 잔량 증감7
                - bidp_rsqn_icdc8: 매수호가 잔량 증감8
                - bidp_rsqn_icdc9: 매수호가 잔량 증감9
                - bidp_rsqn_icdc10: 매수호가 잔량 증감10
                - total_askp_rsqn: 총 매도호가 잔량
                - total_bidp_rsqn: 총 매수호가 잔량
                - total_askp_rsqn_icdc: 총 매도호가 잔량 증감
                - total_bidp_rsqn_icdc: 총 매수호가 잔량 증감
                - ovtm_total_askp_icdc: 시간외 총 매도호가 증감
                - ovtm_total_bidp_icdc: 시간외 총 매수호가 증감
                - ovtm_total_askp_rsqn: 시간외 총 매도호가 잔량
                - ovtm_total_bidp_rsqn: 시간외 총 매수호가 잔량
                - ntby_aspr_rsqn: 순매수 호가 잔량
                - new_mkop_cls_code: 신 장운영 구분 코드

                    - '00':장전 예상체결가와 장마감 동시호가
                    - '49':장후 예상체결가
                    - (1)첫 번째 비트: 1:장개시전 2:장중 3:장종료후 4:시간외단일가 7:일반Buy-in 8:당일Buy-in
                    - (2)두 번째 비트: 0:보통 1:종가 2:대량 3:바스켓 7:정리매매 8:Buy-in

            - output2 (list): 응답상세2
                - antc_mkop_cls_code: 예상 장운영 구분 코드 - 311:예상체결시작 112:예상체결종료
                - stck_prpr: 주식 현재가
                - stck_oprc: 주식 시가
                - stck_hgpr: 주식 최고가
                - stck_lwpr: 주식 최저가
                - stck_sdpr: 주식 기준가
                - antc_cnpr: 예상 체결가
                - antc_cntg_vrss_sign: 예상 체결 대비 부호 - 1:상한 2:상승 3:보합 4:하한 5:하락
                - antc_cntg_vrss: 예상 체결 대비
                - antc_cntg_prdy_ctrt: 예상 체결 전일 대비율
                - antc_vol: 예상 거래량
                - stck_shrn_iscd: 주식 단축 종목코드
                - vi_cls_code: VI적용구분코드

        Raise:
            ValueError: API 에러 발생시
        '''

        url_path = '/uapi/domestic-stock/v1/quotations/inquire-asking-price-exp-ccn'
        tr_id = 'FHKST01010200'
        params = {
            'FID_COND_MRKT_DIV_CODE': fid_cond_mrkt_div_code,
            'FID_INPUT_ISCD': fid_input_iscd
        }

        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 == 'aspr_acpt_hour':
                output1[k] = dtm.datetime.strptime(output1[k], '%H%M%S').time()
            elif k == 'new_mkop_cls_code':
                pass
            else:
                output1[k] = int(output1[k])

        output2 = res_body['output2']
        for k in output2.keys():
            if k in ['antc_mkop_cls_code', 'stck_shrn_iscd', 'vi_cls_code']:
                pass
            elif k == 'antc_cntg_prdy_ctrt':
                output2[k] = Decimal(output2[k])
            else:
                output2[k] = int(output2[k])

        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_daily_itemchartprice(self,
                                     fid_input_iscd: str,
                                     fid_input_date_1: dtm.date,
                                     fid_input_date_2: dtm.date,
                                     fid_period_div_code: str,
                                     fid_cond_mrkt_div_code: str = 'J',
                                     fid_org_adj_prc: str = '0'):
        '''
        (국내주식시세) 국내주식기간별시세(일/주/월/년)[v1_국내주식-016]

        국내주식기간별시세(일/주/월/년) API입니다.
        실전계좌/모의계좌의 경우, 한 번의 호출에 최대 100건까지 확인 가능합니다.

        Args:
            fid_input_iscd (str): FID 입력종목코드 - 종목번호(6자리) ETN의 경우 Q로 시작(EX. Q500001)
            fid_input_date_1 (datetime.date): FID 입력일자1 - 조회 시작일자 (ex. dtm.date(2024, 1, 01))
            fid_input_date_2 (datetime.date): FID 입력일자2 - 조회 종료일자 (ex. dtm.date(2024, 1, 31))
            fid_period_div_code (str): FID 기간구분코드 - D:일별 W:주별 M:월별 Y:년별
            fid_cond_mrkt_div_code (str): FID 조건시장분류코드 - J:주식,ETF,ETN
            fid_org_adj_prc (str): FID 조정가구분코드 - 0:수정주가 1:원주가

        Result:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - tr_cont (str): 연속조회가능여부
            - output1 (object): 응답상세1

                - prdy_vrss: 전일 대비
                - prdy_vrss_sign: 전일 대비 부호
                - prdy_ctrt: 전일 대비율
                - stck_prdy_clpr: 주식 전일 종가
                - acml_vol: 누적 거래량
                - acml_tr_pbmn: 누적 거래 대금
                - hts_kor_isnm: HTS 한글 종목명
                - stck_prpr: 주식 현재가
                - stck_shrn_iscd: 주식 단축 종목코드
                - prdy_vol: 전일 거래량
                - stck_mxpr: 상한가
                - stck_llam: 하한가
                - stck_oprc: 시가
                - stck_hgpr: 최고가
                - stck_lwpr: 최저가
                - stck_prdy_oprc: 주식 전일 시가
                - stck_prdy_hgpr: 주식 전일 최고가
                - stck_prdy_lwpr: 주식 전일 최저가
                - askp: 매도호가
                - bidp: 매수호가
                - prdy_vrss_vol: 전일 대비 거래량
                - vol_tnrt: 거래량 회전율
                - stck_fcam: 주식 액면가
                - lstn_stcn: 상장 주수
                - cpfn: 자본금
                - hts_avls: 시가총액
                - per: PER
                - eps: EPS
                - pbr: PBR
                - itewhol_loan_rmnd_ratem: name	전체 융자 잔고 비율

            - output2: (list): 일별데이터

                - stck_bsop_date: 주식 영업 일자
                - stck_clpr: 주식 종가
                - stck_oprc: 주식 시가
                - stck_hgpr: 주식 최고가
                - stck_lwpr: 주식 최저가
                - acml_vol: 누적 거래량
                - acml_tr_pbmn: 누적 거래 대금
                - flng_cls_code: 락 구분 코드

                    | 00:해당사항없음(락이 발생안한 경우)
                    | 01:권리락
                    | 02:배당락
                    | 03:분배락
                    | 04:권배락
                    | 05:중간(분기)배당락
                    | 06:권리중간배당락
                    | 07:권리분기배당락

                - prtt_rate: 분할 비율
                - mod_yn: 분할변경여부
                - prdy_vrss_sign: 전일 대비 부호
                - prdy_vrss: 전일 대비
                - revl_issu_reas: 재평가사유코드

        Raise:
            ValueError: API 에러 발생시
        '''

        url_path = '/uapi/domestic-stock/v1/quotations/inquire-daily-itemchartprice'
        tr_id = 'FHKST03010100'
        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,
            'FID_ORG_ADJ_PRC': fid_org_adj_prc
        }
        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']

        int_keys = [
            'prdy_vrss', 'prdy_vrss_sign', 'stck_prdy_clpr', 'acml_vol',
            'acml_tr_pbmn', 'stck_prpr', 'prdy_vol', 'stck_mxpr',
            'stck_llam', 'stck_oprc', 'stck_hgpr', 'stck_lwpr',
            'stck_prdy_oprc', 'stck_prdy_hgpr', 'stck_prdy_lwpr',
            'askp', 'bidp', 'prdy_vrss_vol', 'stck_fcam',
            'lstn_stcn', 'cpfn', 'hts_avls']
        for k in int_keys:
            if k in output1 and len(output1[k]) > 0:
                output1[k] = int(output1[k])

        decimal_keys = [
            'prdy_ctrt', 'vol_tnrt', 'per', 'eps', 'pbr',
            'itewhol_loan_rmnd_ratem name'
        ]
        for k in decimal_keys:
            if k in output1 and len(output1[k]) > 0:
                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 in ['mod_yn', 'revl_issu_reas']:
                    pass
                elif k == 'prtt_rate':
                    el[k] = Decimal(el[k])
                else:
                    el[k] = int(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_daily_indexchartprice(self,
                                      fid_input_iscd: str,
                                      fid_input_date_1: dtm.date,
                                      fid_input_date_2: dtm.date,
                                      fid_period_div_code: str):
        '''
        (국내주식시세) 국내주식업종기간별시세(일/주/월/년)[v1_국내주식-021]

        국내주식 업종기간별시세(일/주/월/년) API입니다.
        실전계좌/모의계좌의 경우, 한 번의 호출에 최대 50건까지 확인 가능합니다.

        Args:
            fid_input_iscd (str): 업종상세코드 - 0001:종합 0002:대형주, ... 포탈(FAQ:종목정보 다운로드 - 업종코드 참조)
            fid_input_date_1 (datetime.date): FID 입력일자1 - 조회 시작일자 (ex. dtm.date(2024, 1, 01))
            fid_input_date_2 (datetime.date): FID 입력일자2 - 조회 종료일자 (ex. dtm.date(2024, 1, 31))
            fid_period_div_code (str): FID 기간구분코드 - D:일별 W:주별 M:월별 Y:년별

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output1 (object): 응답상세1

                - BSTP_NMIX_PRDY_VRSS: 업종 지수 전일 대비 - 업종 지수 전일 대비
                - PRDY_VRSS_SIGN: 전일 대비 부호 - 전일 대비 부호
                - BSTP_NMIX_PRDY_CTRT: 업종 지수 전일 대비율 - 업종 지수 전일 대비율
                - PRDY_NMIX: 전일 지수 - 전일 지수
                - ACML_VOL: 누적 거래량 - 누적 거래량
                - ACML_TR_PBMN: 누적 거래 대금 - 누적 거래 대금
                - HTS_KOR_ISNM: HTS 한글 종목명 - HTS 한글 종목명
                - BSTP_NMIX_PRPR: 업종 지수 현재가 - 업종 지수 현재가
                - BSTP_CLS_CODE: 업종 구분 코드 - 업종 구분 코드
                - PRDY_VOL: 전일 거래량 - 전일 거래량
                - BSTP_NMIX_OPRC: 업종 지수 시가 - 업종 지수 시가
                - BSTP_NMIX_HGPR: 업종 지수 최고가 - 업종 지수 최고가
                - BSTP_NMIX_LWPR: 업종 지수 최저가 - 업종 지수 최저가
                - FUTS_PRDY_OPRC: 업종 전일 시가 - 업종 전일 시가
                - FUTS_PRDY_HGPR: 업종 전일 최고가 - 업종 전일 최고가
                - FUTS_PRDY_LWPR: 업종 전일 최저가 - 업종 전일 최저가

            - output2 (list): 응답상세2

                - STCK_BSOP_DATE: 영업 일자 - 영업 일자
                - BSTP_NMIX_PRPR: 업종 지수 현재가 - 업종 지수 현재가
                - BSTP_NMIX_OPRC: 업종 지수 시가 - 업종 지수 시가
                - BSTP_NMIX_HGPR: 업종 지수 최고가 - 업종 지수 최고가
                - BSTP_NMIX_LWPR: 업종 지수 최저가 - 업종 지수 최저가
                - ACML_VOL: 누적 거래량 - 누적 거래량
                - ACML_TR_PBMN: 누적 거래 대금 - 누적 거래 대금
                - MOD_YN: 변경 여부 - 변경 여부

        Raise:
            ValueError: API 에러 발생시

        '''
        url_path = '/uapi/domestic-stock/v1/quotations/inquire-daily-indexchartprice'
        tr_id = 'FHKUP03500100'
        params = {
            'FID_COND_MRKT_DIV_CODE': 'U',
            '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']}")

        output1 = res_body['output1']
        decimal_keys = [
            'bstp_nmix_prdy_vrss', 'bstp_nmix_prdy_ctrt', 'prdy_nmix',
            'bstp_nmix_oprc', 'bstp_nmix_prpr', 'bstp_nmix_hgpr',
            'bstp_nmix_lwpr', 'futs_prdy_oprc', 'futs_prdy_hgpr',
            'futs_prdy_lwpr']
        for k in decimal_keys:
            if k in output1 and len(output1[k]) > 0:
                output1[k] = Decimal(output1[k])

        int_keys = ['prdy_vrss_sign', 'acml_vol', 'acml_tr_pbmn', 'prdy_vol']
        for k in int_keys:
            if k in output1 and len(output1[k]) > 0:
                output1[k] = int(output1[k])

        output2 = []
        for el in res_body['output2']:
            for k in el.keys():
                if k in ['bstp_nmix_prpr', 'bstp_nmix_oprc', 'bstp_nmix_hgpr', 'bstp_nmix_lwpr']:
                    el[k] = Decimal(el[k])
                elif k == 'stck_bsop_date':
                    el[k] = dtm.datetime.strptime(el[k], '%Y%m%d').date()
                elif k in ['acml_vol', 'acml_tr_pbmn']:
                    el[k] = int(el[k])

            output2.append(el)

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'],
            'output1': output1,
            'output2': output2
        }

        return result

    def inquire_time_itemconclusion(self,
                                    fid_input_iscd: str,
                                    fid_input_hour_1: dtm.time,
                                    fid_cond_mrkt_div_code: str = 'J',
                                    tr_cont: str = ''):
        '''
        (국내주식시세) 주식현재가 당일시간대별체결[v1_국내주식-023]

        주식현재가 당일시간대별체결 API입니다.

        Args:
            fid_input_iscd (str): FID 입력종목코드 - 종목번호(6자리) ETN의 경우 Q로 시작(EX. Q500001)
            fid_input_hour_1 (datetime.time): FID 입력시간1 - 기준시간 ex)dtm.time(15, 50, 0) 입력 시 15시 50분 기준 이전 체결내역이 조회됨
            fid_cond_mrkt_div_code (str): FID 조건시장분류코드 - J:주식,ETF,ETN
            tr_cont (str): 연속조회여부

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - tr_cont (str): 연속조회가능여부
            - output1 (object): 응답상세1 - 기본정보

                - stck_prpr: 주식 현재가
                - prdy_vrss: 전일 대비
                - prdy_vrss_sign: 전일 대비 부호
                - prdy_ctrt: 전일 대비율
                - acml_vol: 누적 거래량
                - prdy_vol: 전일 거래량
                - rprs_mrkt_kor_name: 대표 시장 한글명

            - output2 (list): 응답상세2 - 시간대체결 정보

                - stck_cntg_hour: 주식 체결 시간
                - stck_prpr: 주식 현재가
                - prdy_vrss: 전일 대비
                - prdy_vrss_sign: 전일 대비 부호
                - prdy_ctrt: 전일 대비율
                - askp: 매도호가
                - bidp: 매수호가
                - tday_rltv: 당일 체결강도
                - acml_vol: 누적 거래량
                - cnqn: 체결량

        Raise:
            ValueError: API 에러 발생시
        '''

        url_path = '/uapi/domestic-stock/v1/quotations/inquire-time-itemconclusion'
        tr_id = 'FHPST01060000'
        params = {
            'FID_COND_MRKT_DIV_CODE': fid_cond_mrkt_div_code,
            'FID_INPUT_ISCD': fid_input_iscd,
            'FID_INPUT_HOUR_1': fid_input_hour_1.strftime('%H%M%S')
        }

        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 = res_body['output1']
        for k in output1.keys():
            if k == 'rprs_mrkt_kor_name':
                pass
            elif k == 'prdy_ctrt':
                output1[k] = Decimal(output1[k])
            else:
                output1[k] = int(output1[k])

        output2 = []
        for el in res_body['output2']:
            for k in el.keys():
                if k == 'stck_cntg_hour':
                    el[k] = dtm.datetime.strptime(el[k], '%H%M%S').time()
                elif k in ['prdy_ctrt', 'tday_rltv']:
                    el[k] = Decimal(el[k])
                else:
                    el[k] = int(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_time_overtimeconclusion(self,
                                        fid_input_iscd: str,
                                        tr_cont: str = ''):
        '''
        (국내주식시세) 주식현재가 시간외시간별체결[v1_국내주식-025]

        주식현재가 시간외시간별체결 API입니다.

        Args:
            fid_input_iscd (str): FID 입력종목코드 - 종목번호(6자리) ETN의 경우 Q로 시작(EX. Q500001)
            tr_cont (str): 연속조회여부

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - tr_cont (str): 연속조회가능여부
            - output1 (dict): 응답상세1 - 기본정보

                - ovtm_untp_prpr: 시간외 단일가 현재가
                - ovtm_untp_prdy_vrss: 시간외 단일가 전일 대비
                - ovtm_untp_prdy_vrss_sign: 시간외 단일가 전일 대비 부호
                - ovtm_untp_prdy_ctrt: 시간외 단일가 전일 대비율
                - ovtm_untp_vol: 시간외 단일가 거래량
                - ovtm_untp_tr_pbmn: 시간외 단일가 거래 대금
                - ovtm_untp_mxpr: 시간외 단일가 상한가
                - ovtm_untp_llam: 시간외 단일가 하한가
                - ovtm_untp_oprc: 시간외 단일가 시가2
                - ovtm_untp_hgpr: 시간외 단일가 최고가
                - ovtm_untp_lwpr: 시간외 단일가 최저가
                - ovtm_untp_antc_cnpr: 시간외 단일가 예상 체결가
                - ovtm_untp_antc_cntg_vrss: 시간외 단일가 예상 체결 대비
                - ovtm_untp_antc_cntg_vrss_sign: 시간외 단일가 예상 체결 대비
                - ovtm_untp_antc_cntg_ctrt: 시간외 단일가 예상 체결 대비율
                - ovtm_untp_antc_vol: 시간외 단일가 예상 거래량
                - uplm_sign: 상한 부호
                - lslm_sign: 하한 부호

            - output2 (list): 응답상세2 - 시간대별체결 정보

                - stck_cntg_hour: 주식 체결 시간
                - stck_prpr: 주식 현재가
                - prdy_vrss: 전일 대비
                - prdy_vrss_sign: 전일 대비 부호
                - prdy_ctrt: 전일 대비율
                - askp: 매도호가
                - bidp: 매수호가
                - acml_vol: 누적 거래량
                - cntg_vol: 체결 거래량
        Raise:
            ValueError: API 에러 발생시
        '''
        url_path = '/uapi/domestic-stock/v1/quotations/inquire-time-overtimeconclusion'
        tr_id = 'FHPST02310000'
        params = {
            'FID_COND_MRKT_DIV_CODE': 'J',
            'FID_INPUT_ISCD': fid_input_iscd,
            'FID_HOUR_CLS_CODE': '1'
        }
        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 = res_body['output1']
        for k in output1.keys():
            if k in ['ovtm_untp_antc_cntg_ctrt', 'ovtm_untp_prdy_ctrt']:
                output1[k] = Decimal(output1[k])
            else:
                output1[k] = int(output1[k])

        output2 = []
        for el in res_body['output2']:
            for k in el.keys():
                if k == 'prdy_ctrt':
                    el[k] = Decimal(el[k])
                elif k == 'stck_cntg_hour':
                    el[k] = dtm.datetime.strptime(el[k], '%H%M%S').time()
                else:
                    el[k] = int(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_daily_overtimeprice(self, fid_input_iscd: str, tr_cont: str = ''):
        '''
        (국내주식시세) 주식현재가 시간외일자별주가[v1_국내주식-026]

        주식현재가 시간외일자별주가 API입니다.

        Args:
            fid_input_iscd (str): FID 입력종목코드 - 종목번호(6자리) ETN의 경우 Q로 시작(EX. Q500001)

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - tr_cont (str): 연속조회가능여부

            - output1 (dict): 응답상세1 - 기본정보

                - ovtm_untp_prpr: 시간외 단일가 현 재가
                - ovtm_untp_prdy_vrss: 시간외 단일가 전일 대비
                - ovtm_untp_prdy_vrss_sign: 시간외 단일가 전일 대비 부호
                - ovtm_untp_prdy_ctrt: 시간외 단일가 전일 대비율
                - ovtm_untp_vol: 시간외 단일가 거래량
                - ovtm_untp_tr_pbmn: 시간외 단일가 거래 대금
                - ovtm_untp_mxpr: 시간외 단일가 상한가
                - ovtm_untp_llam: 시간외 단일가 하한가
                - ovtm_untp_oprc: 시간외 단일가 시가2
                - ovtm_untp_hgpr: 시간외 단일가 최고가
                - ovtm_untp_lwpr: 시간외 단일가 최저가
                - ovtm_untp_antc_cnpr: 시간외 단일가 예상 체결가
                - ovtm_untp_antc_cntg_vrss: 시간외 단일가 예상 체결 대비
                - ovtm_untp_antc_cntg_vrss_sign: 시간외 단일가 예상 체결 대비
                - ovtm_untp_antc_cntg_ctrt: 시간외 단일가 예상 체결 대비율
                - ovtm_untp_antc_vol: 시간외 단일가 예상 거래량

            - output2 (list): 응답상세2 - 일자별 정보

                - stck_bsop_date: 주식 영업 일자
                - ovtm_untp_prpr: 시간외 단일가 현재가
                - ovtm_untp_prdy_vrss: 시간외 단일가 전일 대비
                - ovtm_untp_prdy_vrss_sign: 시간외 단일가 전일 대비 부호
                - ovtm_untp_prdy_ctrt: 시간외 단일가 전일 대비율
                - ovtm_untp_vol: 시간외 단일가 거래량
                - stck_clpr: 주식 종가
                - prdy_vrss: 전일 대비
                - prdy_vrss_sign: 전일 대비 부호
                - prdy_ctrt: 전일 대비율
                - acml_vol: 누적 거래량
                - ovtm_untp_tr_pbmn: 시간외 단일가 거래대금

        Raise:
            ValueError: API 에러 발생시
        '''

        url_path = '/uapi/domestic-stock/v1/quotations/inquire-daily-overtimeprice'
        tr_id = 'FHPST02320000'

        params = {
            'FID_COND_MRKT_DIV_CODE': 'J',
            'FID_INPUT_ISCD': fid_input_iscd
        }

        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 = res_body['output1']
        for k in output1.keys():
            if k in ['ovtm_untp_antc_cntg_ctrt', 'ovtm_untp_prdy_ctrt']:
                output1[k] = Decimal(output1[k])
            else:
                output1[k] = int(output1[k])

        output2 = []
        for el in res_body['output2']:
            for k in el.keys():
                if k in ['prdy_ctrt', 'ovtm_untp_prdy_ctrt']:
                    el[k] = Decimal(el[k])
                else:
                    el[k] = int(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': res_body['output2']
        }

        return result

    def inquire_time_itemchartprice(self,
                                    fid_input_iscd: str,
                                    fid_input_hour_1: dtm.time|int,
                                    fid_cond_mrkt_div_code: str = 'J',
                                    fid_pw_data_incu_yn: str = 'Y'):
        '''
        (국내주식시세) 주식당일분봉조회[v1_국내주식-022]

        주식당일분봉조회 API입니다.
        실전계좌/모의계좌의 경우, 한 번의 호출에 최대 30건까지 확인 가능합니다.

        Args:
            fid_input_iscd (str): FID 입력종목코드 - 종목번호(6자리) ETN의 경우 Q로 시작(EX. Q500001)
            fid_input_hour_1 (datetime.date|int) - 조회대상(FID_COND_MRKT_DIV_CODE)에 따라 입력하는 값 상이
              | 종목(J)일 경우, 조회 시작일자(HHMMSS)
              | ex) "123000" 입력 시 12시 30분 이전부터 1분 간격으로 조회
              |
              | 업종(U)일 경우, 조회간격(초) (60 or 120 만 입력 가능)
              | ex) "60" 입력 시 현재시간부터 1분간격으로 조회
              | "120" 입력 시 현재시간부터 2분간격으로 조회
              |
              | ※ FID_INPUT_HOUR_1 에 미래일시 입력 시에 현재가로 조회됩니다.
              | ex) 오전 10시에 113000 입력 시에 오전 10시~11시30분 사이의 데이터가 오전 10시 값으로 조회됨
            fid_cond_mrkt_div_code (str): FID 조건시장분류코드 - J:주식,ETF,ETN U:업종
            fid_pw_data_incu_yn (str): FID 과거 데이터 포함 여부 - N:당일데이터만조회 Y:과거데이터포함조회

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1

            - output1 (dict): 응답상세1 - 기본정보

                - prdy_vrss: 전일 대비
                - prdy_vrss_sign: 전일 대비 부호
                - prdy_ctrt: 전일 대비율
                - stck_prdy_clpr: 주식 전일 종가
                - acml_vol: 누적 거래량
                - acml_tr_pbmn: 누적 거래 대금
                - hts_kor_isnm: HTS 한글 종목명
                - stck_prpr: 주식 현재가

            - output2 (list): 응답상세2 - 조회결과 상세

                - stck_bsop_date: 주식 영업 일자
                - stck_cntg_hour: 주식 체결 시간
                - acml_tr_pbmn: 누적 거래 대금
                - stck_prpr: 주식 현재가
                - stck_oprc: 주식 시가2
                - stck_hgpr: 주식 최고가
                - stck_lwpr: 주식 최저가
                - cntg_vol: 체결 거래량

        Raise:
            ValueError: API 에러 발생시
        '''

        assert fid_cond_mrkt_div_code in ['J', 'U'], 'fid_cond_mrkt_div_code must be "J" or "U"'
        assert fid_pw_data_incu_yn in ['Y', 'N'], 'fid_pw_data_incu_yn must be "Y" or "N"'
        assert fid_cond_mrkt_div_code == 'J' and isinstance(fid_input_hour_1, dtm.time) or \
               fid_cond_mrkt_div_code == 'U' and isinstance(fid_input_hour_1, int), 'fid_input_hour_1 type mismatch'
        if type(fid_input_hour_1) == int:
            assert fid_input_hour_1 in [60, 120], 'fid_input_hour_1 must be 60 or 120'

        url_path = '/uapi/domestic-stock/v1/quotations/inquire-time-itemchartprice'
        tr_id = 'FHKST03010200'
        params = {
            'FID_ETC_CLS_CODE': '',
            'FID_COND_MRKT_DIV_CODE': fid_cond_mrkt_div_code,
            'FID_INPUT_ISCD': fid_input_iscd,
            'FID_INPUT_HOUR_1': fid_input_hour_1.strftime('%H%M%S') if isinstance(fid_input_hour_1, dtm.time) else str(fid_input_hour_1),
            'FID_PW_DATA_INCU_YN': fid_pw_data_incu_yn
        }

        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 == 'hts_kor_isnm':
                pass
            elif k == 'prdy_ctrt':
                output1[k] = Decimal(output1[k])
            else:
                output1[k] = int(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':
                    el[k] = dtm.datetime.strptime(el[k], '%H%M%S').time()
                else:
                    el[k] = int(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 search_info(self,
                    pdno: str,
                    prdt_type_cd: str):
        '''
        (국내주식시세) 상품기본조회[v1_국내주식-029]

        Args:
            pdno (str): 상품번호

              | 주식(하이닉스):000660 (코드:300)
              | 선물(101S12):KR4101SC0009 (코드:301)
              | 미국(AAPL):AAPL (코드:512)

            prdt_type_cd (str): 상품유형코드

              | '300':주식
              | '301':선물옵션
              | '302':채권
              | '512':미국 나스닥 / 513 미국 뉴욕 / 529 미국 아멕스
              | '515':일본
              | '501':홍콩 / 543 홍콩CNY / 558 홍콩USD
              | '507':베트남 하노이 / 508 베트남 호치민
              | '551':중국 상해A / 552 중국 심천A

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output (dict): 응답상세

                - pdno: 상품번호
                - prdt_type_cd: 상품유형코드
                - prdt_name: 상품명
                - prdt_name120: 상품명120
                - prdt_abrv_name: 상품약어명
                - prdt_eng_name: 상품영문명
                - prdt_eng_name120: 상품영문명120
                - prdt_eng_abrv_name: 상품영문약어명
                - std_pdno: 표준상품번호
                - shtn_pdno: 단축상품번호
                - prdt_sale_stat_cd: 상품판매상태코드
                - prdt_risk_grad_cd: 상품위험등급코드
                - prdt_clsf_cd: 상품분류코드
                - prdt_clsf_name: 상품분류명
                - sale_strt_dt: 판매시작일자
                - sale_end_dt: 판매종료일자
                - wrap_asst_type_cd: 랩어카운트자산유형코드
                - ivst_prdt_type_cd: 투자상품유형코드
                - ivst_prdt_type_cd_name: 투자상품유형코드명
                - frst_erlm_dt: 최초등록일자

        Raise:
            ValueError: API 에러 발생시
        '''
        assert self.auth.paper_trading == False, '실전계좌에서만 사용 가능한 API입니다.'
        assert prdt_type_cd in ['300', '301', '302', '512', '513', '529', '515', '501', '543', '558', '507', '508', '551', '552'], 'unknown prdt_type_cd'

        url_path = '/uapi/domestic-stock/v1/quotations/search-info'
        tr_id = 'CTPF1604R'

        params = {
            'pdno': pdno,
            'prdt_type_cd': prdt_type_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']}")

        output = res_body['output']

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'],
            'output': output
        }

        return result

    def chk_holiday(self, base_dt: dtm.date, tr_cont: str = ''):
        '''
        (국내주식시세) 휴일여부조회[v1_국내주식-030]

        국내휴장일조회 API입니다.
        영업일, 거래일, 개장일, 결제일 여부를 조회할 수 있습니다.
        주문을 넣을 수 있는지 확인하고자 하실 경우 개장일여부(opnd_yn)을 사용하시면 됩니다.

        Args:
            base_dt (datetime.date): 기준일자.
            tr_cont (str): 연속조회여부

        Returns:
            dict:

            - rt_cd (str): 응답코드.
            - msg_cd (str): 메시지코드.
            - msg1 (str): 메시지1.
            - output (list): 응답상세.

                - bass_dt (datetime.date): 기준일자
                - wday_dvsn_cd (str): 요일구분코드 - 01:일요일, 02:월요일, 03:화요일, 04:수요일, 05:목요일, 06:금요일, 07:토요일
                - bzdy_yn (bool): 영업일여부 - 금융기관이 업무를 하는 날
                - tr_day_yn (bool): 거래일여부 - 증권 업무가 가능한 날(입출금, 이체 등의 업무 포함)
                - opnd_yn (bool): 개장일여부 - 주식시장이 개장되는 날. 주문을 넣고자 할 경우 개장일여부(opnd_yn)를 사용
                - sttl_day_yn (bool): 결제일여부 - 주식 거래에서 실제로 주식을 인수하고 돈을 지불하는 날

        Raise:
            ValueError: API 에러 발생시
        '''

        assert self.auth.paper_trading == False, '실전계좌에서만 사용 가능한 API입니다.'

        url_path = '/uapi/domestic-stock/v1/quotations/chk-holiday'
        tr_id = 'CTCA0903R'
        params = {
            'BASS_DT': base_dt.strftime('%Y%m%d'),
            'CTX_AREA_NK': '',
            'CTX_AREA_FK': '',
        }
        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']}")

        output = []
        for el in res_body['output']:
            el['bass_dt'] = dtm.datetime.strptime(el['bass_dt'], '%Y%m%d').date()
            for k in el.keys():
                if k in ['wday_dvsn_cd', 'bzdy_yn', 'tr_day_yn', 'opnd_yn', 'sttl_day_yn']:
                    el[k] = True if el[k] == 'Y' else False
            output.append(el)

        result = {
            'rt_cd': res_body['rt_cd'],
            'tr_cont': res_headers['tr_cont'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'],
            'output': output
        }

        return result

    def get_foreign_institution_total(self,
                                      fid_input_iscd: str,
                                      fid_div_cls_code: str,
                                      fid_rank_sort_cls_code: str,
                                      fid_etc_cls_code: str,
                                      tr_cont: str = ''):
        '''
        (국내주식시세) 국내기관_외국인 매매종목가집계[국내주식-037]

        국내기관_외국인 매매종목가집계 API입니다.

        증권사 직원이 장중에 집계/입력한 자료를 단순 누계한 수치로서,
        입력시간은 외국인 09:30, 11:20, 13:20, 14:30 / 기관종합 10:00, 11:20, 13:20, 14:30 이며 사정에 따라 변동될 수 있습니다.

        Args:
            fid_input_iscd (str): 입력 종목코드 - 0000:전체, 0001:코스피, 1001:코스닥, ... 포탈 (FAQ : 종목정보 다운로드 - 업종코드 참조)
            fid_div_cls_code (str): 분류 구분 코드 - 0: 수량정열, 1: 금액정열
            fid_rank_sort_cls_code (str): 순위 정렬 구분 코드 - 0: 순매수상위, 1: 순매도상위
            fid_etc_cls_code (str): 기타 구분 정렬 - 0:전체 1:외국인 2:기관계 3:기타
            tr_cont (str): 연속조회여부

        Returns:
            dict

            - rt_cd (str): 응답코드
            - tr_cont (str): 연속조회가능여부
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output (list): 응답상세

                - hts_kor_isnm: HTS 한글 종목명
                - mksc_shrn_iscd: 유가증권 단축 종목코드
                - ntby_qty: 순매수 수량
                - stck_prpr: 주식 현재가
                - prdy_vrss_sign: 전일 대비 부호
                - prdy_vrss: 전일 대비
                - prdy_ctrt: 전일 대비율
                - acml_vol: 누적 거래량
                - frgn_ntby_qty: 외국인 순매수 수량
                - orgn_ntby_qty: 기관계 순매수 수량
                - ivtr_ntby_qty: 투자신탁 순매수 수량
                - bank_ntby_qty: 은행 순매수 수량
                - insu_ntby_qty: 보험 순매수 수량
                - mrbn_ntby_qty: 종금 순매수 수량
                - fund_ntby_qty: 기금 순매수 수량
                - etc_orgt_ntby_vol: 기타 단체 순매수 거래량
                - etc_corp_ntby_vol: 기타 법인 순매수 거래량
                - frgn_ntby_tr_pbmn: 외국인 순매수 거래 대금 - frgn_ntby_tr_pbmn ~ etc_corp_ntby_tr_pbmn (단위 : 백만원, 수량*현재가)
                - orgn_ntby_tr_pbmn: 기관계 순매수 거래 대금
                - ivtr_ntby_tr_pbmn: 투자신탁 순매수 거래 대금
                - bank_ntby_tr_pbmn: 은행 순매수 거래 대금
                - insu_ntby_tr_pbmn: 보험 순매수 거래 대금
                - mrbn_ntby_tr_pbmn: 종금 순매수 거래 대금
                - fund_ntby_tr_pbmn: 기금 순매수 거래 대금
                - etc_orgt_ntby_tr_pbmn: 기타 단체 순매수 거래 대금
                - etc_corp_ntby_tr_pbmn: 기타 법인 순매수 거래 대금

        Raise:
            ValueError: API 에러 발생시
        '''

        assert self.auth.paper_trading == False, '실전계좌에서만 사용 가능한 API입니다.'
        assert fid_div_cls_code in ['0', '1'], 'fid_div_cls_code must be "0" or "1"'
        assert fid_rank_sort_cls_code in ['0', '1'], 'fid_rank_sort_cls_code must be "0" or "1"'
        assert fid_etc_cls_code in ['0', '1', '2', '3'], 'fid_etc_cls_code must be "0", "1", "2" or "3"'

        url_path = '/uapi/domestic-stock/v1/quotations/foreign-institution-total'
        tr_id = 'FHPTJ04400000'

        params = {
            'FID_COND_MRKT_DIV_CODE': 'V',
            'FID_COND_SCR_DIV_CODE': '16449',
            'FID_INPUT_ISCD': fid_input_iscd,
            'FID_DIV_CLS_CODE': fid_div_cls_code,
            'FID_RANK_SORT_CLS_CODE': fid_rank_sort_cls_code,
            'FID_ETC_CLS_CODE': fid_etc_cls_code
        }

        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']}")

        output = []
        for el in res_body['output']:
            for k in el.keys():
                if k == 'prdy_ctrt':
                    el[k] = Decimal(el[k])
                elif k == 'hts_kor_isnm':
                    pass
                else:
                    el[k] = int(el[k])
            output.append(el)

        result = {
            'rt_cd': res_body['rt_cd'],
            'tr_cont': res_headers['tr_cont'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'],
            'output': output
        }

        return result

    def get_stock_condition_search_list(self, user_id: str, tr_cont: str = ""):
        """
        (국내주식시세) 종목조건검색 목록조회[국내주식-038]

        HTS(efriend Plus) [0110] 조건검색에서 등록 및 서버저장한 나의 조건 목록을 확인할 수 있는 API입니다.
        종목조건검색 목록조회 API(/uapi/domestic-stock/v1/quotations/psearch-title)의 output인 'seq'을 종목조건검색조회 API(/uapi/domestic-stock/v1/quotations/psearch-result)의 input으로 사용하시면 됩니다.

        ※ 시스템 안정성을 위해 API로 제공되는 조건검색 결과의 경우 조건당 100건으로 제한을 둔 점 양해 부탁드립니다.

        ※ [0110] 화면의 '대상변경' 설정사항은 HTS [0110] 사용자 조건검색 화면에만 적용됨에 유의 부탁드립니다.

        ※ '조회가 계속 됩니다. (다음을 누르십시오.)' 오류 발생 시 해결방법
        → HTS(efriend Plus) [0110] 조건검색 화면에서 조건을 등록하신 후, 왼쪽 하단의 "사용자조건 서버저장" 클릭하셔서 등록한 조건들을 서버로 보낸 후 다시 API 호출 시도 부탁드립니다.


        Args:
            user_id (str): 사용자 HTS ID
            tr_cont (str): 연속조회여부

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - tr_cont (str): 연속조회가능여부
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output (list): 응답상세

                - seq (str): 조건키값 - 해당 값을 종목조건검색조회 API의 input으로 사용 (0번부터 시작)
                - grp_nm (str): 그룹명 - HTS(eFriend Plus) [0110] "사용자조건검색"화면을 통해 등록한 사용자조건 그룹
                - condition_nm (str): 조건명 - 등록한 사용자 조건명

        Raise:
            ValueError: API 에러 발생시
        """
        assert self.auth.paper_trading == False, "실전계좌에서만 사용 가능한 API입니다."

        url_path = "/uapi/domestic-stock/v1/quotations/psearch-title"
        tr_id = "HHKST03900300"
        params = {"user_id": user_id}

        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']}")

        output = []
        for el in res_body["output2"]:
            output.append(el)

        result = {
            "rt_cd": res_body["rt_cd"],
            "tr_cont": res_headers["tr_cont"],
            "msg_cd": res_body["msg_cd"],
            "msg1": res_body["msg1"],
            "output": output,
        }

        return result

    def get_stock_condition_search_results(
        self, user_id: str, seq: str, tr_cont: str = ""
    ):
        """
        (국내주식시세) 종목조건검색조회 [국내주식-039]

        HTS(efriend Plus) [0110] 조건검색에서 등록 및 서버저장한 나의 조건 목록을 확인할 수 있는 API입니다.
        종목조건검색 목록조회 API(/uapi/domestic-stock/v1/quotations/psearch-title)의 output인 'seq'을 종목조건검색조회 API(/uapi/domestic-stock/v1/quotations/psearch-result)의 input으로 사용하시면 됩니다.

        ※ 시스템 안정성을 위해 API로 제공되는 조건검색 결과의 경우 조건당 100건으로 제한을 둔 점 양해 부탁드립니다.

        ※ [0110] 화면의 '대상변경' 설정사항은 HTS [0110] 사용자 조건검색 화면에만 적용됨에 유의 부탁드립니다.

        ※ '조회가 계속 됩니다. (다음을 누르십시오.)' 오류 발생 시 해결방법
        → HTS(efriend Plus) [0110] 조건검색 화면에서 조건을 등록하신 후, 왼쪽 하단의 "사용자조건 서버저장" 클릭하셔서 등록한 조건들을 서버로 보낸 후 다시 API 호출 시도 부탁드립니다.

        ※ {"rt_cd":"1","msg_cd":"MCA05918","msg1":"종목코드 오류입니다."} 메시지 발생 이유
        → 조건검색 결과 검색된 종목이 0개인 경우 위 응답값을 수신하게 됩니다.

        Args:
            user_id (str): 사용자 HTS ID
            seq (str): 사용자조건 키값 - 종목조건검색 목록조회 API의 output인 'seq'값을 사용 (0번부터 시작)
            tr_cont (str): 연속조회여부

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - tr_cont (str): 연속조회가능여부
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output (list): 응답상세

                - code (str): 종목코드
                - name (str): 종목명
                - daebi (int): 전일대비부호 (1:상한 2:상승 3:보합 4:하한 5:하락)
                - price (int): 현재가
                - chgrate (Decimal): 등락율
                - acml_vol (Decimal): 거래량
                - trade_amt (Decimal): 거래대금
                - change (Decimal): 전일대비
                - cttr (Decimal): 체결강도
                - open (Decimal): 시가
                - high (Decimal): 고가
                - low (Decimal): 저가
                - high52 (Decimal): 52주최고가
                - low52 (Decimal): 52주최저가
                - expprice (Decimal): 예상체결가
                - expchange (Decimal): 예상대비
                - expchggrate (Decimal): 예상등락률
                - expcvol (Decimal): 예상체결수량
                - chgrate2 (Decimal): 전일거래량대비율
                - expdaebi (int): 예상대비부호
                - recprice (Decimal): 기준가
                - uplmtprice (Decimal): 상한가
                - dnlmtprice (Decimal): 하한가
                - stotprice (Decimal): 시가총액
        """
        url_path = "/uapi/domestic-stock/v1/quotations/psearch-result"
        tr_id = "HHKST03900400"

        params = {
            "user_id": user_id,
            "seq": seq,
        }

        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']}")

        output = []
        for el in res_body["output2"]:
            for k in el.keys():
                if el[k] is None or len(el[k]) == 0:
                    pass
                elif k in ["code", "name"]:
                    pass
                elif k in ["daebi", "expdaebi"]:
                    el[k] = int(el[k])
                else:
                    el[k] = Decimal(el[k])
            output.append(el)

        result = {
            "rt_cd": res_body["rt_cd"],
            "tr_cont": res_headers["tr_cont"],
            "msg_cd": res_body["msg_cd"],
            "msg1": res_body["msg1"],
            "output": output,
        }

        return result

    def get_program_trade_by_stock(self, fid_input_iscd: str, tr_cont: str = ''):
        '''
        (국내주식시세) 종목별 프로그램매매추이(체결)[v1_국내주식-044]

        국내주식 종목별 프로그램매매추이(체결) API입니다.

        한국투자 HTS(eFriend Plus) > [0465] 종목별 프로그램 매매추이 화면(혹은 한국투자 MTS > 국내 현재가 > 기타수급 > 프로그램) 의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.

        Args:
            fid_input_iscd (str): 입력 종목코드 - 종목번호(6자리) ETN의 경우 Q로 시작(EX. Q500001)
            tr_cont (str): 연속조회여부

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - tr_cont (str): 연속조회가능여부
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output (list): 응답상세

                - bsop_hour: 영업 시간
                - stck_prpr: 주식 현재가
                - prdy_vrss: 전일 대비
                - prdy_vrss_sign: 전일 대비 부호
                - prdy_ctrt: 전일 대비율
                - acml_vol: 누적 거래량
                - whol_smtn_seln_vol: 전체 합계 매도 거래량
                - whol_smtn_shnu_vol: 전체 합계 매수2 거래량
                - whol_smtn_ntby_qty: 전체 합계 순매수 수량
                - whol_smtn_seln_tr_pbmn: 전체 합계 매도 거래 대금
                - whol_smtn_shnu_tr_pbmn: 전체 합계 매수2 거래 대금
                - whol_smtn_ntby_tr_pbmn: 전체 합계 순매수 거래 대금
                - whol_ntby_vol_icdc: 전체 순매수 거래량 증감
                - whol_ntby_tr_pbmn_icdc: 전체 순매수 거래 대금 증감

        Raise:
            ValueError: API 에러 발생시
        '''
        assert self.auth.paper_trading == False, '실전계좌에서만 사용 가능한 API입니다.'

        url_path = '/uapi/domestic-stock/v1/quotations/program-trade-by-stock'
        tr_id = 'FHPPG04650100'

        params = {
            'FID_INPUT_ISCD': fid_input_iscd
        }

        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']}")

        output = []
        for el in res_body['output']:
            for k in el.keys():
                if k in ['prdy_ctrt']:
                    el[k] = Decimal(el[k])
                elif k == 'bsop_hour':
                    el[k] = dtm.datetime.strptime(el[k], '%H%M%S').time()
                else:
                    el[k] = int(el[k])
            output.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'],
            'output': output,
        }

        return result

    def get_volume_rank(self,
                        fid_input_iscd: str,
                        fid_div_cls_code: str,
                        fid_blng_cls_code: str,
                        fid_trgt_cls_code: str,
                        fid_trgt_excls_cls_code: str,
                        fid_input_price_1: int = None,
                        fid_input_price_2: int = None,
                        fid_vol_cnt: int = None):
        '''
        (국내주식시세) 거래량순위[v1_국내주식-047]

        국내주식 거래량순위 API입니다.

        한국투자 HTS(eFriend Plus) > [0171] 거래량 순위 화면의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.

        최대 30건 확인 가능하며, 다음 조회가 불가합니다.
        +30건 이상의 목록 조회가 필요한 경우, 대안으로 종목조건검색 API를 이용해서 원하는 종목 100개까지 검색할 수 있는 기능을 제공하고 있습니다.

        종목조건검색 API는 HTS(efriend Plus) [0110] 조건검색에서 등록 및 서버저장한 나의 조건 목록을 확인할 수 있는 API로,
        HTS [0110]에서 여러가지 조건을 설정할 수 있는데, 그 중 거래량 순위(ex. 0봉전 거래량 상위순 100종목) 에 대해서도 설정해서 종목을 검색할 수 있습니다.

        자세한 사용 방법은 공지사항 - [조건검색 필독] 조건검색 API 이용안내 참고 부탁드립니다.

        Args:
            fid_input_iscd (str): 입력 종목코드 0000(전체) 기타(업종코드)
            fid_div_cls_code (str): 분류 구분 코드 0:전체 1:보통주 2:우선주
            fid_blng_cls_code (str): 소속 구분 코드 0:평균거래량 1:거래증가율 2:평균거래회전율 3:거래금액순 4:평균거래금액회전율
            fid_trgt_cls_code (str): 대상 구분 코드

              | 1 or 0 9자리 (차례대로 증거금 30% 40% 50% 60% 100% 신용보증금 30% 40% 50% 60%)
              | ex) "111111111"

            fid_trgt_exls_cls_code (str): 대상 제외 구분 코드

              | 1 or 0 6자리 (차례대로 투자위험/경고/주의 관리종목 정리매매 불성실공시 우선주 거래정지)
              | ex) "000000"

            fid_input_price_1 (int): 입력 가격1 - 가격 ~

              | ex) 0
              | 전체 가격 대상 조회 시 FID_INPUT_PRICE_1, FID_INPUT_PRICE_2 모두 None

            fid_input_price_2 (int): 입력 가격2 - ~ 가격

              | ex) 1000000
              | 전체 가격 대상 조회 시 FID_INPUT_PRICE_1, FID_INPUT_PRICE_2 모두 None

            fid_vol_cnt (int): 거래량 수 - 거래량 ~

              | ex) 100000
              | 전체 거래량 대상 조회 시 FID_VOL_CNT None

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output (list): 응답상세

                - hts_kor_isnm: HTS 한글 종목명
                - mksc_shrn_iscd: 유가증권 단축 종목코드
                - data_rank: 데이터 순위
                - stck_prpr: 주식 현재가
                - prdy_vrss_sign: 전일 대비 부호
                - prdy_vrss: 전일 대비
                - prdy_ctrt: 전일 대비율
                - acml_vol: 누적 거래량
                - prdy_vol: 전일 거래량
                - lstn_stcn: 상장 주수
                - avrg_vol: 평균 거래량
                - n_befr_clpr_vrss_prpr_rate: N일전종가대비현재가대비율
                - vol_inrt: 거래량증가율
                - vol_tnrt: 거래량 회전율
                - nday_vol_tnrt: N일 거래량 회전율
                - avrg_tr_pbmn: 평균 거래 대금
                - tr_pbmn_tnrt: 거래대금회전율
                - nday_tr_pbmn_tnrt: N일 거래대금 회전율
                - acml_tr_pbmn: 누적 거래 대금

        Raise:
            ValueError: API 에러 발생시
        '''
        assert self.auth.paper_trading == False, '실전계좌에서만 사용 가능한 API입니다.'
        assert fid_div_cls_code in ['0', '1'], 'fid_div_cls_code must be "0" or "1"'
        assert fid_blng_cls_code in ['0', '1', '2', '3', '4'], 'fid_blng_cls_code must be "0", "1", "2", "3" or "4"'
        assert len(fid_trgt_cls_code) == 9, 'fid_trgt_cls_code length must be 9'
        assert all([x in ['0', '1'] for x in fid_trgt_cls_code]), 'fid_trgt_cls_code must be "0" or "1"'
        assert len(fid_trgt_excls_cls_code) == 6, 'fid_trgt_excls_cls_code length must be 6'
        assert all([x in ['0', '1'] for x in fid_trgt_excls_cls_code]), 'fid_trgt_excls_cls_code must be "0" or "1"'
        assert fid_input_price_1 is None or isinstance(fid_input_price_1, int), 'fid_input_price_1 must be None or int'
        assert fid_input_price_2 is None or isinstance(fid_input_price_2, int), 'fid_input_price_2 must be None or int'
        assert fid_vol_cnt is None or isinstance(fid_vol_cnt, int), 'fid_vol_cnt must be None or int'

        url_path = '/uapi/domestic-stock/v1/quotations/volume-rank'
        tr_id = 'FHPST01710000'
        params = {
            'FID_COND_MRKT_DIV_CODE': 'J',
            'FID_COND_SCR_DIV_CODE': '20171',
            'FID_INPUT_ISCD': fid_input_iscd,
            'FID_DIV_CLS_CODE': fid_div_cls_code,
            'FID_BLNG_CLS_CODE': fid_blng_cls_code,
            'FID_TRGT_CLS_CODE': fid_trgt_cls_code,
            'FID_TRGT_EXLS_CLS_CODE': fid_trgt_excls_cls_code,
            'FID_INPUT_PRICE_1': '' if fid_input_price_1 is None else int(fid_input_price_1),
            'FID_INPUT_PRICE_2': '' if fid_input_price_2 is None else int(fid_input_price_2),
            'FID_VOL_CNT': '' if fid_vol_cnt is None else int(fid_vol_cnt),
            'FID_INPUT_DATE_1': '0',
        }
        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']}")

        output = []
        for el in res_body['output']:
            for k in el.keys():
                if k in ['hts_kor_isnm', 'mksc_shrn_iscd']:
                    pass
                elif k in ['prdy_ctrt', 'n_befr_clpr_vrss_prpr_rate', 'vol_inrt', 'vol_tnrt', 'nday_vol_tnrt', 'tr_pbmn_tnrt', 'nday_tr_pbmn_tnrt']:
                    el[k] = Decimal(el[k])
                else:
                    el[k] = int(el[k])
            output.append(el)

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'],
            'output': output
        }

        return result

    def get_investor_trend_estimate(self, mksc_shrn_iscd: str):
        '''
        (국내주식시세) 종목별 외인기관 추정가집계[v1_국내주식-046]

        국내주식 종목별 외국인, 기관 추정가집계 API입니다.

        한국투자 MTS > 국내 현재가 > 투자자 > 투자자동향 탭 > 왼쪽구분을 '추정(주)'로 선택 시 확인 가능한 데이터를 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.

        증권사 직원이 장중에 집계/입력한 자료를 단순 누계한 수치로서,
        입력시간은 외국인 09:30, 11:20, 13:20, 14:30 / 기관종합 10:00, 11:20, 13:20, 14:30 이며, 사정에 따라 변동될 수 있습니다.

        Args:
            mksc_shrn_iscd (str): 종목코드

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output (list): 응답상세

                - bsop_hour_gb: 입력구분 - 1:09시30분 입력 2:10시00분 입력 3:11시20분 입력 4:13시20분 입력 5:14시30분 입력
                - acml_tr_pbmn: 누적 거래 대금
                - stck_prpr: 주식 현재가
                - stck_oprc: 주식 시가2
                - stck_hgpr: 주식 최고가
                - stck_lwpr: 주식 최저가
                - cntg_vol: 체결 거래량

        Raise:
            ValueError: API 에러 발생시
        '''

        assert self.auth.paper_trading == False, '실전계좌에서만 사용 가능한 API입니다.'

        url_path = '/uapi/domestic-stock/v1/quotations/investor-trend-estimate'
        tr_id = 'HHPTJ04160200'
        params = {
            'MKSC_SHRN_ISCD': mksc_shrn_iscd
        }

        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']}")

        output = []
        for el in res_body['output2']:
            for k in el.keys():
                if k == 'bsop_hour_gb':
                    pass
                else:
                    el[k] = int(el[k])
            output.append(el)

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'],
            'output': res_body['output2']
        }

        return result

    def inquire_time_indexchartprice(self,
                                     fid_etc_cls_code: str,
                                     fid_input_iscd: str,
                                     fid_input_hour_1: int,
                                     fid_pw_data_incu_yn: str,
                                     tr_cont: str = ''):
        '''
        (국내주식시세) 업종 분봉조회[v1_국내주식-045]

        업종분봉조회 API입니다.
        실전계좌의 경우, 한 번의 호출에 최대 102건까지 확인 가능합니다.

        Args:
            fid_etc_cls_code (str): 기타 구분 코드 - 0:기본 1:장마감,시간외 제외
            fid_input_iscd (str): 입력 종목코드 - 0001:종합, 1001:코스닥종합
            fid_input_hour_1 (int): 입력 시간1 - 30,60->1분 600->10분 3600->1시간
            fid_pw_data_incu_yn (str): 과거 데이터 포함 여부 - Y:과거 N:당일
            tr_cont (str): 연속조회여부. '':초기조회, 'N':연속조회

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output1 (dict): 응답상세

                - bstp_nmix_prdy_vrss: 업종 지수 전일 대비
                - prdy_vrss_sign: 전일 대비 부호
                - bstp_nmix_prdy_ctrt: 업종 지수 전일 대비율
                - prdy_nmix: 전일 지수
                - acml_vol: 누적 거래량
                - acml_tr_pbmn: 누적 거래 대금
                - hts_kor_isnm: HTS 한글 종목명
                - bstp_nmix_prpr: 업종 지수 현재가
                - bstp_cls_code: 업종 구분 코드
                - prdy_vol: 전일 거래량
                - bstp_nmix_oprc: 업종 지수 시가2
                - bstp_nmix_hgpr: 업종 지수 최고가
                - bstp_nmix_lwpr: 업종 지수 최저가
                - futs_prdy_oprc: 선물 전일 시가
                - futs_prdy_hgpr: 선물 전일 최고가
                - futs_prdy_lwpr: 선물 전일 최저가

            - output2 (list): 응답상세

                - stck_bsop_date: 주식 영업 일자
                - stck_cntg_hour: 주식 체결 시간
                - bstp_nmix_prpr: 업종 지수 현재가
                - bstp_nmix_oprc: 업종 지수 시가2
                - bstp_nmix_hgpr: 업종 지수 최고가
                - bstp_nmix_lwpr: 업종 지수 최저가
                - cntg_vol: 체결 거래량
                - acml_tr_pbmn: 누적 거래 대금

        Raise:
            ValueError: API 에러 발생시
        '''
        assert self.auth.paper_trading == False, '실전계좌에서만 사용 가능한 API입니다.'
        assert fid_etc_cls_code in ['0', '1'], 'fid_etc_cls_code must be "0" or "1"'
        assert fid_input_iscd in ['0001', '1001'], 'fid_input_iscd must be "0001" or "1001"'
        assert fid_pw_data_incu_yn in ['Y', 'N'], 'fid_pw_data_incu_yn must be "Y" or "N"'

        url_path = '/uapi/domestic-stock/v1/quotations/inquire-time-indexchartprice'
        tr_id = 'FHKUP03500200'
        params = {
            'FID_COND_MRKT_DIV_CODE': 'U',
            'FID_ETC_CLS_CODE': fid_etc_cls_code,
            'FID_INPUT_ISCD': fid_input_iscd,
            'FID_INPUT_HOUR_1': str(fid_input_hour_1),
            'FID_PW_DATA_INCU_YN': fid_pw_data_incu_yn
        }

        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 = res_body['output1']
        for k in output1.keys():
            if k in ['hts_kor_isnm', 'bstp_cls_code']:
                pass
            elif k in ['prdy_vrss_sign', 'acml_vol', 'acml_tr_pbmn', 'prdy_vol']:
                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':
                    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

    def inquire_price_2(self, fid_input_iscd: str):
        '''
        (국내주식시세) 주식현재가 시세2[v1_국내주식-054]

        주식현재가 시세2 API입니다.

        Args:
            fid_input_iscd (str): 입력 종목코드

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output (dict): 응답상세

                - rprs_mrkt_kor_name: 대표 시장 한글 명
                - new_hgpr_lwpr_cls_code: 신 고가 저가 구분 코드 - 특정 경우에만 데이터 출력
                - mxpr_llam_cls_code: 상하한가 구분 코드  - 특정 경우에만 데이터 출력
                - crdt_able_yn: 신용 가능 여부
                - stck_mxpr: 주식 상한가
                - elw_pblc_yn: ELW 발행 여부
                - prdy_clpr_vrss_oprc_rate: 전일 종가 대비 시가2 비율
                - crdt_rate: 신용 비율
                - marg_rate: 증거금 비율
                - lwpr_vrss_prpr: 최저가 대비 현재가
                - lwpr_vrss_prpr_sign: 최저가 대비 현재가 부호
                - prdy_clpr_vrss_lwpr_rate: 전일 종가 대비 최저가 비율
                - stck_lwpr: 주식 최저가
                - hgpr_vrss_prpr: 최고가 대비 현재가
                - hgpr_vrss_prpr_sign: 최고가 대비 현재가 부호
                - prdy_clpr_vrss_hgpr_rate: 전일 종가 대비 최고가 비율
                - stck_hgpr: 주식 최고가
                - oprc_vrss_prpr: 시가2 대비 현재가
                - oprc_vrss_prpr_sign: 시가2 대비 현재가 부호
                - mang_issu_yn: 관리 종목 여부
                - divi_app_cls_code: 동시호가배분처리코드 - 11:매수상한배분 12:매수하한배분 13: 매도상한배분 14:매도하한배분
                - short_over_yn: 단기과열여부
                - mrkt_warn_cls_code: 시장경고코드 - 00: 없음 01: 투자주의 02:투자경고 03:투자위험
                - invt_caful_yn: 투자유의여부
                - stange_runup_yn: 이상급등여부
                - ssts_hot_yn: 공매도과열 여부
                - low_current_yn: 저유동성 종목 여부
                - vi_cls_code: VI적용구분코드
                - short_over_cls_code: 단기과열구분코드
                - stck_llam: 주식 하한가
                - new_lstn_cls_name: 신규 상장 구분 명
                - vlnt_deal_cls_name: 임의 매매 구분 명
                - flng_cls_name: 락 구분 이름  - 특정 경우에만 데이터 출력
                - revl_issu_reas_name: 재평가 종목 사유 명 - 특정 경우에만 데이터 출력
                - mrkt_warn_cls_name: 시장 경고 구분 명 - 특정 경우에만 데이터 출력 "투자환기" / "투자경고"
                - stck_sdpr: 주식 기준가
                - bstp_cls_code: 업종 구분 코드
                - stck_prdy_clpr: 주식 전일 종가
                - insn_pbnt_yn: 불성실 공시 여부
                - fcam_mod_cls_name: 액면가 변경 구분 명 - 특정 경우에만 데이터 출력
                - stck_prpr: 주식 현재가
                - prdy_vrss: 전일 대비
                - prdy_vrss_sign: 전일 대비 부호
                - prdy_ctrt: 전일 대비율
                - acml_tr_pbmn: 누적 거래 대금
                - acml_vol: 누적 거래량
                - prdy_vrss_vol_rate: 전일 대비 거래량 비율
                - bstp_kor_isnm: 업종 한글 종목명
                - sltr_yn: 정리매매 여부
                - trht_yn: 거래정지 여부
                - oprc_rang_cont_yn: 시가 범위 연장 여부
                - vlnt_fin_cls_code: 임의 종료 구분 코드
                - stck_oprc: 주식 시가2
                - prdy_vol: 전일 거래량

        Raise:
            ValueError: API 에러 발생시
        '''
        assert self.auth.paper_trading == False, '실전계좌에서만 사용 가능한 API입니다.'

        url_path = '/uapi/domestic-stock/v1/quotations/inquire-price-2'
        tr_id = 'FHPST01010000'
        params = {
            'FID_COND_MRKT_DIV_CODE': 'J',
            'FID_INPUT_ISCD': fid_input_iscd
        }

        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']}")

        output = res_body['output']
        for k in output.keys():
            if k in ['prdy_ctrt', 'prdy_vrss_vol_rate', 'prdy_clpr_vrss_oprc_rate', 'prdy_clpr_vrss_hgpr_rate', 'prdy_clpr_vrss_lwpr_rate', 'marg_rate', 'crdt_rate']:
                output[k] = Decimal(output[k])
            elif k in ['stck_prpr', 'prdy_vrss', 'prdy_vrss_sign', 'acml_tr_pbmn', 'acml_vol', 'prdy_vol', 'stck_prdy_clpr', 'stck_oprc', 'oprc_vrss_prpr_sign', 'oprc_vrss_prpr', 'stck_hgpr', 'hgpr_vrss_prpr_sign', 'hgpr_vrss_prpr', 'stck_lwpr', 'lwpr_vrss_prpr_sign', 'lwpr_vrss_prpr', 'stck_mxpr', 'stck_llam', 'bstp_cls_code', 'stck_sdpr']:
                output[k] = int(output[k])
            else:
                output[k] = output[k].strip()

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'],
            'output': res_body['output']
        }

        return result

    def inquire_daily_trade_volume(self,
                                   fid_input_iscd: str,
                                   fid_input_date_1: dtm.date,
                                   fid_input_date_2: dtm.date,
                                   tr_cont: str = ''):
        '''
        (국내주식시세) 종목별일별매수매도체결량 [v1_국내주식-056]

        종목별일별매수매도체결량 API입니다. 실전계좌의 경우, 한 번의 호출에 최대 100건까지 확인 가능합니다.
        국내주식 종목의 일별 매수체결량, 매도체결량 데이터를 확인할 수 있습니다.

        Args:
            fid_input_iscd (str): 입력 종목코드
            fid_input_date_1 (dtm.date): 입력 일자1 - from
            fid_input_date_2 (dtm.date): 입력 일자2 - to
            tr_cont (str): 연속조회여부

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - tr_cont (str): 연속조회가능여부

            - output1 (dict): 응답상세

                - shnu_cnqn_smtn: 매수 체결량 합계 - 당일 매수체결량 합계
                - seln_cnqn_smtn: 매도 체결량 합계 - 당일 매도체결량 합계

            - output2 (list): 응답상세

                - stck_bsop_date: 주식 영업 일자
                - total_seln_qty: 총 매도 수량
                - total_shnu_qty: 총 매수 수량

        Raise:
            ValueError: API 에러 발생시
        '''
        assert self.auth.paper_trading == False, '실전계좌에서만 사용 가능한 API입니다.'

        url_path = '/uapi/domestic-stock/v1/quotations/inquire-daily-trade-volume'
        tr_id = 'FHKST03010800'
        params = {
            'FID_COND_MRKT_DIV_CODE': 'J',
            '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': 'D'
        }
        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 = res_body['output1']
        for k in output1.keys():
            output1[k] = int(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()
                else:
                    el[k] = int(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_index_price(self, fid_input_iscd: str):
        '''
        (국내주식시세) 국내업종 현재지수[v1_국내주식-063]

        국내업종 현재지수 API입니다.

        한국투자 HTS(eFriend Plus) > [0210] 업종 현재지수 화면 의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.

        Args:
            fid_input_iscd (str): 입력 종목코드 - 코스피(0001), 코스닥(1001), 코스피200(2001)

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output (dict): 응답상세

                - bstp_nmix_prpr: 업종 지수 현재가
                - bstp_nmix_prdy_vrss: 업종 지수 전일 대비
                - prdy_vrss_sign: 전일 대비 부호
                - bstp_nmix_prdy_ctrt: 업종 지수 전일 대비율
                - acml_vol: 누적 거래량
                - prdy_vol: 전일 거래량
                - acml_tr_pbmn: 누적 거래 대금
                - prdy_tr_pbmn: 전일 거래 대금
                - bstp_nmix_oprc: 업종 지수 시가2
                - prdy_nmix_vrss_nmix_oprc: 전일 지수 대비 지수 시가2
                - oprc_vrss_prpr_sign: 시가2 대비 현재가 부호
                - bstp_nmix_oprc_prdy_ctrt: 업종 지수 시가2 전일 대비율
                - bstp_nmix_hgpr: 업종 지수 최고가
                - prdy_nmix_vrss_nmix_hgpr: 전일 지수 대비 지수 최고가
                - hgpr_vrss_prpr_sign: 최고가 대비 현재가 부호
                - bstp_nmix_hgpr_prdy_ctrt: 업종 지수 최고가 전일 대비율
                - bstp_nmix_lwpr: 업종 지수 최저가
                - prdy_clpr_vrss_lwpr: 전일 종가 대비 최저가
                - lwpr_vrss_prpr_sign: 최저가 대비 현재가 부호
                - prdy_clpr_vrss_lwpr_rate: 전일 종가 대비 최저가 비율
                - ascn_issu_cnt: 상승 종목 수
                - uplm_issu_cnt: 상한 종목 수
                - stnr_issu_cnt: 보합 종목 수
                - down_issu_cnt: 하락 종목 수
                - lslm_issu_cnt: 하한 종목 수
                - dryy_bstp_nmix_hgpr: 연중업종지수최고가
                - dryy_hgpr_vrss_prpr_rate: 연중 최고가 대비 현재가 비율
                - dryy_bstp_nmix_hgpr_date: 연중업종지수최고가일자
                - dryy_bstp_nmix_lwpr: 연중업종지수최저가
                - dryy_lwpr_vrss_prpr_rate: 연중 최저가 대비 현재가 비율
                - dryy_bstp_nmix_lwpr_date: 연중업종지수최저가일자
                - total_askp_rsqn: 총 매도호가 잔량
                - total_bidp_rsqn: 총 매수호가 잔량
                - seln_rsqn_rate: 매도 잔량 비율
                - shnu_rsqn_rate: 매수2 잔량 비율
                - ntby_rsqn: 순매수 잔량

        Raise:
            ValueError: API 에러 발생시
        '''

        assert self.auth.paper_trading == False, '실전계좌에서만 사용 가능한 API입니다.'

        url_path = '/uapi/domestic-stock/v1/quotations/inquire-index-price'
        tr_id = 'FHPUP02100000'
        params = {
            'FID_COND_MRKT_DIV_CODE': 'U',
            'FID_INPUT_ISCD': fid_input_iscd
        }

        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']}")

        output = res_body['output']

        for k in output.keys():
            if k in ['dryy_bstp_nmix_hgpr_date', 'dryy_bstp_nmix_lwpr_date']:
                output[k] = dtm.datetime.strptime(output[k], '%Y%m%d').date()
            elif k in ['bstp_nmix_prdy_vrss', 'bstp_nmix_prdy_ctrt', 'bstp_nmix_prpr', 'bstp_nmix_oprc', 'prdy_nmix_vrss_nmix_oprc', 'bstp_nmix_oprc_prdy_ctrt', 'bstp_nmix_hgpr', 'prdy_nmix_vrss_nmix_hgpr', 'bstp_nmix_hgpr_prdy_ctrt', 'bstp_nmix_lwpr', 'prdy_clpr_vrss_lwpr', 'prdy_clpr_vrss_lwpr_rate', 'dryy_bstp_nmix_hgpr', 'dryy_hgpr_vrss_prpr_rate', 'dryy_bstp_nmix_lwpr', 'dryy_lwpr_vrss_prpr_rate', 'seln_rsqn_rate', 'shnu_rsqn_rate']:
                output[k] = Decimal(output[k])
            else:
                output[k] = int(output[k])

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'],
            'output': output
        }

        return result

    def inquire_index_daily_price(self,
                                  fid_period_div_code: str,
                                  fid_input_iscd: str,
                                  fid_input_date_1: dtm.date,):
        '''
        (국내주식시세) 국내업종 일자별지수[v1_국내주식-065]

        국내업종 일자별지수 API입니다. 한 번의 조회에 100건까지 확인 가능합니다.

        한국투자 HTS(eFriend Plus) > [0212] 업종 일자별지수 화면 의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.

        Args:
            fid_period_div_code (str): 기간 구분 코드 - D:일 W:주 M:월
            fid_input_iscd (str): 입력 종목코드 - 전체(0000) 코스피(0001), 코스닥(1001), 코스피200(2001)
            fid_input_date_1 (dtm.date): 입력 일자1

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output1 (dict): 응답상세

                - bstp_nmix_prpr: 업종 지수 현재가
                - bstp_nmix_prdy_vrss: 업종 지수 전일 대비
                - prdy_vrss_sign: 전일 대비 부호
                - bstp_nmix_prdy_ctrt: 업종 지수 전일 대비율
                - acml_vol: 누적 거래량
                - acml_tr_pbmn: 누적 거래 대금
                - bstp_nmix_oprc: 업종 지수 시가2
                - bstp_nmix_hgpr: 업종 지수 최고가
                - bstp_nmix_lwpr: 업종 지수 최저가
                - prdy_vol: 전일 거래량
                - ascn_issu_cnt: 상승 종목 수
                - down_issu_cnt: 하락 종목 수
                - stnr_issu_cnt: 보합 종목 수
                - uplm_issu_cnt: 상한 종목 수
                - lslm_issu_cnt: 하한 종목 수
                - prdy_tr_pbmn: 전일 거래 대금
                - dryy_bstp_nmix_hgpr_date: 연중업종지수최고가일자
                - dryy_bstp_nmix_hgpr: 연중업종지수최고가
                - dryy_bstp_nmix_lwpr: 연중업종지수최저가
                - dryy_bstp_nmix_lwpr_date: 연중업종지수최저가일자

            - output2 (list): 응답상세

                - stck_bsop_date: 주식 영업 일자
                - bstp_nmix_prpr: 업종 지수 현재가
                - prdy_vrss_sign: 전일 대비 부호
                - bstp_nmix_prdy_vrss: 업종 지수 전일 대비
                - bstp_nmix_prdy_ctrt: 업종 지수 전일 대비율
                - bstp_nmix_oprc: 업종 지수 시가2
                - bstp_nmix_hgpr: 업종 지수 최고가
                - bstp_nmix_lwpr: 업종 지수 최저가
                - acml_vol_rlim: 누적 거래량 비중
                - acml_vol: 누적 거래량
                - acml_tr_pbmn: 누적 거래 대금
                - invt_new_psdg: 투자 신 심리도
                - d20_dsrt: 20일 이격도

        Raise:
            ValueError: API 에러 발생시
        '''
        assert self.auth.paper_trading == False, '실전계좌에서만 사용 가능한 API입니다.'
        assert fid_period_div_code in ['D', 'W', 'M'], 'fid_period_div_code must be "D", "W" or "M"'
        assert fid_input_iscd in ['0000', '0001', '1001', '2001'], 'fid_input_iscd must be "0000", "0001", "1001" or "2001"'

        url_path = '/uapi/domestic-stock/v1/quotations/inquire-index-daily-price'
        tr_id = 'FHPUP02120000'
        params = {
            'FID_PERIOD_DIV_CODE': fid_period_div_code,
            'FID_COND_MRKT_DIV_CODE': 'U',
            'FID_INPUT_ISCD': fid_input_iscd,
            'FID_INPUT_DATE_1': fid_input_date_1.strftime('%Y%m%d')
        }

        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']
        '''
        {
            'dryy_bstp_nmix_lwpr_date': '20240118'
            'dryy_bstp_nmix_hgpr_date': '20240219',
            'bstp_nmix_prpr': '2664.20',
            'bstp_nmix_prdy_vrss': '10.89',
            'bstp_nmix_prdy_ctrt': '0.41',
            'bstp_nmix_oprc': '2671.69',
            'bstp_nmix_hgpr': '2671.69',
            'bstp_nmix_lwpr': '2653.99',
            'dryy_bstp_nmix_hgpr': '2683.39',
            'dryy_bstp_nmix_lwpr': '2429.12',
            'prdy_vrss_sign': '2',
            'acml_vol': '406329',
            'acml_tr_pbmn': '8946698',
            'prdy_vol': '562144',
            'ascn_issu_cnt': '319',
            'down_issu_cnt': '545',
            'stnr_issu_cnt': '71',
            'uplm_issu_cnt': '1',
            'lslm_issu_cnt': '0',
            'prdy_tr_pbmn': '9150151',
        }
        '''
        for k in output1.keys():
            if k in ['dryy_bstp_nmix_lwpr_date', 'dryy_bstp_nmix_hgpr_date']:
                output1[k] = dtm.datetime.strptime(output1[k], '%Y%m%d').date()
            elif k in ['bstp_nmix_prpr', 'bstp_nmix_prdy_vrss', 'bstp_nmix_prdy_ctrt', 'bstp_nmix_oprc', 'bstp_nmix_hgpr', 'bstp_nmix_lwpr', 'dryy_bstp_nmix_hgpr', 'dryy_bstp_nmix_lwpr']:
                output1[k] = Decimal(output1[k])
            else:
                output1[k] = int(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 in ['acml_vol', 'prdy_vrss_sign', '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'],
            'output1': output1,
            'output2': output2
        }

        return result

    def inquire_index_category_price(self,
                                     fid_blng_cls_code: str,
                                     fid_input_iscd: str,
                                     fid_mrkt_cls_code: str):
        '''
        (국내주식시세) 국내업종 구분별전체시세[v1_국내주식-066]

        국내업종 구분별전체시세 API입니다.
        한국투자 HTS(eFriend Plus) > [0214] 업종 전체시세 화면 의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.

        Args:
            fid_blng_cls_code (str): FID 소속 구분 코드

              | 시장구분코드(K:거래소) 0:전업종, 1:기타구분, 2:자본금구분 3:상업별구분
              | 시장구분코드(Q:코스닥) 0:전업종, 1:기타구분, 2:벤처구분 3:일반구분
              | 시장구분코드(K2:코스닥) 0:전업종

            fid_input_iscd (str): FID 입력 종목코드 - 코스피(0001), 코스닥(1001), 코스피200(2001)
            fid_mrkt_cls_code (str): FID 시장 구분 코드 - 시장구분코드(K:거래소, Q:코스닥, K2:코스피200)

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output1 (dict): 응답상세

                - bstp_nmix_prpr: 업종 지수 현재가
                - bstp_nmix_prdy_vrss: 업종 지수 전일 대비
                - prdy_vrss_sign: 전일 대비 부호
                - bstp_nmix_prdy_ctrt: 업종 지수 전일 대비율
                - acml_vol: 누적 거래량
                - acml_tr_pbmn: 누적 거래 대금
                - bstp_nmix_oprc: 업종 지수 시가2
                - bstp_nmix_hgpr: 업종 지수 최고가
                - bstp_nmix_lwpr: 업종 지수 최저가
                - prdy_vol: 전일 거래량
                - ascn_issu_cnt: 상승 종목 수
                - down_issu_cnt: 하락 종목 수
                - stnr_issu_cnt: 보합 종목 수
                - uplm_issu_cnt: 상한 종목 수
                - lslm_issu_cnt: 하한 종목 수
                - prdy_tr_pbmn: 전일 거래 대금
                - dryy_bstp_nmix_hgpr_date: 연중업종지수최고가일자
                - dryy_bstp_nmix_hgpr: 연중업종지수최고가
                - dryy_bstp_nmix_lwpr: 연중업종지수최저가
                - dryy_bstp_nmix_lwpr_date: 연중업종지수최저가일자

            - output2 (list): 응답상세

                - bstp_cls_code: 업종 구분 코드
                - hts_kor_isnm: HTS 한글 종목명
                - bstp_nmix_prpr: 업종 지수 현재가
                - bstp_nmix_prdy_vrss: 업종 지수 전일 대비
                - prdy_vrss_sign: 전일 대비 부호
                - bstp_nmix_prdy_ctrt: 업종 지수 전일 대비율
                - acml_vol: 누적 거래량
                - acml_tr_pbmn: 누적 거래 대금
                - acml_vol_rlim: 누적 거래량 비중
                - acml_tr_pbmn_rlim: 누적 거래 대금 비중
        Raise:
            ValueError: API 에러 발생시
        '''

        assert self.auth.paper_trading == False, '실전계좌에서만 사용 가능한 API입니다.'
        assert fid_blng_cls_code in ['0', '1', '2', '3'], 'fid_blng_cls_code must be "0", "1", "2" or "3"'
        assert fid_input_iscd in ['0001', '1001', '2001'], 'fid_input_iscd must be "0001", "1001" or "2001"'
        assert fid_mrkt_cls_code in ['K', 'Q', 'K2'], 'fid_mrkt_cls_code must be "K", "Q" or "K2"'

        url_path = '/uapi/domestic-stock/v1/quotations/inquire-index-category-price'
        tr_id = 'FHPUP02140000'
        params = {
            'FID_COND_MRKT_DIV_CODE': 'U',
            'FID_BLNG_CLS_CODE': fid_blng_cls_code,
            'FID_INPUT_ISCD': fid_input_iscd,
            'FID_COND_SCR_DIV_CODE': '20214',
            'FID_MRKT_CLS_CODE': fid_mrkt_cls_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']}")

        output1 = res_body['output1']
        for k in output1.keys():
            if k in ['dryy_bstp_nmix_lwpr_date', 'dryy_bstp_nmix_hgpr_date']:
                output1[k] = dtm.datetime.strptime(output1[k], '%Y%m%d').date()
            elif k in ['bstp_nmix_prpr', 'bstp_nmix_prdy_vrss', 'bstp_nmix_prdy_ctrt', 'bstp_nmix_oprc', 'bstp_nmix_hgpr', 'bstp_nmix_lwpr', 'dryy_bstp_nmix_hgpr', 'dryy_bstp_nmix_lwpr']:
                output1[k] = Decimal(output1[k])
            else:
                output1[k] = int(output1[k])

        output2 = []
        for el in res_body['output2']:
            for k in el.keys():
                if k in ['bstp_cls_code', 'hts_kor_isnm']:
                    pass
                elif k in ['prdy_vrss_sign', 'acml_vol', 'acml_tr_pbmn']:
                    if len(el[k]) > 0:
                        el[k] = int(el[k])
                else:
                    if len(el[k]) > 0:
                        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'],
            'output1': output1,
            'output2': output2
        }

        return result

    def search_stock_info(self,
                          prdt_type_cd: str,
                          pdno: str):
        '''
        (국내주식시세) 주식기본조회[v1_국내주식-067]

        주식기본조회 API입니다.
        국내주식 종목의 종목상세정보를 확인할 수 있습니다.

        Args:
            prdt_type_cd (str): 상품유형코드 - 300:주식 301:선물옵션 302:채권 306:ELS
            pdno (str): 상품번호

        Returns:
            dict:

            - tr_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output (dict): 응답상세

                - pdno: 상품번호
                - prdt_type_cd: 상품유형코드
                - mket_id_cd: 시장ID코드
                - scty_grp_id_cd: 증권그룹ID코드
                - excg_dvsn_cd: 거래소구분코드
                - setl_mmdd: 결산월일
                - lstg_stqt: 상장주수
                - lstg_cptl_amt: 상장자본금액
                - cpta: 자본금
                - papr: 액면가
                - issu_pric: 발행가격
                - kospi200_item_yn: 코스피200종목여부
                - scts_mket_lstg_dt: 유가증권시장상장일자
                - scts_mket_lstg_abol_dt: 유가증권시장상장폐지일자
                - kosdaq_mket_lstg_dt: 코스닥시장상장일자
                - kosdaq_mket_lstg_abol_dt: 코스닥시장상장폐지일자
                - frbd_mket_lstg_dt: 프리보드시장상장일자
                - frbd_mket_lstg_abol_dt: 프리보드시장상장폐지일자
                - reits_kind_cd: 리츠종류코드
                - etf_dvsn_cd: ETF구분코드
                - oilf_fund_yn: 유전펀드여부
                - idx_bztp_lcls_cd: 지수업종대분류코드
                - idx_bztp_mcls_cd: 지수업종중분류코드
                - idx_bztp_scls_cd: 지수업종소분류코드
                - stck_kind_cd: 주식종류코드
                - mfnd_opng_dt: 뮤추얼펀드개시일자
                - mfnd_end_dt: 뮤추얼펀드종료일자
                - dpsi_erlm_cncl_dt: 예탁등록취소일자
                - etf_cu_qty: ETFCU수량
                - prdt_name: 상품명
                - prdt_name120: 상품명120
                - prdt_abrv_name: 상품약어명
                - std_pdno: 표준상품번호
                - prdt_eng_name: 상품영문명
                - prdt_eng_name120: 상품영문명120
                - prdt_eng_abrv_name: 상품영문약어명
                - dpsi_aptm_erlm_yn: 예탁지정등록여부
                - etf_txtn_type_cd: ETF과세유형코드
                - etf_type_cd: ETF유형코드
                - lstg_abol_dt: 상장폐지일자
                - nwst_odst_dvsn_cd: 신주구주구분코드
                - sbst_pric: 대용가격
                - thco_sbst_pric: 당사대용가격
                - thco_sbst_pric_chng_dt: 당사대용가격변경일자
                - tr_stop_yn: 거래정지여부
                - admn_item_yn: 관리종목여부
                - thdt_clpr: 당일종가
                - bfdy_clpr: 전일종가
                - clpr_chng_dt: 종가변경일자
                - std_idst_clsf_cd: 표준산업분류코드
                - std_idst_clsf_cd_name: 표준산업분류코드명
                - idx_bztp_lcls_cd_name: 지수업종대분류코드명
                - idx_bztp_mcls_cd_name: 지수업종중분류코드명
                - idx_bztp_scls_cd_name: 지수업종소분류코드명
                - ocr_no: OCR번호
                - crfd_item_yn: 크라우드펀딩종목여부
                - elec_scty_yn: 전자증권여부

        Raise:
            ValueError: API 에러 발생시
        '''

        assert self.auth.paper_trading == False, '실전계좌에서만 사용 가능한 API입니다.'
        assert prdt_type_cd in ['300', '301', '302', '306'], 'prdt_type_cd must be "300", "301", "302" or "306"'

        url_path = '/uapi/domestic-stock/v1/quotations/search-stock-info'
        tr_id = 'CTPF1002R'
        params = {
            'PRDT_TYPE_CD': prdt_type_cd,
            'PDNO': pdno
        }

        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']}")

        output = res_body['output']
        for k in output.keys():
            if k in ['lstg_stqt', 'lstg_cptl_amt', 'cpta', 'papr', 'issu_pric', 'etf_cu_qty', 'sbst_pric', 'thco_sbst_pric', 'thdt_clpr', 'bfdy_clpr']:
                if len(output[k]) > 0:
                    output[k] = int(output[k])

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'],
            'output': output
        }

        return result

    def order_cash(self,
                    cano: str,
                    acnt_prdt_cd: str,
                    side: str,
                    pdno: str,
                    ord_dvsn: str,
                    ord_qty: int,
                    ord_unpr: int = None,):
        '''
        (국내주식주문) 주식주문(현금)[v1_국내주식-001]

        국내주식주문(현금) API 입니다.

        | ※ TTC0802U(현금매수) 사용하셔서 미수매수 가능합니다. 단, 거래하시는 계좌가 증거금40%계좌로 신청이 되어있어야 가능합니다.
        | ※ 신용매수는 별도의 API가 준비되어 있습니다.

        | ※ ORD_UNPR(주문단가)가 없는 주문은 상한가로 주문금액을 선정하고 이후 체결이되면 체결금액로 정산됩니다.

        | ※ 종목코드 마스터파일 파이썬 정제코드는 한국투자증권 Github 참고 부탁드립니다.
        | https://github.com/koreainvestment/open-trading-api/tree/main/stocks_info

        Args:
            cano (str): 계좌번호
            acnt_prdt_cd (str): 계좌상품코드
            side (str): 매매구분 - 매수:buy 매도:sell
            pdno (str): 상품번호
            ord_dvsn (str): 주문구분

              | 00:지정가
              | 01:시장가
              | 02:조건부지정가
              | 03:최유리지정가
              | 04:최우선지정가
              | 05:장전 시간외 (08:20~08:40)
              | 06:장후 시간외 (15:30~16:00)
              | 07:시간외 단일가(16:00~18:00)
              | 08:자기주식
              | 09:자기주식S-Option
              | 10:자기주식금전신탁
              | 11:IOC지정가 (즉시체결,잔량취소)
              | 12:FOK지정가 (즉시체결,전량취소)
              | 13:IOC시장가 (즉시체결,잔량취소)
              | 14:FOK시장가 (즉시체결,전량취소)
              | 15:IOC최유리 (즉시체결,잔량취소)
              | 16:FOK최유리 (즉시체결,전량취소)

            ord_qty (int): 주문수량
            ord_unpr (int): 주문단가

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output (dict): 응답상세

                - KRX_FWDG_ORD_ORGNO: 한국거래소전송주문조직번호 - 주문시 한국투자증권 시스템에서 지정된 영업점코드
                - ODNO: 주문번호 - 주문시 한국투자증권 시스템에서 채번된 주문번호
                - ORD_TMD: 주문시각 - 주문시각

        Raise:
            ValueError: API 에러 발생시
        '''
        assert side in ['sell', 'buy']
        assert type(ord_dvsn) == str and len(ord_dvsn) == 2 and int(ord_dvsn) >= 0 and int(ord_dvsn) <= 16, 'ord_dvsn must be a string of integer between 00 and 16'
        assert type(ord_qty) == int and ord_qty > 0, 'ord_qty must be a positive integer'

        if ord_dvsn in ['00', '02', '11', '12']: # 지정가, 조건부지정가, IOC/FOK지정가
            assert type(ord_unpr) == int and ord_unpr > 0, 'ord_unpr must be a positive integer when limit order'

        url_path = '/uapi/domestic-stock/v1/trading/order-cash'

        if side == 'sell':
            tr_id = 'VTTC0801U' if self.auth.paper_trading else 'TTTC0801U'
        else:
            tr_id = 'VTTC0802U' if self.auth.paper_trading else 'TTTC0802U'

        req_body = {
            'CANO': cano,
            'ACNT_PRDT_CD': acnt_prdt_cd,
            'PDNO': pdno,
            'ORD_DVSN': ord_dvsn,
            'ORD_QTY': str(ord_qty),
            'ORD_UNPR': '0' if ord_unpr is None else str(ord_unpr),
        }

        res_body, _ = self._tr_request(url_path, tr_id, body=req_body, method="POST")

        if res_body['rt_cd'] != '0':
            raise ValueError(f"Error: ({res_body['msg_cd']}) {res_body['msg1']}")

        res_body['ORD_TMD'] = dtm.datetime.strptime(res_body['output']['ORD_TMD'], '%H%M%S').time()

        return res_body

    def order_credit(self,
                    cano: str,
                    acnt_prdt_cd: str,
                    side: str,
                    pdno: str,
                    crdt_type: str,
                    load_dt: dtm.date,
                    ord_dvsn: str,
                    ord_qty: int,
                    rvsn_ord_yn: str,
                    ord_unpr: int = None,):
        '''
        (국내주식주문) 주식주문(신용)[v1_국내주식-002]

        국내주식주문(신용) API입니다.

        ※ 모의투자는 사용 불가합니다.

        Args:
            cano (str): 계좌번호
            acnt_prdt_cd (str): 계좌상품코드
            side (str): 매매구분 - 신용매수:buy 신용매도:sell
            pdno (str): 상품번호
            crdt_type (str): 신용유형

              | - 신용매수
              |     - 21:자기융자신규
              |     - 23:유동융자신규
              |     - 26:유동대주상환
              |     - 28:자기대주상환
              | - 신용매도
              |     - 25:자기융자상환
              |     - 27:유동융자상환
              |     - 22:유동대주신규
              |     - 24:자기대주신규

            load_dt (dtm.date): 대출일자

              | 신용매수: 신규 대출로, 오늘날짜 입력
              | 신용매도: 매도할 종목의 대출일자 입력
              | * 주식잔고조회 API(TTC8434R)의 INQR_DVSN(조회구분)을 01(대출일별)로 조회하여서 조회된 주문의 LOAN_DT(대출일자) 입력

            ord_dvsn (str): 주문구분

              | 00:지정가
              | 01:시장가
              | 02:조건부지정가
              | 03:최유리지정가
              | 04:최우선지정가
              | 05:장전 시간외 (08:20~08:40)
              | 06:장후 시간외 (15:30~16:00)
              | 07:시간외 단일가(16:00~18:00)
              | 08:자기주식
              | 09:자기주식S-Option
              | 10:자기주식금전신탁
              | 11:IOC지정가 (즉시체결,잔량취소)
              | 12:FOK지정가 (즉시체결,전량취소)
              | 13:IOC시장가 (즉시체결,잔량취소)
              | 14:FOK시장가 (즉시체결,전량취소)
              | 15:IOC최유리 (즉시체결,잔량취소)
              | 16:FOK최유리 (즉시체결,전량취소)

            ord_qty (int): 주문수량
            rsvn_ord_yn (str): 예약주문여부

              | - 정규 증권시장이 열리지 않는 시간 (15:10분 ~ 익일 7:30분) 에 주문을 미리 설정 하여 다음 영업일 또는 설정한 기간 동안 아침 동시 호가에 주문하는 것.
              | - 예약주문:Y, 즉시주문:N

            ord_unpr (int): 주문단가

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output (dict): 응답상세
                - KRX_FWDG_ORD_ORGNO: 한국거래소전송주문조직번호 - 주문시 한국투자증권 시스템에서 지정된 영업점코드
                - ODNO: 주문번호 - 주문시 한국투자증권 시스템에서 채번된 주문번호
                - ORD_TMD: 주문시각 - 주문시각

        Raise:
            ValueError: API 에러 발생시
        '''
        assert self.auth.paper_trading == False, '실전계좌에서만 사용 가능한 API입니다.'
        assert side in ['sell', 'buy']

        if side == 'sell':
            assert crdt_type in ['25', '27', '22', '24'], 'crdt_type must be "25", "27", "22" or "24" when sell'
        else:
            assert crdt_type in ['21', '23', '26', '28'], 'crdt_type must be "21", "23", "26" or "28" when buy'

        assert type(ord_dvsn) == str and len(ord_dvsn) == 2 and int(ord_dvsn) >= 0 and int(ord_dvsn) <= 16, 'ord_dvsn must be a string of integer between 00 and 16'
        assert type(ord_qty) == int and ord_qty > 0, 'ord_qty must be a positive integer'

        if ord_dvsn in ['00', '02', '11', '12']: # 지정가, 조건부지정가, IOC/FOK지정가
            assert type(ord_unpr) == int and ord_unpr > 0, 'ord_unpr must be a positive integer when limit order'

        assert rvsn_ord_yn in ['Y', 'N'], 'rvsn_ord_yn must be "Y" or "N"'

        url_path = '/uapi/domestic-stock/v1/trading/order-credit'

        if side == 'sell':
            tr_id = 'TTTC0851U'
        else:
            tr_id = 'TTTC0852U'

        req_body = {
            'CANO': cano,
            'ACNT_PRDT_CD': acnt_prdt_cd,
            'PDNO': pdno,
            'CRDT_TYPE': crdt_type,
            'LOAD_DT': load_dt.strftime('%Y%m%d'),
            'ORD_DVSN': ord_dvsn,
            'ORD_QTY': str(ord_qty),
            'ORD_UNPR': '0' if ord_unpr is None else str(ord_unpr),
        }

        res_body, _ = self._tr_request(url_path, tr_id, json=req_body, method='POST')

        if res_body['rt_cd'] != '0':
            raise ValueError(f"Error: ({res_body['msg_cd']}) {res_body['msg1']}")

        res_body['output']['ORD_TMD'] = dtm.datetime.strptime(res_body['ORD_TMD'], '%H%M%S').time()

        return res_body

    def order_rvsecncl(self,
                       cano: str,
                       acnt_prdt_cd: str,
                       orgn_odno: str,
                       ord_dvsn: str,
                       rvse_cncl_dvsn_cd: str,
                       ord_qty: int,
                       ord_unpr: int,
                       qty_all_ord_yn: str):
        '''
        (국내주식주문) 주식주문(정정취소)[v1_국내주식-003]

        주문 건에 대하여 정정 및 취소하는 API입니다. 단, 이미 체결된 건은 정정 및 취소가 불가합니다.

        Args:
            cano (str): 종합계좌번호 - 계좌번호 체계(8-2)의 앞 8자리
            acnt_prdt_cd (str): 계좌상품코드 - 계좌번호 체계(8-2)의 뒤 2자리
            orgn_odno (str): 원주문번호 - 주식일별주문체결조회 API output1의 odno(주문번호) 값 입력. 주문시 한국투자증권 시스템에서 채번된 주문번호
            ord_dvsn (str): 주문구분

              | 00:지정가
              | 01:시장가
              | 02:조건부지정가
              | 03:최유리지정가
              | 04:최우선지정가
              | 05:장전 시간외
              | 06:장후 시간외
              | 07:시간외 단일가
              | 08:자기주식
              | 09:자기주식S-Option
              | 10:자기주식금전신탁
              | 11:IOC지정가 (즉시체결,잔량취소)
              | 12:FOK지정가 (즉시체결,전량취소)
              | 13:IOC시장가 (즉시체결,잔량취소)
              | 14:FOK시장가 (즉시체결,전량취소)
              | 15:IOC최유리 (즉시체결,잔량취소)
              | 16:FOK최유리 (즉시체결,전량취소)

            rvse_cncl_dvsn_cd (str): 정정취소구분코드 - 정정:01 취소:02
            ord_qty (int): 주문수량 - 전부 취소/정정시 0 입력, 일부 취소/정정시 취소/정정 수량 입력
            ord_unpr (int): 주문단가 - 정정주문 1주당 가격, 취소시 0 설정
            qty_all_ord_yn (str): 잔량전부주문여부 - Y:잔량전부 N:잔량일부

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - output (dict): 응답상세
                - KRX_FWDG_ORD_ORGNO: 한국거래소전송주문조직번호 - 주문시 한국투자증권 시스템에서 지정된 영업점코드
                - ODNO: 주문번호 - 주문시 한국투자증권 시스템에서 채번된 주문번호
                - ORD_TMD: 주문시각 - 주문시각
        '''
        url_path = '/uapi/domestic-stock/v1/trading/order-rvsecncl'
        tr_id = 'VTTC0803U' if self.auth.paper_trading else 'TTTC0803U'
        req_body = {
            'CANO': cano,
            'ACNT_PRDT_CD': acnt_prdt_cd,
            'KRX_FWDG_ORD_ORGNO': '',
            'ORGN_ODNO': orgn_odno,
            'ORD_DVSN': ord_dvsn,
            'RVSE_CNCL_DVSN_CD': rvse_cncl_dvsn_cd,
            'ORD_QTY': str(ord_qty),
            'ORD_UNPR': str(ord_unpr),
            'QTY_ALL_ORD_YN': qty_all_ord_yn
        }

        res_body, _ = self._tr_request(url_path, tr_id, body=req_body, method="POST")

        if res_body['rt_cd'] != '0':
            raise ValueError(f"Error: ({res_body['msg_cd']}) {res_body['msg1']}")

        res_body['output']['ORD_TMD'] = dtm.datetime.strptime(res_body['output']['ORD_TMD'], '%H%M%S').time()

        return res_body

    def inquire_psbl_rvsecncl(
        self,
        cano: str,
        acnt_prdt_cd: str,
        inqr_dvsn_1: str = "1",
        inqr_dvsn_2: str = "0",
        ctx_area_fk100: str = "",
        ctx_area_nk100: str = "",
    ):
        """
        (국내주식주문) 주식정정취소가능주문조회[v1_국내주식-004]

        주식정정취소가능주문조회 API입니다. 한 번의 호출에 최대 50건까지 확인 가능하며, 이후의 값은 연속조회를 통해 확인하실 수 있습니다.

        Args:
            cano (str): 종합계좌번호 - 계좌번호 체계(8-2)의 앞 8자리
            acnt_prdt_cd (str): 계좌상품코드 - 계좌번호 체계(8-2)의 뒤 2자리
            inqr_dvsn_1 (str): 조회구분1 - 0:조회순서 1:주문순 2:종목순
            inqr_dvsn_2 (str): 조회구분2 - 0:전체 1:매도 2:매수
            ctx_area_fk100 (str): CTX_AREA_FK100
            ctx_area_nk100 (str): CTX_AREA_NK100

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - tr_cont (str): 연속 조회 가능 여부
            - ctx_area_fk100 (str): 연속조회검색조건100
            - ctx_area_nk100 (str): 연속조회검색키100
            - output (list): 응답상세

                - ord_gno_brno: 주문채번지점번호 - 주문시 한국투자증권 시스템에서 지정된 영업점코드
                - odno: 주문번호 - 주문시 한국투자증권 시스템에서 채번된 주문번호
                - orgn_odno: 원주문번호 - 정정/취소주문 인경우 원주문번호
                - ord_dvsn_name: 주문구분명
                - pdno: 상품번호 - 종목번호(뒤 6자리만 해당)
                - prdt_name: 상품명 - 종목명
                - rvse_cncl_dvsn_name: 정정취소구분명 - 정정 또는 취소 여부 표시
                - ord_qty: 주문수량 - 주문수량
                - ord_unpr: 주문단가 - 1주당 주문가격
                - ord_tmd: 주문시각 - 주문시각(시분초HHMMSS)
                - tot_ccld_qty: 총체결수량 - 주문 수량 중 체결된 수량
                - tot_ccld_amt: 총체결금액 - 주문금액 중 체결금액
                - psbl_qty: 가능수량 - 정정/취소 주문 가능 수량
                - sll_buy_dvsn_cd: 매도매수구분코드 - 01:매도 02:매수
                - ord_dvsn_cd: 주문구분코드

                    | 00:지정가
                    | 01:시장가
                    | 02:조건부지정가
                    | 03:최유리지정가
                    | 04:최우선지정가
                    | 05:장전 시간외
                    | 06:장후 시간외
                    | 07:시간외 단일가
                    | 08:자기주식
                    | 09:자기주식S-Option
                    | 10:자기주식금전신탁
                    | 11:IOC지정가 (즉시체결,잔량취소)
                    | 12:FOK지정가 (즉시체결,전량취소)
                    | 13:IOC시장가 (즉시체결,잔량취소)
                    | 14:FOK시장가 (즉시체결,전량취소)
                    | 15:IOC최유리 (즉시체결,잔량취소)
                    | 16:FOK최유리 (즉시체결,전량취소)
                    | 51:장중대량

                - mgco_aptm_odno: 운용사지정주문번호 - 주문 번호 (운용사 통한 주문)

        Raise:
            ValueError: API 에러 발생시
        """

        assert self.auth.paper_trading == False, '실전계좌에서만 사용 가능한 API입니다.'

        url_path = '/uapi/domestic-stock/v1/trading/inquire-psbl-rvsecncl'
        tr_id = 'TTTC8036R'
        tr_cont = "" if ctx_area_fk100 == "" else "N"

        params = {
            'CANO': cano,
            'ACNT_PRDT_CD': acnt_prdt_cd,
            'INQR_DVSN_1': inqr_dvsn_1,
            'INQR_DVSN_2': inqr_dvsn_2,
            'CTX_AREA_FK100': ctx_area_fk100,
            'CTX_AREA_NK100': ctx_area_nk100
        }
        res_body, res_header = 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']}")

        output = []
        for el in res_body['output']:
            for k in el.keys():
                if k == 'ord_tmd':
                    el[k] = dtm.datetime.strptime(el[k], '%H%M%S').time()
                elif k in ['ord_qty', 'ord_unpr', 'tot_ccld_qty', 'tot_ccld_amt', 'psbl_qty']:
                    el[k] = int(el[k])

            output.append(el)

        result = {
            "rt_cd": res_body["rt_cd"],
            "tr_cont": res_header["tr_cont"],
            "msg_cd": res_body["msg_cd"],
            "msg1": res_body["msg1"].strip(),
            "ctx_area_fk100": res_body["ctx_area_fk100"].strip(),
            "ctx_area_nk100": res_body["ctx_area_nk100"].strip(),
            "output": output,
        }

        return result

    def inquire_daily_ccld(self,
                           cano: str,
                           acnt_prdt_cd: str,
                           inqr_strt_dt: dtm.date,
                           inqr_end_dt: dtm.date,
                           sll_buy_dvsn_cd: str = '00',
                           inqr_dvsn: str = '00',
                           pdno: str = '',
                           ccld_dvsn: str = '00',
                           inqr_dvsn_3: str = '00',
                           inqr_dvsn_1: str = '',
                           ctx_area_fk100: str = '',
                           ctx_area_nk100: str = '',
                           tr_cont: str = ''):
        '''
        (국내주식주문) 주식일별주문체결조회[v1_국내주식-005]

        | 주식일별주문체결조회 API입니다.
        | 실전계좌의 경우, 한 번의 호출에 최대 100건까지 확인 가능하며, 이후의 값은 연속조회를 통해 확인하실 수 있습니다.
        | 모의계좌의 경우, 한 번의 호출에 최대 15건까지 확인 가능하며, 이후의 값은 연속조회를 통해 확인하실 수 있습니다.

        | * 다만, 3개월 이전 체결내역 조회(CTSC9115R) 의 경우,
        | 장중에는 많은 거래량으로 인해 순간적으로 DB가 밀렸거나 응답을 늦게 받거나 하는 등의 이슈가 있을 수 있어
        | ① 가급적 장 종료 이후(15:30 이후) 조회하시고
        | ② 조회기간(INQR_STRT_DT와 INQR_END_DT 사이의 간격)을 보다 짧게 해서 조회하는 것을 권유드립니다.

        Args:
            cano (str): 종합계좌번호 - 계좌번호 체계(8-2)의 앞 8자리
            acnt_prdt_cd (str): 계좌상품코드 - 계좌번호 체계(8-2)의 뒤 2자리
            inqr_strt_dt (datetime.date): 조회시작일자
            inqr_end_dt (datetime.datestr): 조회종료일자
            sll_buy_dvsn_cd (str): 매도매수구분코드 - 00:전체 01:매도 02:매수
            inqr_dvsn (str): 조회구분 - 00:역순 01:정순
            pdno (str): 상품번호 - 종목번호(6자리) 공란:전체 조회
            ccld_dvsn (str): 체결구분 - 00:전체 01:체결 02:미체결
            inqr_dvsn_3 (str): 조회구분3 - 00:전체 01:현금 02:융자 03:대출 04:대주
            inqr_dvsn_1 (str): 조회구분1 - 공란:전체 1:ELW 2:프리보드
            ctx_area_fk100 (str): 연속조회검색조건100 - "":최초 조회시 이전 조회 ctx_area_fk100 값:다음페이지 조회시(2번째부터)
            ctx_area_nk100 (str): 연속조회키100 - "":최초 조회시 이전 조회 ctx_area_nk100 값:다음페이지 조회시(2번째부터)

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 메시지1
            - tr_cont (str): TR내용
            - ctx_area_fk100 (str): 연속조회검색조건100
            - ctx_area_nk100 (str): 연속조회키100
            - output1 (list): 응답상세

                - ord_dt: 주문일자 - 주문일자
                - ord_gno_brno: 주문채번지점번호 - 주문시 한국투자증권 시스템에서 지정된 영업점코드
                - odno: 주문번호 - 주문시 한국투자증권 시스템에서 채번된 주문번호, 지점별 일자별로 채번됨

                    - 주문번호 유일조건: ord_dt(주문일자) + ord_gno_brno(주문채번지점번호) + odno(주문번호)

                - orgn_odno: 원주문번호 - 이전 주문에 채번된 주문번호
                - ord_dvsn_name: 주문구분명
                - sll_buy_dvsn_cd: 매도매수구분코드 - 01:매도 02:매수
                - sll_buy_dvsn_cd_name: 매도매수구분코드명 - * 반대매매 인경우 "임의매도"로 표시됨
                - pdno: 상품번호 - 종목번호(6자리)
                - prdt_name: 상품명 - 종목명
                - ord_qty: 주문수량
                - ord_unpr: 주문단가
                - ord_tmd: 주문시각
                - tot_ccld_qty: 총체결수량
                - avg_prvs: 평균가 - 체결평균가 ( 총체결금액 / 총체결수량 )
                - cncl_yn: 취소여부
                - tot_ccld_amt: 총체결금액
                - loan_dt: 대출일자
                - ord_dvsn_cd: 주문구분코드

                    | 00:지정가
                    | 01:시장가
                    | 02:조건부지정가
                    | 03:최유리지정가
                    | 04:최우선지정가
                    | 05:장전 시간외
                    | 06:장후 시간외
                    | 07:시간외 단일가
                    | 08:자기주식
                    | 09:자기주식S-Option
                    | 10:자기주식금전신탁
                    | 11:IOC지정가 (즉시체결,잔량취소)
                    | 12:FOK지정가 (즉시체결,전량취소)
                    | 13:IOC시장가 (즉시체결,잔량취소)
                    | 14:FOK시장가 (즉시체결,전량취소)
                    | 15:IOC최유리 (즉시체결,잔량취소)
                    | 16:FOK최유리 (즉시체결,전량취소)
                - cncl_cfrm_qty: 취소확인수량
                - rmn_qty: 잔여수량
                - rjct_qty: 거부수량
                - ccld_cndt_name: 체결조건명
                - infm_tmd: 통보시각 - ※ 실전투자계좌로는 해당값이 제공되지 않습니다.
                - ctac_tlno: 연락전화번호
                - prdt_type_cd: 상품유형코드 - 300:주식 301:선물옵션 302:채권 306:ELS
                - excg_dvsn_cd: 거래소구분코드

                    | 01:한국증권
                    | 02:증권거래소
                    | 03:코스닥
                    | 04:K-OTC
                    | 05:선물거래소
                    | 06:CME
                    | 07:EUREX
                    | 21:금현물
                    | 51:홍콩
                    | 52:상해B
                    | 53:심천
                    | 54:홍콩거래소
                    | 55:미국
                    | 56:일본
                    | 57:상해A
                    | 58:심천A
                    | 59:베트남
                    | 61:장전시간외시장
                    | 64:경쟁대량매매
                    | 65:경매매시장
                    | 81:시간외단일가시장

            - output2 (dict): 응답상세

                - tot_ord_qty: 총주문수량 - 미체결주문수량 + 체결수량 (취소주문제외)
                - tot_ccld_qty: 총체결수량
                - pchs_avg_pric: 매입평균가격 - 총체결금액 / 총체결수량
                - tot_ccld_amt: 총체결금액
                - prsm_tlex_smtl: 추정제비용합계 - 제세 + 주문수수료

                    ※ 해당 값은 당일 데이터에 대해서만 제공됩니다.

        Raise:
            ValueError: API 에러 발생시
        '''

        def __is_within_3month(dt: dtm.date):
            target_date = dtm.date.today().replace(day=1)

            for _ in range(3):
                target_date = target_date - dtm.timedelta(days=1)
                target_date = target_date.replace(day=1)

            three_month_ago = target_date

            return dt >= three_month_ago

        assert __is_within_3month(inqr_strt_dt) == __is_within_3month(inqr_end_dt), '3개월 이전 채결내역은 분리하여 조회해주세요.'

        within_3month = __is_within_3month(inqr_strt_dt)

        url_path = '/uapi/domestic-stock/v1/trading/inquire-daily-ccld'
        if self.auth.paper_trading:
            tr_id = 'VTTC8001R' if within_3month else 'VTSC9115R'
        else:
            tr_id = 'TTTC8001R' if within_3month else 'CTSC9115R'

        params = {
            'CANO': cano,
            'ACNT_PRDT_CD': acnt_prdt_cd,
            'INQR_STRT_DT': inqr_strt_dt.strftime('%Y%m%d'),
            'INQR_END_DT': inqr_end_dt.strftime('%Y%m%d'),
            'SLL_BUY_DVSN_CD': sll_buy_dvsn_cd,
            'INQR_DVSN': inqr_dvsn,
            'PDNO': pdno,
            'CCLD_DVSN': ccld_dvsn,
            'ORD_GNO_BRNO': '',
            'ODNO': '',
            'INQR_DVSN_3': inqr_dvsn_3,
            'INQR_DVSN_1': inqr_dvsn_1,
            'CTX_AREA_FK100': ctx_area_fk100,
            'CTX_AREA_NK100': ctx_area_nk100
        }

        res_body, res_header = 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 = []
        for el in res_body['output1']:
            for k in el.keys():
                if k == ['ord_dt', 'rsvn_ord_end_dt', 'loan_dt']:
                    if len(el[k]) == 8:
                        el[k] = dtm.datetime.strptime(el[k], '%Y%m%d').date()
                elif k in ['ord_tmd', 'infm_tmd']:
                    if len(el[k]) == 6:
                        el[k] = dtm.datetime.strptime(el[k], '%H%M%S').time()
                elif k in ['ord_qty', 'ord_unpr', 'tot_ccld_qty', 'avg_prvs', 'tot_ccld_amt', 'cncl_cfrm_qty', 'rmn_qty', 'rjct_qty']:
                    if len(el[k]) > 0:
                        el[k] = int(el[k])

            output1.append(el)

        output2 = res_body['output2']
        for k in output2.keys():
            if k == 'pchs_avg_pric':
                if len(output2[k]) > 0:
                    output2[k] = Decimal(output2[k])
            else:
                output2[k] = int(output2[k])

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'].strip(),
            'tr_cont': res_header['tr_cont'],
            'ctx_area_fk100': res_body['ctx_area_fk100'].strip(),
            'ctx_area_nk100': res_body['ctx_area_nk100'].strip(),
            'output1': output1,
            'output2': output2
        }

        return result

    def inquire_balance(self,
                        cano: str,
                        acnt_prdt_cd: str,
                        inqr_dvsn: str,
                        afhr_flpr_yn: str = 'N',
                        fund_sttl_icld_yn: str = 'N',
                        prcs_dvsn: str = '00',
                        ctx_area_fk100: str = '',
                        ctx_area_nk100: str = '',
                        tr_cont: str = ''):
        '''
        (국내주식주문) 주식잔고조회[v1_국내주식-006]

        주식 잔고조회 API입니다.

        실전계좌의 경우, 한 번의 호출에 최대 50건까지 확인 가능하며, 이후의 값은 연속조회를 통해 확인하실 수 있습니다.

        모의계좌의 경우, 한 번의 호출에 최대 20건까지 확인 가능하며, 이후의 값은 연속조회를 통해 확인하실 수 있습니다.

        * 당일 전량매도한 잔고도 보유수량 0으로 보여질 수 있으나, 해당 보유수량 0인 잔고는 최종 D-2일 이후에는 잔고에서 사라집니다.

        Args:
            cano (str): 종합계좌번호 - 계좌번호 체계(8-2)의 앞 8자리
            acnt_prdt_cd (str): 계좌상품코드 - 계좌번호 체계(8-2)의 뒤 2자리
            inqr_dvsn (str): 조회구분 - 01:대출일별 02:종목별
            afhr_flpr_yn (str): 시간외단일가여부 - N:기본값 Y:시간외단일가
            fund_sttl_icld_yn (str): 펀드결제분포함여부 - N:포함하지 않음 Y:포함
            prcs_dvsn (str): 처리구분 - 00:전일매매포함 01:전일매매미포함
            ctx_area_fk100 (str): 연속조회검색조건100 - 공란:최초 조회시. 이전 조회 output ctx_area_fk100 값:다음페이지 조회시(2번째부터)
            ctx_area_nk100 (str): 연속조회키100 - 공란:최초 조회시. 이전 조회 output ctx_area_nk100 값:다음페이지 조회시(2번째부터)
            tr_cont (str): 연속조회여부 - 공란:최초 조회시. N:연속조회 시

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 응답메시지
            - tr_cont (str): 연속조회가능여부
            - ctx_area_fk100 (str): 연속조회검색조건100
            - ctx_area_nk100 (str): 연속조회키100
            - output1 (list): 응답상세1

                - pdno: 상품번호 - 종목번호(뒷 6자리)
                - prdt_name: 상품명 - 종목명
                - trad_dvsn_name: 매매구분명 - 매수매도구분
                - bfdy_buy_qty: 전일매수수량
                - bfdy_sll_qty: 전일매도수량
                - thdt_buyqty: 금일매수수량
                - thdt_sll_qty: 금일매도수량
                - hldg_qty: 보유수량
                - ord_psbl_qty: 주문가능수량
                - pchs_avg_pric: 매입평균가격 - 매입금액 / 보유수량
                - pchs_amt: 매입금액
                - prpr: 현재가
                - evlu_amt: 평가금액
                - evlu_pfls_amt: 평가손익금액 - 평가금액 - 매입금액
                - evlu_pfls_rt: 평가손익율
                - evlu_erng_rt: 평가수익율 - 미사용항목(0으로 출력)
                - loan_dt: 대출일자 - INQR_DVSN(조회구분)을 01(대출일별)로 설정해야 값이 나옴
                - loan_amt: 대출금액
                - stln_slng_chgs: 대주매각대금
                - expd_dt: 만기일자
                - fltt_rt: 등락율
                - bfdy_cprs_icdc: 전일대비증감
                - item_mgna_rt_name: 종목증거금율명
                - grta_rt_name: 보증금율명
                - sbst_pric: 대용가격 - 증권매매의 위탁보증금으로서 현금 대신에 사용되는 유가증권 가격
                - stck_loan_unpr: 주식대출단가

            - output2 (list): 응답상세2

                - dnca_tot_amt: 예수금총금액 - 예수금
                - nxdy_excc_amt: 익일정산금액 - D+1 예수금
                - prvs_rcdl_excc_amt: 가수도정산금액 - D+2 예수금
                - cma_evlu_amt: CMA평가금액
                - bfdy_buy_amt: 전일매수금액
                - thdt_buy_amt: 금일매수금액
                - nxdy_auto_rdpt_amt: 익일자동상환금액
                - bfdy_sll_amt: 전일매도금액
                - thdt_sll_amt: 금일매도금액
                - d2_auto_rdpt_amt: D+2자동상환금액
                - bfdy_tlex_amt: 전일제비용금액
                - thdt_tlex_amt: 금일제비용금액
                - tot_loan_amt: 총대출금액
                - scts_evlu_amt: 유가평가금액
                - tot_evlu_amt: 총평가금액 - 유가증권 평가금액 합계금액 + D+2 예수금
                - nass_amt: 순자산금액
                - fncg_gld_auto_rdpt_yn: 융자금자동상환여부 - 보유현금에 대한 융자금만 차감여부. 신용융자 매수체결 시점에서는 융자비율을 매매대금 100%로 계산 하였다가 수도결제일에 보증금에 해당하는 금액을 고객의 현금으로 충당하여 융자금을 감소시키는 업무
                - pchs_amt_smtl_amt: 매입금액합계금액
                - evlu_amt_smtl_amt: 평가금액합계금액 - 유가증권 평가금액 합계금액
                - evlu_pfls_smtl_amt: 평가손익합계금액
                - tot_stln_slng_chgs: 총대주매각대금
                - bfdy_tot_asst_evlu_amt: 전일총자산평가금액
                - asst_icdc_amt: 자산증감액
                - asst_icdc_erng_rt: 자산증감수익율 - 데이터 미제공

        Raise:
            ValueError: API 에러 발생시
        '''
        assert afhr_flpr_yn in ['Y', 'N'], 'afhr_flpr_yn must be "Y" or "N"'
        assert inqr_dvsn in ['01', '02'], 'inqr_dvsn must be "01" or "02"'
        assert fund_sttl_icld_yn in ['Y', 'N'], 'fund_sttl_icld_yn must be "Y" or "N"'
        assert prcs_dvsn in ['00', '01'], 'prcs_dvsn must be "00" or "01"'

        url_path = '/uapi/domestic-stock/v1/trading/inquire-balance'
        tr_id = 'VTTC8434R' if self.auth.paper_trading else 'TTTC8434R'
        params = {
            'CANO': cano,
            'ACNT_PRDT_CD': acnt_prdt_cd,
            'INQR_DVSN': inqr_dvsn,
            'AFHR_FLPR_YN': afhr_flpr_yn,
            'OFL_YN': '',
            'UNPR_DVSN': '01',
            'FUND_STTL_ICLD_YN': fund_sttl_icld_yn,
            'FNCG_AMT_AUTO_RDPT_YN': 'N',
            'PRCS_DVSN': prcs_dvsn,
            'CTX_AREA_FK100': ctx_area_fk100,
            'CTX_AREA_NK100': ctx_area_nk100,
            'TR_CONT': tr_cont
        }

        res_body, res_header = 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 = []
        for el in res_body['output1']:
            for k in el.keys():
                if len(el[k]) == 0 or k in ['pdno', 'prdt_name', 'trad_dvsn_name', 'item_mgna_rt_name', 'grta_rt_name']:
                    pass
                elif k in ['loan_dt', 'expd_dt']:
                    el[k] = dtm.datetime.strptime(el[k], '%Y%m%d').date()
                elif k in ['pchs_avg_pric', 'evlu_pfls_rt', 'evlu_erng_rt', 'stck_loan_unpr', 'fltt_rt']:
                    el[k] = Decimal(el[k])
                else:
                    el[k] = int(el[k])

            output1.append(el)

        output2 = []
        for el in res_body['output2']:
            for k in el.keys():
                if len(el[k]) == 0 or el[k] == 'fncg_gld_auto_rdpt_yn':
                    pass
                elif k == 'asst_icdc_erng_rt':
                    el[k] = Decimal(el[k])
                else:
                    el[k] = int(el[k])

            output2.append(el)

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'].strip(),
            'tr_cont': res_header['tr_cont'].strip(),
            'ctx_area_fk100': res_body['ctx_area_fk100'].strip(),
            'ctx_area_nk100': res_body['ctx_area_nk100'].strip(),
            'output1': output1,
            'output2': output2,
        }

        return result

    def inquire_psbl_order(self,
                           cano: str,
                           acnt_prdt_cd: str,
                           pdno: str,
                           ord_dvsn: str,
                           ord_unpr: int = None,
                           cma_evlu_amt: str = 'N',
                           ovrs_icld_yn: str = 'N'):
        '''
        (국내주식주문) 매수가능조회[v1_국내주식-007]

        | 매수가능 조회 API입니다.
        | 실전계좌/모의계좌의 경우, 한 번의 호출에 최대 1건까지 확인 가능합니다.
        |
        | 1) 매수가능금액 확인
        | . 미수 사용 X: nrcvb_buy_amt(미수없는매수금액) 확인
        | . 미수 사용 O: max_buy_amt(최대매수금액) 확인
        |
        | 2) 매수가능수량 확인
        | . 특정 종목 전량매수 시 가능수량을 확인하실 경우 ORD_DVSN:00(지정가)는 종목증거금율이 반영되지 않습니다.
        | 따라서 "반드시" ORD_DVSN:01(시장가)로 지정하여 종목증거금율이 반영된 가능수량을 확인하시기 바랍니다.
        |
        | (다만, 조건부지정가 등 특정 주문구분(ex.IOC)으로 주문 시 가능수량을 확인할 경우 주문 시와 동일한 주문구분(ex.IOC) 입력하여 가능수량 확인)
        |
        | . 미수 사용 X: ORD_DVSN:01(시장가) or 특정 주문구분(ex.IOC)로 지정하여 nrcvb_buy_qty(미수없는매수수량) 확인
        | . 미수 사용 O: ORD_DVSN:01(시장가) or 특정 주문구분(ex.IOC)로 지정하여 max_buy_qty(최대매수수량) 확인

        Args:
            cano (str): 종합계좌번호 계좌번호 체계(8-2)의 앞 8자리
            acnt_prdt_cd (str): 계좌상품코드 계좌번호 체계(8-2)의 뒤 2자리
            pdno (str): 상품번호 종목번호(6자리)
            ord_unpr (int): 주문단가 1주당 가격 * 시장가(ORD_DVSN:01)로 조회 시, 공란으로 입력
            ord_dvsn (str): 주문구분

              | * 특정 종목 전량매수 시 가능수량을 확인할 경우 00:지정가는 증거금율이 반영되지 않으므로 증거금율이 반영되는 01: 시장가로 조회
              | * 다만, 조건부지정가 등 특정 주문구분(ex.IOC)으로 주문 시 가능수량을 확인할 경우 주문 시와 동일한 주문구분(ex.IOC) 입력하여 가능수량 확인
              | * 공란 시, 매수수량 없이 매수금액만 조회됨.
              |
              | 00:지정가
              | 01:시장가
              | 02:조건부지정가
              | 03:최유리지정가
              | 04:최우선지정가
              | 05:장전 시간외
              | 06:장후 시간외
              | 07:시간외 단일가
              | 08:자기주식
              | 09:자기주식S-Option
              | 10:자기주식금전신탁
              | 11:IOC지정가 (즉시체결,잔량취소)
              | 12:FOK지정가 (즉시체결,전량취소)
              | 13:IOC시장가 (즉시체결,잔량취소)
              | 14:FOK시장가 (즉시체결,전량취소)
              | 15:IOC최유리 (즉시체결,잔량취소)
              | 16:FOK최유리 (즉시체결,전량취소)
              | 51:장중대량
              | 52:장중바스켓
              | 62:장개시전 시간외대량
              | 63:장개시전 시간외바스켓
              | 67:장개시전 금전신탁자사주
              | 69:장개시전 자기주식
              | 72:시간외대량
              | 77:시간외자사주신탁
              | 79:시간외대량자기주식
              | 80:바스켓

            cma_evlu_amt_icld_yn (str): CMA평가금액포함여부 Y:포함 N:포함하지 않음
            ovrs_icld_yn (str): 해외포함여부 Y:포함 N:포함하지 않음

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 응답메시지
            - output (dict): 응답상세

                - ord_psbl_cash: 주문가능현금
                - ord_psbl_sbst: 주문가능대용
                - ruse_psbl_amt: 재사용가능금액
                - fund_rpch_chgs: 펀드환매대금
                - psbl_qty_calc_unpr: 가능수량계산단가
                - nrcvb_buy_amt: 미수없는매수금액 - 미수를 사용하지 않으실 경우 nrcvb_buy_amt(미수없는매수금액)을 확인
                - nrcvb_buy_qty: 미수없는매수수량 - 미수를 사용하지 않으실 경우 nrcvb_buy_qty(미수없는매수수량)을 확인

                    * 특정 종목 전량매수 시 가능수량을 확인하실 경우 조회 시 ORD_DVSN:01(시장가)로 지정 필수
                    * 다만, 조건부지정가 등 특정 주문구분(ex.IOC)으로 주문 시 가능수량을 확인할 경우 주문 시와 동일한 주문구분(ex.IOC) 입력

                - max_buy_amt: 최대매수금액 - 미수를 사용하시는 경우 max_buy_amt(최대매수금액)를 확인
                - max_buy_qty: 최대매수수량 - 미수를 사용하시는 경우 max_buy_qty(최대매수수량)를 확인

                    * 특정 종목 전량매수 시 가능수량을 확인하실 경우 조회 시 ORD_DVSN:01(시장가)로 지정 필수
                    * 다만, 조건부지정가 등 특정 주문구분(ex.IOC)으로 주문 시 가능수량을 확인할 경우 주문 시와 동일한 주문구분(ex.IOC) 입력

                - cma_evlu_amt: CMA평가금액
                - ovrs_re_use_amt_wcrc: 해외재사용금액원화
                - ord_psbl_frcr_amt_wcrc: 주문가능외화금액원화
        '''

        url_path = '/uapi/domestic-stock/v1/trading/inquire-psbl-order'
        tr_id = 'VTTC8908R' if self.auth.paper_trading else 'TTTC8908R'
        params = {
            'CANO': cano,
            'ACNT_PRDT_CD': acnt_prdt_cd,
            'PDNO': pdno,
            'ORD_UNPR': str(ord_unpr) if ord_unpr is not None else '',
            'ORD_DVSN': ord_dvsn,
            'CMA_EVLU_AMT_ICLD_YN': cma_evlu_amt,
            'OVRS_ICLD_YN': ovrs_icld_yn,
        }

        res_body, _ = 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']}")

        output = res_body['output']
        '''
        {
            'ord_psbl_cash': '10000000',
            'ord_psbl_sbst': '0',
            'ruse_psbl_amt': '0',
            'fund_rpch_chgs': '0',
            'psbl_qty_calc_unpr': '21645',
            'nrcvb_buy_amt': '9950248',
            'nrcvb_buy_qty': '459',
            'max_buy_amt': '9950248',
            'max_buy_qty': '459',
            'cma_evlu_amt': '0',
            'ovrs_re_use_amt_wcrc': '0',
            'ord_psbl_frcr_amt_wcrc': '0'
        }
        '''

        for k in output.keys():
            output[k] = int(output[k])

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'].strip(),
            'output': output,
        }

        return result

    def inquire_balance_rlz_pl(self,
                               cano: str,
                               acnt_prdt_cd: str,
                               afhr_flpr_yn: str = 'N',
                               fund_sttl_icld_yn: str = 'N',
                               prcs_dvsn: str = '00',
                               cost_icld_yn: str = 'N',
                               ctx_area_fk100: str = '',
                               ctx_area_nk100: str = '',
                               tr_cont: str = ''):
        '''
        (국내주식주문) 주식잔고조회_실현손익[v1_국내주식-041]

        주식잔고조회_실현손익 API입니다.

        | 한국투자 HTS(eFriend Plus) [0800] 국내 체결기준잔고 화면을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.
        | (참고: 포럼 - 공지사항 - 신규 API 추가 안내(주식잔고조회_실현손익 외 1건))

        Args:
            cano (str): 종합계좌번호 - 계좌번호 체계(8-2)의 앞 8자리
            acnt_prdt_cd (str): 계좌상품코드 - 계좌번호 체계(8-2)의 뒤 2자리
            afhr_flpr_yn (str): 시간외단일가여부 - N:기본값 Y:시간외단일가
            fund_sttl_icld_yn (str): 펀드결제포함여부 - N:포함하지 않음 Y:포함
            prcs_dvsn (str): PRCS_DVSN - 00:전일매매포함 01:전일매매미포함
            cost_icld_yn (str): 비용포함여부
            ctx_area_fk100 (str): 연속조회검색조건100 - 공란:최초 조회시. 이전 조회 output ctx_area_fk100 값:다음페이지 조회시(2번째부터)
            ctx_area_nk100 (str): 연속조회키100 - 공란:최초 조회시. 이전 조회 output ctx_area_nk100 값:다음페이지 조회시(2번째부터)

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 응답메시지
            - output1 (list): 응답상세1

                - pdno: 상품번호 - 종목번호(뒷 6자리)
                - prdt_name: 상품명 - 종목명
                - trad_dvsn_name: 매매구분명 - 매수매도구분
                - bfdy_buy_qty: 전일매수수량
                - bfdy_sll_qty: 전일매도수량
                - thdt_buyqty: 금일매수수량
                - thdt_sll_qty: 금일매도수량
                - hldg_qty: 보유수량
                - ord_psbl_qty: 주문가능수량
                - pchs_avg_pric: 매입평균가격 - 매입금액 / 보유수량
                - pchs_amt: 매입금액
                - prpr: 현재가
                - evlu_amt: 평가금액
                - evlu_pfls_amt: 평가손익금액 - 평가금액 - 매입금액
                - evlu_pfls_rt: 평가손익율
                - evlu_erng_rt: 평가수익율
                - loan_dt: 대출일자
                - loan_amt: 대출금액
                - stln_slng_chgs: 대주매각대금 - 신용 거래에서, 고객이 증권 회사로부터 대부받은 주식의 매각 대금
                - expd_dt: 만기일자
                - stck_loan_unpr: 주식대출단가
                - bfdy_cprs_icdc: 전일대비증감
                - fltt_rt: 등락율

            - output2 (list): 응답상세2

                - dnca_tot_amt: 예수금총금액
                - nxdy_excc_amt: 익일정산금액
                - prvs_rcdl_excc_amt: 가수도정산금액
                - cma_evlu_amt: CMA평가금액
                - bfdy_buy_amt: 전일매수금액
                - thdt_buy_amt: 금일매수금액
                - nxdy_auto_rdpt_amt: 익일자동상환금액
                - bfdy_sll_amt: 전일매도금액
                - thdt_sll_amt: 금일매도금액
                - d2_auto_rdpt_amt: D+2자동상환금액
                - bfdy_tlex_amt: 전일제비용금액
                - thdt_tlex_amt: 금일제비용금액
                - tot_loan_amt: 총대출금액
                - scts_evlu_amt: 유가평가금액
                - tot_evlu_amt: 총평가금액
                - nass_amt: 순자산금액
                - fncg_gld_auto_rdpt_yn: 융자금자동상환여부
                - pchs_amt_smtl_amt: 매입금액합계금액
                - evlu_amt_smtl_amt: 평가금액합계금액
                - evlu_pfls_smtl_amt: 평가손익합계금액
                - tot_stln_slng_chgs: 총대주매각대금
                - bfdy_tot_asst_evlu_amt: 전일총자산평가금액
                - asst_icdc_amt: 자산증감액
                - asst_icdc_erng_rt: 자산증감수익율
                - rlzt_pfls: 실현손익
                - rlzt_erng_rt: 실현수익율
                - real_evlu_pfls: 실평가손익
                - real_evlu_pfls_erng_rt: 실평가손익수익율

        Raise:
            ValueError: API 에러 발생시
        '''
        assert self.auth.paper_trading is False, '실전계좌에서만 조회 가능합니다.'

        url_path = '/uapi/domestic-stock/v1/trading/inquire-balance-rlz-pl'
        tr_id = 'TTTC8494R'
        params = {
            'CANO': cano,
            'ACNT_PRDT_CD': acnt_prdt_cd,
            'AFHR_FLPR_YN': afhr_flpr_yn,
            'OFL_YN': '',
            'INQR_DVSN': '00',
            'UNPR_DVSN': '01',
            'FUND_STTL_ICLD_YN': fund_sttl_icld_yn,
            'FNCG_AMT_AUTO_RDPT_YN': 'N',
            'PRCS_DVSN': prcs_dvsn,
            'COST_ICLD_YN': cost_icld_yn,
            'CTX_AREA_FK100': ctx_area_fk100,
            'CTX_AREA_NK100': ctx_area_nk100,
            'TR_CONT': tr_cont
        }

        res_body, res_header = 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 = []
        for el in res_body['output1']:
            for k in el.keys():
                if len(el[k]) == 0 or k in ['pdno', 'prdt_name', 'trad_dvsn_name']:
                    pass
                elif k in ['loan_dt', 'expd_dt']:
                    el[k] = dtm.datetime.strptime(el[k], '%Y%m%d').date()
                elif k in ['evlu_pfls_rt', 'evlu_erng_rt', 'fltt_rt', 'pchs_avg_pric', 'stck_loan_unpr']:
                    el[k] = Decimal(el[k])
                else:
                    el[k] = int(el[k])
            output1.append(el)

        output2 = []
        for el in res_body['output2']:
            for k in el.keys():
                if len(el[k]) == 0 or k in ['fncg_gld_auto_rdpt_yn']:
                    pass
                elif k in ['asst_icdc_erng_rt', 'rlzt_erng_rt', 'real_evlu_pfls_erng_rt']:
                    el[k] = Decimal(el[k])
                else:
                    el[k] = int(el[k])

            output2.append(el)

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'].strip(),
            'tr_cont': res_header['tr_cont'].strip(),
            'ctx_area_fk100': res_body['ctx_area_fk100'].strip(),
            'ctx_area_nk100': res_body['ctx_area_nk100'].strip(),
            'output1': output1,
            'output2': output2
        }

        return result

    def inquire_credit_psamount(self,
                                cano: str,
                                acnt_prdt_cd: str,
                                pdno: str,
                                ord_unpr: int,
                                ord_dvsn: str,
                                crdt_type: str,
                                cma_evlu_amt_icld_yn: str = 'N',
                                ovrs_icld_yn: str = 'N'):
        '''
        (국내주식주문) 신용매수가능조회[v1_국내주식-042]

        Args:
            cano (str): 종합계좌번호 - 계좌번호 체계(8-2)의 앞 8자리
            acnt_prdt_cd (str): 계좌상품코드 - 계좌번호 체계(8-2)의 뒤 2자리
            pdno (str): 상품번호 - 종목코드(6자리)
            ord_unpr (int): 주문단가 - 1주당 가격. * 장전 시간외, 장후 시간외, 시장가의 경우 1주당 가격을 공란으로 비우지 않음 0으로 입력 권고
            ord_dvsn (str): 주문구분 - 00:지정가 01:시장가 02:조건부지정가 03:최유리지정가 04:최우선지정가 05:장전 시간외 06:장후 시간외 07:시간외 단일가 등
            crdt_type (str): 신용유형 - 21:자기융자신규 23:유통융자신규 26:유통대주상환 28:자기대주상환 25:자기융자상환 27:유통융자상환 22:유통대주신규 24:자기대주신규
            cma_evlu_amt_icld_yn (str): CMA평가금액포함여부 - Y/N
            ovrs_icld_yn (str): 해외포함여부 - Y/N

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 응답메시지
            - output1 (list): 응답상세1

                - ORD_PSBL_CASH: 주문가능현금
                - ORD_PSBL_SBST: 주문가능대용
                - RUSE_PSBL_AMT: 재사용가능금액
                - FUND_RPCH_CHGS: 펀드환매대금
                - PSBL_QTY_CALC_UNPR: 가능수량계산단가
                - NRCVB_BUY_AMT: 미수없는매수금액
                - NRCVB_BUY_QTY: 미수없는매수수량
                - MAX_BUY_AMT: 최대매수금액
                - MAX_BUY_QTY: 최대매수수량
                - CMA_EVLU_AMT: CMA평가금액
                - OVRS_RE_USE_AMT_WCRC: 해외재사용금액원화
                - ORD_PSBL_FRCR_AMT_WCRC: 주문가능외화금액원화

        Raise:
            ValueError: API 에러 발생시
        '''
        assert self.auth.paper_trading is False, '실전계좌에서만 조회 가능합니다.'

        url_path = '/uapi/domestic-stock/v1/trading/inquire-credit-psamount'
        tr_id = 'TTTC8909R'
        params = {
            'CANO': cano,
            'ACNT_PRDT_CD': acnt_prdt_cd,
            'PDNO': pdno,
            'ORD_UNPR': ord_unpr,
            'ORD_DVSN': ord_dvsn,
            'CRDT_TYPE': crdt_type,
            'CMA_EVLU_AMT_ICLD_YN': cma_evlu_amt_icld_yn,
            'OVRS_ICLD_YN': ovrs_icld_yn,
        }

        res_body, _ = 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']}")

        output = res_body['output']
        for k in output.keys():
            if len(output[k]) == 0:
                pass
            else:
                output[k] = int(output[k])

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'].strip(),
            'output': output,
        }

        return result

    def inquire_account_balance(self,
                                cano: str,
                                acnt_prdt_cd: str):
        '''
        (국내주식주문) 투자계좌자산현황조회[v1_국내주식-048]

        투자계좌자산현황조회 API입니다.

        output1은 한국투자 HTS(eFriend Plus) > [0891] 계좌 자산비중(결제기준) 화면 아래 테이블의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.

        Args:
            cano (str): 종합계좌번호 - 계좌번호 체계(8-2)의 앞 8자리
            acnt_prdt_cd (str): 계좌상품코드 - 계좌번호 체계(8-2)의 뒤 2자리

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 응답메시지

            - output1 (list): 응답상세1

                - pchs_amt: 매입금액
                - evlu_amt: 평가금액
                - evlu_pfls_amt: 평가손익금액
                - crdt_lnd_amt: 신용대출금액
                - real_nass_amt: 실제순자산금액
                - whol_weit_rt: 전체비중율

            - output2 (dict): 응답상세2

                - pchs_amt_smtl: 매입금액합계 - 유가매입금액
                - nass_tot_amt: 순자산총금액
                - loan_amt_smtl: 대출금액합계
                - evlu_pfls_amt_smtl: 평가손익금액합계 - 평가손익금액
                - evlu_amt_smtl: 평가금액합계 - 유가평가금액
                - tot_asst_amt: 총자산금액 - 자산금액
                - tot_lnda_tot_ulst_lnda: 총대출금액총융자대출금액
                - cma_auto_loan_amt: CMA자동대출금액
                - tot_mgln_amt: 총담보대출금액
                - stln_evlu_amt: 대주평가금액
                - crdt_fncg_amt: 신용융자금액
                - ocl_apl_loan_amt: OCL_APL대출금액
                - pldg_stup_amt: 질권설정금액
                - frcr_evlu_tota: 외화평가총액
                - tot_dncl_amt: 총예수금액
                - cma_evlu_amt: CMA평가금액
                - dncl_amt: 예수금액
                - tot_sbst_amt: 총대용금액
                - thdt_rcvb_amt: 당일미수금액
                - ovrs_stck_evlu_amt1: 해외주식평가금액1
                - ovrs_bond_evlu_amt: 해외채권평가금액
                - mmf_cma_mgge_loan_amt: MMFCMA담보대출금액
                - sbsc_dncl_amt: 청약예수금액
                - pbst_sbsc_fnds_loan_use_amt: 공모주청약자금대출사용금액
                - etpr_crdt_grnt_loan_amt: 기업신용공여대출금액

        Raise:
            ValueError: API 에러 발생시
        '''
        assert self.auth.paper_trading is False, '실전계좌에서만 조회 가능합니다.'

        url_path = '/uapi/domestic-stock/v1/trading/inquire-account-balance'
        tr_id = 'CTRP6548R'
        params = {
            'CANO': cano,
            'ACNT_PRDT_CD': acnt_prdt_cd,
            'INQR_DVSN_1': '',
            'BSPR_BF_DT_APLY_YN': '',
        }

        res_body, _ = 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 = []
        for el in res_body['output1']:
            for k in el.keys():
                if len(el[k]) == 0:
                    pass
                elif k == 'whol_weit_rt':
                    el[k] = Decimal(el[k])
                else:
                    el[k] = int(el[k])

            output1.append(el)

        output2 = res_body['output2']
        for k in output2.keys():
            if len(output2[k]) == 0:
                pass
            elif k in ['ovrs_stck_evlu_amt1', 'ovrs_bond_evlu_amt']:
                output2[k] = Decimal(output2[k])
            else:
                output2[k] = int(output2[k])

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'].strip(),
            'output1': output1,
            'output2': output2
        }

        return result

    def inquire_period_trade_profit(self,
                                    cano: str,
                                    acnt_prdt_cd: str,
                                    inqr_strt_dt: dtm.date,
                                    inqr_end_dt: dtm.date,
                                    sort_dvsn: str = '00',
                                    pdno: str = '',
                                    ctx_area_nk100: str = '',
                                    ctx_area_fk100: str = '',
                                    tr_cont: str = ''):
        '''
        (국내주식주문) 기간별매매손익현황조회[v1_국내주식-060]

        기간별매매손익현황조회 API입니다.

        한국투자 HTS(eFriend Plus) > [0856] 기간별 매매손익 화면 에서 "종목별" 클릭 시의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.

        Args:
            cano (str): 종합계좌번호
            sort_dvsn (str): 정렬구분 - 00:최근순(기본값) 01:과거순 02:최근순
            acnt_prdt_cd (str): 계좌상품코드
            pdno (str): 상품번호 - "" 공란입력 시, 전체 (기본값)
            inqr_strt_dt (datetime.date): 조회시작일자
            inqr_end_dt (datetime.date): 조회종료일자
            ctx_area_nk100 (str): 연속조회키100
            ctx_area_fk100 (str): 연속조회검색조건100
            tr_cont (str): 연속조회여부 - 공란:최초 조회시. 'N':연속조회시

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 응답메시지
            - output1 (dict): 응답상세1

                - trad_dt: 매매일자
                - pdno: 상품번호 - 종목번호(뒤 6자리만 해당)
                - prdt_name: 상품명
                - trad_dvsn_name: 매매구분명
                - loan_dt: 대출일자
                - hldg_qty: 보유수량
                - pchs_unpr: 매입단가
                - buy_qty: 매수수량
                - buy_amt: 매수금액
                - sll_pric: 매도가격
                - sll_qty: 매도수량
                - sll_amt: 매도금액
                - rlzt_pfls: 실현손익
                - pfls_rt: 손익률
                - fee: 수수료
                - tl_tax: 제세금
                - loan_int: 대출이자
                - ctx_area_fk100: 연속조회검색조건100
                - ctx_area_nk100: 연속조회키100 - 100

            - output2 (list): 응답상세2

                - sll_qty_smtl: 매도수량합계
                - sll_tr_amt_smtl: 매도거래금액합계
                - sll_fee_smtl: 매도수수료합계
                - sll_tltx_smtl: 매도제세금합계
                - sll_excc_amt_smtl: 매도정산금액합계
                - buyqty_smtl: 매수수량합계
                - buy_tr_amt_smtl: 매수거래금액합계
                - buy_fee_smtl: 매수수수료합계
                - buy_tax_smtl: 매수제세금합계
                - buy_excc_amt_smtl: 매수정산금액합계
                - tot_qty: 총수량
                - tot_tr_amt: 총거래금액
                - tot_fee: 총수수료
                - tot_tltx: 총제세금
                - tot_excc_amt: 총정산금액
                - tot_rlzt_pfls: 총실현손익
                - loan_int: 대출이자
                - tot_pftrt: 총수익률

        Raise:
            ValueError: API 에러 발생시
        '''

        assert self.auth.paper_trading is False, '실전계좌에서만 조회 가능합니다.'
        assert sort_dvsn in ['00', '01', '02'], 'sort_dvsn은 00, 01, 02 중 하나여야 합니다.'

        url_path = '/uapi/domestic-stock/v1/trading/inquire-period-trade-profit'
        tr_id = 'TTTC8715R'
        params = {
            'CANO': cano,
            'SORT_DVSN': sort_dvsn,
            'ACNT_PRDT_CD': acnt_prdt_cd,
            'PDNO': pdno,
            'INQR_STRT_DT': inqr_strt_dt.strftime('%Y%m%d'),
            'INQR_END_DT': inqr_end_dt.strftime('%Y%m%d'),
            'CBLC_DVSN': '00',
            'CTX_AREA_NK100': ctx_area_nk100,
            'CTX_AREA_FK100': ctx_area_fk100,
        }

        res_body, res_header = 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 = []
        for el in res_body['output1']:
            for k in el.keys():
                if len(el[k]) == 0 or k in ['pdno', 'prdt_name', 'trad_dvsn_name']:
                    pass
                elif k in ['trad_dt', 'loan_dt']:
                    el[k] = dtm.datetime.strptime(el[k], '%Y%m%d').date()
                elif k in ['pfls_rt']:
                    el[k] = Decimal(el[k])
                else:
                    el[k] = int(el[k])

            output1.append(el)

        output2 = res_body['output2']
        '''
        {
            'sll_qty_smtl': '111',
            'sll_tr_amt_smtl': '1940820',
            'sll_fee_smtl': '81',
            'sll_tltx_smtl': '1660',
            'sll_excc_amt_smtl': '1939079',
            'buyqty_smtl': '83',
            'buy_tr_amt_smtl': '965290',
            'buy_fee_smtl': '40',
            'buy_tax_smtl': '0',
            'buy_excc_amt_smtl': '965330',
            'tot_qty': '194',
            'tot_tr_amt': '2906110',
            'tot_fee': '121',
            'tot_tltx': '1660',
            'tot_excc_amt': '2904409',
            'tot_rlzt_pfls': '8029',
            'loan_int': '0',
            'tot_pftrt': '0.41579277'
        }
        '''
        for k in output2.keys():
            if len(output2[k]) == 0:
                pass
            elif k == 'tot_pftrt':
                output2[k] = Decimal(output2[k])
            else:
                output2[k] = int(output2[k])

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'].strip(),
            'ctx_area_fk100': res_body['ctx_area_fk100'].strip(),
            'ctx_area_nk100': res_body['ctx_area_nk100'].strip(),
            'tr_cont': res_header['tr_cont'].strip(),
            'output1': output1,
            'output2': output2
        }

        return result

    def inquire_period_profit(self,
                              cano: str,
                              acnt_prdt_cd: str,
                              inqr_strt_dt: dtm.date,
                              inqr_end_dt: dtm.date,
                              pdno: str = '',
                              sort_dvsn: str = '00',
                              ctx_area_nk100: str = '',
                              ctx_area_fk100: str = '',
                              tr_cont: str = ''):

        '''
        (국내주식주문) 기간별손익일별합산조회[v1_국내주식-052]

        기간별손익일별합산조회 API입니다.

        한국투자 HTS(eFriend Plus) > [0856] 기간별 매매손익 화면 에서 "일별" 클릭 시의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.

        Args:
            acnt_prdt_cd (str): 계좌상품코드
            cano (str): 종합계좌번호
            inqr_strt_dt (datetime.date): 조회시작일자
            inqr_end_dt (datetime.date): 조회종료일자
            pdno (str): 상품번호 - "" 공란입력 시, 전체
            sort_dvsn (str): 정렬구분 - 00:최근순 01:과거순 02:최근순
            ctx_area_nk100 (str): 연속조회키100
            ctx_area_fk100 (str): 연속조회검색조건100
            tr_cont (str): 연속조회여부 - 공란:최초 조회시. 'N':연속조회시

        Returns:
            dict:

            - rt_cd (str): 응답코드
            - msg_cd (str): 메시지코드
            - msg1 (str): 응답메시지

            - output1 (list): 응답상세1

                - trad_dt: 매매일자
                - buy_amt: 매수금액
                - sll_amt: 매도금액
                - rlzt_pfls: 실현손익
                - fee: 수수료
                - loan_int: 대출이자
                - tl_tax: 제세금
                - pfls_rt: 손익률
                - sll_qty1: 매도수량1
                - buy_qty1: 매수수량1

            - outpu2 (dict): 응답상세2

                - sll_qty_smtl: 매도수량합계
                - sll_tr_amt_smtl: 매도거래금액합계
                - sll_fee_smtl: 매도수수료합계
                - sll_tltx_smtl: 매도제세금합계
                - sll_excc_amt_smtl: 매도정산금액합계
                - buy_qty_smtl: 매수수량합계
                - buy_tr_amt_smtl: 매수거래금액합계
                - buy_fee_smtl: 매수수수료합계
                - buy_tax_smtl: 매수제세금합계
                - buy_excc_amt_smtl: 매수정산금액합계
                - tot_qty: 총수량
                - tot_tr_amt: 총거래금액
                - tot_fee: 총수수료
                - tot_tltx: 총제세금
                - tot_excc_amt: 총정산금액
                - tot_rlzt_pfls: 총실현손익
                - loan_int: 대출이자

        Raise:
            ValueError: API 에러 발생시
        '''

        assert self.auth.paper_trading is False, '실전계좌에서만 조회 가능합니다.'

        url_path = '/uapi/domestic-stock/v1/trading/inquire-period-profit'
        tr_id = 'TTTC8708R'
        params = {
            'CANO': cano,
            'ACNT_PRDT_CD': acnt_prdt_cd,
            'PDNO': pdno,
            'INQR_STRT_DT': inqr_strt_dt.strftime('%Y%m%d'),
            'INQR_END_DT': inqr_end_dt.strftime('%Y%m%d'),
            'SORT_DVSN': sort_dvsn,
            'INQR_DVSN': '00',
            'CBLC_DVSN': '00',
            'CTX_AREA_NK100': ctx_area_nk100,
            'CTX_AREA_FK100': ctx_area_fk100,
        }

        res_body, res_header = 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 = []
        for el in res_body['output1']:
            for k in el.keys():
                if len(el[k]) == 0:
                    pass
                elif k == 'trad_dt':
                    el[k] = dtm.datetime.strptime(el[k], '%Y%m%d').date()
                elif k == 'pfls_rt':
                    el[k] = Decimal(el[k])
                else:
                    el[k] = int(el[k])

            output1.append(el)

        output2 = res_body['output2']

        for k in output2.keys():
            if len(output2[k]) == 0:
                pass

            output2[k] = int(output2[k])

        result = {
            'rt_cd': res_body['rt_cd'],
            'msg_cd': res_body['msg_cd'],
            'msg1': res_body['msg1'].strip(),
            'ctx_area_fk100': res_body['ctx_area_fk100'].strip(),
            'ctx_area_nk100': res_body['ctx_area_nk100'].strip(),
            'tr_cont': res_header['tr_cont'].strip(),
            'output1': output1,
            'output2': output2
        }

        return result
