initial commit
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
# DOMSTK_RANK - 국내주식 시간외잔량 순위
|
||||
# Generated by KIS API Generator (Single API Mode)
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-16
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 기본시세 > 국내주식 시간외잔량 순위[v1_국내주식-093]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/ranking/after-hour-balance"
|
||||
|
||||
def after_hour_balance(
|
||||
fid_input_price_1: str, # 입력 가격1
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
fid_cond_scr_div_code: str, # 조건 화면 분류 코드
|
||||
fid_rank_sort_cls_code: str, # 순위 정렬 구분 코드
|
||||
fid_div_cls_code: str, # 분류 구분 코드
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
fid_trgt_exls_cls_code: str, # 대상 제외 구분 코드
|
||||
fid_trgt_cls_code: str, # 대상 구분 코드
|
||||
fid_vol_cnt: str, # 거래량 수
|
||||
fid_input_price_2: str, # 입력 가격2
|
||||
tr_cont: str = "", # 연속 거래 여부
|
||||
dataframe: Optional[pd.DataFrame] = None, # 누적 데이터프레임
|
||||
depth: int = 0, # 현재 재귀 깊이
|
||||
max_depth: int = 10 # 최대 재귀 깊이
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
국내주식 시간외잔량 순위[v1_국내주식-093]
|
||||
국내주식 시간외잔량 순위 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_input_price_1 (str): 입력값 없을때 전체 (가격 ~)
|
||||
fid_cond_mrkt_div_code (str): 시장구분코드 (주식 J)
|
||||
fid_cond_scr_div_code (str): Unique key( 20176 )
|
||||
fid_rank_sort_cls_code (str): 1: 장전 시간외, 2: 장후 시간외, 3:매도잔량, 4:매수잔량
|
||||
fid_div_cls_code (str): 0 : 전체
|
||||
fid_input_iscd (str): 0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200
|
||||
fid_trgt_exls_cls_code (str): 0 : 전체
|
||||
fid_trgt_cls_code (str): 0 : 전체
|
||||
fid_vol_cnt (str): 입력값 없을때 전체 (거래량 ~)
|
||||
fid_input_price_2 (str): 입력값 없을때 전체 (~ 가격)
|
||||
tr_cont (str): 연속 거래 여부
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: 국내주식 시간외잔량 순위 데이터
|
||||
|
||||
Example:
|
||||
>>> df = after_hour_balance(
|
||||
... fid_input_price_1="",
|
||||
... fid_cond_mrkt_div_code="J",
|
||||
... fid_cond_scr_div_code="20176",
|
||||
... fid_rank_sort_cls_code="1",
|
||||
... fid_div_cls_code="0",
|
||||
... fid_input_iscd="0000",
|
||||
... fid_trgt_exls_cls_code="0",
|
||||
... fid_trgt_cls_code="0",
|
||||
... fid_vol_cnt="",
|
||||
... fid_input_price_2=""
|
||||
... )
|
||||
>>> print(df)
|
||||
"""
|
||||
# 로깅 설정
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
|
||||
if not fid_cond_scr_div_code:
|
||||
logger.error("fid_cond_scr_div_code is required. (e.g. '20176')")
|
||||
raise ValueError("fid_cond_scr_div_code is required. (e.g. '20176')")
|
||||
|
||||
if not fid_rank_sort_cls_code:
|
||||
logger.error("fid_rank_sort_cls_code is required. (e.g. '1')")
|
||||
raise ValueError("fid_rank_sort_cls_code is required. (e.g. '1')")
|
||||
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '0000')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '0000')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe if dataframe is not None else pd.DataFrame()
|
||||
|
||||
# API 호출 URL 및 거래 ID 설정
|
||||
|
||||
tr_id = "FHPST01760000"
|
||||
|
||||
# API 요청 파라미터 설정
|
||||
params = {
|
||||
"fid_input_price_1": fid_input_price_1,
|
||||
"fid_cond_mrkt_div_code": fid_cond_mrkt_div_code,
|
||||
"fid_cond_scr_div_code": fid_cond_scr_div_code,
|
||||
"fid_rank_sort_cls_code": fid_rank_sort_cls_code,
|
||||
"fid_div_cls_code": fid_div_cls_code,
|
||||
"fid_input_iscd": fid_input_iscd,
|
||||
"fid_trgt_exls_cls_code": fid_trgt_exls_cls_code,
|
||||
"fid_trgt_cls_code": fid_trgt_cls_code,
|
||||
"fid_vol_cnt": fid_vol_cnt,
|
||||
"fid_input_price_2": fid_input_price_2,
|
||||
}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
# API 호출 성공 시 데이터 처리
|
||||
if res.isOK():
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
current_data = pd.DataFrame(res.getBody().output)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
# 기존 데이터프레임과 병합
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
# 연속 거래 여부 확인
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
# 다음 페이지 호출
|
||||
if tr_cont == "M":
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return after_hour_balance(
|
||||
fid_input_price_1,
|
||||
fid_cond_mrkt_div_code,
|
||||
fid_cond_scr_div_code,
|
||||
fid_rank_sort_cls_code,
|
||||
fid_div_cls_code,
|
||||
fid_input_iscd,
|
||||
fid_trgt_exls_cls_code,
|
||||
fid_trgt_cls_code,
|
||||
fid_vol_cnt,
|
||||
fid_input_price_2,
|
||||
"N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
# API 호출 실패 시 에러 로그 출력
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,117 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-16
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from after_hour_balance import after_hour_balance
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 기본시세 > 국내주식 시간외잔량순위 [v1_국내주식-093]
|
||||
##############################################################################################
|
||||
|
||||
# 통합 컬럼 매핑
|
||||
COLUMN_MAPPING = {
|
||||
'stck_shrn_iscd': '주식 단축 종목코드',
|
||||
'data_rank': '데이터 순위',
|
||||
'hts_kor_isnm': 'HTS 한글 종목명',
|
||||
'stck_prpr': '주식 현재가',
|
||||
'prdy_vrss': '전일 대비',
|
||||
'prdy_vrss_sign': '전일 대비 부호',
|
||||
'prdy_ctrt': '전일 대비율',
|
||||
'ovtm_total_askp_rsqn': '시간외 총 매도호가 잔량',
|
||||
'ovtm_total_bidp_rsqn': '시간외 총 매수호가 잔량',
|
||||
'mkob_otcp_vol': '장개시전 시간외종가 거래량',
|
||||
'mkfa_otcp_vol': '장종료후 시간외종가 거래량'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
국내주식 시간외잔량 순위[v1_국내주식-093]
|
||||
|
||||
국내주식 시간외잔량 순위 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_input_price_1 (str): 입력 가격1 (입력값 없을때 전체 (가격 ~))
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (시장구분코드 (주식 J))
|
||||
- fid_cond_scr_div_code (str): 조건 화면 분류 코드 (Unique key( 20176 ))
|
||||
- fid_rank_sort_cls_code (str): 순위 정렬 구분 코드 (1: 장전 시간외, 2: 장후 시간외, 3:매도잔량, 4:매수잔량)
|
||||
- fid_div_cls_code (str): 분류 구분 코드 (0 : 전체)
|
||||
- fid_input_iscd (str): 입력 종목코드 (0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200)
|
||||
- fid_trgt_exls_cls_code (str): 대상 제외 구분 코드 (0 : 전체)
|
||||
- fid_trgt_cls_code (str): 대상 구분 코드 (0 : 전체)
|
||||
- fid_vol_cnt (str): 거래량 수 (입력값 없을때 전체 (거래량 ~))
|
||||
- fid_input_price_2 (str): 입력 가격2 (입력값 없을때 전체 (~ 가격))
|
||||
Returns:
|
||||
- DataFrame: 국내주식 시간외잔량 순위 결과
|
||||
|
||||
Example:
|
||||
>>> df = after_hour_balance(fid_input_price_1="", fid_cond_mrkt_div_code="J", fid_cond_scr_div_code="20176", fid_rank_sort_cls_code="1", fid_div_cls_code="0", fid_input_iscd="0000", fid_trgt_exls_cls_code="0", fid_trgt_cls_code="0", fid_vol_cnt="", fid_input_price_2="")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
|
||||
# API 호출
|
||||
logger.info("API 호출 시작: 국내주식 시간외잔량 순위")
|
||||
result = after_hour_balance(
|
||||
fid_input_price_1="", # 입력 가격1
|
||||
fid_cond_mrkt_div_code="J", # 조건 시장 분류 코드
|
||||
fid_cond_scr_div_code="20176", # 조건 화면 분류 코드
|
||||
fid_rank_sort_cls_code="1", # 순위 정렬 구분 코드
|
||||
fid_div_cls_code="0", # 분류 구분 코드
|
||||
fid_input_iscd="0000", # 입력 종목코드
|
||||
fid_trgt_exls_cls_code="0", # 대상 제외 구분 코드
|
||||
fid_trgt_cls_code="0", # 대상 구분 코드
|
||||
fid_vol_cnt="", # 거래량 수
|
||||
fid_input_price_2="" # 입력 가격2
|
||||
)
|
||||
|
||||
if result is None or result.empty:
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# 컬럼명 출력
|
||||
logger.info("사용 가능한 컬럼 목록:")
|
||||
logger.info(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
logger.info("=== 국내주식 시간외잔량 순위 결과 ===")
|
||||
logger.info("조회된 데이터 건수: %d", len(result))
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,85 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간호가 (KRX) [실시간-004]
|
||||
##############################################################################################
|
||||
|
||||
def asking_price_krx(
|
||||
tr_type: str,
|
||||
tr_key: str,
|
||||
env_dv: str = "real", # 실전모의구분
|
||||
) -> tuple[dict, list[str]]:
|
||||
"""
|
||||
국내주식 실시간 호가 데이터 구독 (KRX)[H0STASP0]
|
||||
|
||||
이 함수는 한국투자증권 웹소켓 API를 통해 실시간으로 국내주식의 호가 데이터를 구독합니다.
|
||||
웹소켓을 통해 실시간 데이터를 수신하며, 구독 등록 및 해제 기능을 제공합니다.
|
||||
|
||||
Args:
|
||||
tr_type (str): [필수] 구독 등록("1") 또는 해제("0") 여부
|
||||
tr_key (str): [필수] 종목코드 (빈 문자열 불가)
|
||||
env_dv (str): 실전모의구분 (real: 실전, demo: 모의)
|
||||
|
||||
Returns:
|
||||
message (dict): 실시간 데이터 구독에 대한 메시지 데이터
|
||||
columns (list[str]): 실시간 데이터의 컬럼 정보
|
||||
|
||||
Raises:
|
||||
ValueError: 필수 파라미터가 누락되었거나 잘못된 경우 발생
|
||||
|
||||
Example:
|
||||
>>> msg, columns = subscribe_krx_realtime_asking_price("1", "005930", env_dv="real")
|
||||
>>> print(msg, columns)
|
||||
|
||||
실시간 데이터는 웹소켓을 통해 지속적으로 수신되며, 구독 해제 시까지 계속됩니다.
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not tr_key:
|
||||
raise ValueError("tr_key는 필수 입력값입니다.")
|
||||
|
||||
# TR ID 설정 (모의투자 지원 로직)
|
||||
if env_dv == "real":
|
||||
tr_id = "H0STASP0" # 실전투자용 TR ID
|
||||
elif env_dv == "demo":
|
||||
tr_id = "H0STASP0" # 모의투자용 TR ID (웹소켓은 동일한 TR ID 사용)
|
||||
else:
|
||||
raise ValueError("env_dv는 'real' 또는 'demo'만 가능합니다.")
|
||||
|
||||
params = {
|
||||
"tr_key": tr_key,
|
||||
}
|
||||
|
||||
# 데이터 구독 요청
|
||||
msg = ka.data_fetch(tr_id, tr_type, params)
|
||||
|
||||
# 응답 데이터 컬럼 정보
|
||||
columns = [
|
||||
"MKSC_SHRN_ISCD", "BSOP_HOUR", "HOUR_CLS_CODE",
|
||||
"ASKP1", "ASKP2", "ASKP3", "ASKP4", "ASKP5",
|
||||
"ASKP6", "ASKP7", "ASKP8", "ASKP9", "ASKP10",
|
||||
"BIDP1", "BIDP2", "BIDP3", "BIDP4", "BIDP5",
|
||||
"BIDP6", "BIDP7", "BIDP8", "BIDP9", "BIDP10",
|
||||
"ASKP_RSQN1", "ASKP_RSQN2", "ASKP_RSQN3", "ASKP_RSQN4", "ASKP_RSQN5",
|
||||
"ASKP_RSQN6", "ASKP_RSQN7", "ASKP_RSQN8", "ASKP_RSQN9", "ASKP_RSQN10",
|
||||
"BIDP_RSQN1", "BIDP_RSQN2", "BIDP_RSQN3", "BIDP_RSQN4", "BIDP_RSQN5",
|
||||
"BIDP_RSQN6", "BIDP_RSQN7", "BIDP_RSQN8", "BIDP_RSQN9", "BIDP_RSQN10",
|
||||
"TOTAL_ASKP_RSQN", "TOTAL_BIDP_RSQN", "OVTM_TOTAL_ASKP_RSQN", "OVTM_TOTAL_BIDP_RSQN",
|
||||
"ANTC_CNPR", "ANTC_CNQN", "ANTC_VOL", "ANTC_CNTG_VRSS", "ANTC_CNTG_VRSS_SIGN",
|
||||
"ANTC_CNTG_PRDY_CTRT", "ACML_VOL", "TOTAL_ASKP_RSQN_ICDC", "TOTAL_BIDP_RSQN_ICDC",
|
||||
"OVTM_TOTAL_ASKP_ICDC", "OVTM_TOTAL_BIDP_ICDC", "STCK_DEAL_CLS_CODE"
|
||||
]
|
||||
|
||||
return msg, columns
|
||||
@@ -0,0 +1,155 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from asking_price_krx import asking_price_krx
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간호가 (KRX) [실시간-004]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
"MKSC_SHRN_ISCD": "유가증권 단축 종목코드",
|
||||
"BSOP_HOUR": "영업 시간",
|
||||
"HOUR_CLS_CODE": "시간 구분 코드",
|
||||
"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",
|
||||
"TOTAL_ASKP_RSQN": "총 매도호가 잔량",
|
||||
"TOTAL_BIDP_RSQN": "총 매수호가 잔량",
|
||||
"OVTM_TOTAL_ASKP_RSQN": "시간외 총 매도호가 잔량",
|
||||
"OVTM_TOTAL_BIDP_RSQN": "시간외 총 매수호가 잔량",
|
||||
"ANTC_CNPR": "예상 체결가",
|
||||
"ANTC_CNQN": "예상 체결량",
|
||||
"ANTC_VOL": "예상 거래량",
|
||||
"ANTC_CNTG_VRSS": "예상 체결 대비",
|
||||
"ANTC_CNTG_VRSS_SIGN": "예상 체결 대비 부호",
|
||||
"ANTC_CNTG_PRDY_CTRT": "예상 체결 전일 대비율",
|
||||
"ACML_VOL": "누적 거래량",
|
||||
"TOTAL_ASKP_RSQN_ICDC": "총 매도호가 잔량 증감",
|
||||
"TOTAL_BIDP_RSQN_ICDC": "총 매수호가 잔량 증감",
|
||||
"OVTM_TOTAL_ASKP_ICDC": "시간외 총 매도호가 증감",
|
||||
"OVTM_TOTAL_BIDP_ICDC": "시간외 총 매수호가 증감",
|
||||
"STCK_DEAL_CLS_CODE": "주식 매매 구분 코드"
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = [
|
||||
"매도호가1", "매도호가2", "매도호가3", "매도호가4", "매도호가5",
|
||||
"매도호가6", "매도호가7", "매도호가8", "매도호가9", "매도호가10",
|
||||
"매수호가1", "매수호가2", "매수호가3", "매수호가4", "매수호가5",
|
||||
"매수호가6", "매수호가7", "매수호가8", "매수호가9", "매수호가10",
|
||||
"매도호가 잔량1", "매도호가 잔량2", "매도호가 잔량3", "매도호가 잔량4", "매도호가 잔량5",
|
||||
"매도호가 잔량6", "매도호가 잔량7", "매도호가 잔량8", "매도호가 잔량9", "매도호가 잔량10",
|
||||
"매수호가 잔량1", "매수호가 잔량2", "매수호가 잔량3", "매수호가 잔량4", "매수호가 잔량5",
|
||||
"매수호가 잔량6", "매수호가 잔량7", "매수호가 잔량8", "매수호가 잔량9", "매수호가 잔량10",
|
||||
"총 매도호가 잔량", "총 매수호가 잔량", "시간외 총 매도호가 잔량", "시간외 총 매수호가 잔량",
|
||||
"예상 체결가", "예상 체결량", "예상 거래량", "예상 체결 대비", "예상 체결 전일 대비율",
|
||||
"누적 거래량", "총 매도호가 잔량 증감", "총 매수호가 잔량 증감", "시간외 총 매도호가 증감", "시간외 총 매수호가 증감"
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내주식 실시간호가 (KRX)
|
||||
|
||||
[호출 데이터]
|
||||
헤더와 바디 값을 합쳐 JSON 형태로 전송합니다.
|
||||
|
||||
[응답 데이터]
|
||||
1. 정상 등록 여부 (JSON)
|
||||
- JSON["body"]["msg1"] - 정상 응답 시, SUBSCRIBE SUCCESS
|
||||
- JSON["body"]["output"]["iv"] - 실시간 결과 복호화에 필요한 AES256 IV (Initialize Vector)
|
||||
- JSON["body"]["output"]["key"] - 실시간 결과 복호화에 필요한 AES256 Key
|
||||
|
||||
2. 실시간 결과 응답 ( | 로 구분되는 값)
|
||||
- 암호화 유무 : 0 암호화 되지 않은 데이터 / 1 암호화된 데이터
|
||||
- TR_ID : 등록한 tr_id
|
||||
- 데이터 건수 : (ex. 001 데이터 건수를 참조하여 활용)
|
||||
- 응답 데이터 : 아래 response 데이터 참조 ( ^로 구분됨)
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
ka.auth_ws()
|
||||
|
||||
# 인증(auth_ws()) 이후에 선언
|
||||
kws = ka.KISWebSocket(api_url="/tryitout")
|
||||
|
||||
# 조회
|
||||
kws.subscribe(request=asking_price_krx, data=["005930", "000660"])
|
||||
|
||||
# 결과 표시
|
||||
def on_result(ws, tr_id: str, result: pd.DataFrame, data_map: dict):
|
||||
try:
|
||||
# 컬럼명 매핑
|
||||
result.rename(columns=COLUMN_MAPPING, inplace=True)
|
||||
|
||||
# 숫자형 컬럼 변환
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce')
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
except Exception as e:
|
||||
logging.error(f"결과 처리 중 오류: {e}")
|
||||
logging.error(f"받은 데이터: {result}")
|
||||
|
||||
kws.start(on_result=on_result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,130 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간호가 (NXT)
|
||||
##############################################################################################
|
||||
|
||||
|
||||
|
||||
def asking_price_nxt(
|
||||
tr_type: str,
|
||||
tr_key: str,
|
||||
) -> tuple[dict, list[str]]:
|
||||
"""
|
||||
국내주식 실시간호가 (NXT)[H0NXASP0] 구독 함수
|
||||
국내주식 실시간호가 (NXT) API를 통해 실시간 데이터를 구독합니다.
|
||||
|
||||
Args:
|
||||
tr_type (str): [필수] 구독 등록("1") 또는 해제("0") 여부를 나타내는 값
|
||||
tr_key (str): [필수] 종목코드 (빈 문자열 불가)
|
||||
|
||||
Returns:
|
||||
message (dict): 실시간 데이터 메시지
|
||||
columns (list[str]): 데이터의 컬럼 정보
|
||||
|
||||
Raises:
|
||||
ValueError: tr_key가 빈 문자열인 경우 발생
|
||||
|
||||
Example:
|
||||
>>> msg, columns = subscribe_asking_price("1", "005930")
|
||||
>>> print(msg, columns)
|
||||
|
||||
Note:
|
||||
이 함수는 웹소켓을 통해 실시간 데이터를 구독합니다. 구독을 시작하면 실시간으로 데이터가 수신됩니다.
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not tr_key:
|
||||
raise ValueError("tr_key는 빈 문자열일 수 없습니다.")
|
||||
|
||||
tr_id = "H0NXASP0"
|
||||
|
||||
params = {
|
||||
"tr_key": tr_key,
|
||||
}
|
||||
|
||||
# 웹소켓을 통해 실시간 데이터 구독
|
||||
msg = ka.data_fetch(tr_id, tr_type, params)
|
||||
|
||||
# API 메타데이터 기반 컬럼 정보
|
||||
columns = [
|
||||
"MKSC_SHRN_ISCD",
|
||||
"BSOP_HOUR",
|
||||
"HOUR_CLS_CODE",
|
||||
"ASKP1",
|
||||
"ASKP2",
|
||||
"ASKP3",
|
||||
"ASKP4",
|
||||
"ASKP5",
|
||||
"ASKP6",
|
||||
"ASKP7",
|
||||
"ASKP8",
|
||||
"ASKP9",
|
||||
"ASKP10",
|
||||
"BIDP1",
|
||||
"BIDP2",
|
||||
"BIDP3",
|
||||
"BIDP4",
|
||||
"BIDP5",
|
||||
"BIDP6",
|
||||
"BIDP7",
|
||||
"BIDP8",
|
||||
"BIDP9",
|
||||
"BIDP10",
|
||||
"ASKP_RSQN1",
|
||||
"ASKP_RSQN2",
|
||||
"ASKP_RSQN3",
|
||||
"ASKP_RSQN4",
|
||||
"ASKP_RSQN5",
|
||||
"ASKP_RSQN6",
|
||||
"ASKP_RSQN7",
|
||||
"ASKP_RSQN8",
|
||||
"ASKP_RSQN9",
|
||||
"ASKP_RSQN10",
|
||||
"BIDP_RSQN1",
|
||||
"BIDP_RSQN2",
|
||||
"BIDP_RSQN3",
|
||||
"BIDP_RSQN4",
|
||||
"BIDP_RSQN5",
|
||||
"BIDP_RSQN6",
|
||||
"BIDP_RSQN7",
|
||||
"BIDP_RSQN8",
|
||||
"BIDP_RSQN9",
|
||||
"BIDP_RSQN10",
|
||||
"TOTAL_ASKP_RSQN",
|
||||
"TOTAL_BIDP_RSQN",
|
||||
"OVTM_TOTAL_ASKP_RSQN",
|
||||
"OVTM_TOTAL_BIDP_RSQN",
|
||||
"ANTC_CNPR",
|
||||
"ANTC_CNQN",
|
||||
"ANTC_VOL",
|
||||
"ANTC_CNTG_VRSS",
|
||||
"ANTC_CNTG_VRSS_SIGN",
|
||||
"ANTC_CNTG_PRDY_CTRT",
|
||||
"ACML_VOL",
|
||||
"TOTAL_ASKP_RSQN_ICDC",
|
||||
"TOTAL_BIDP_RSQN_ICDC",
|
||||
"OVTM_TOTAL_ASKP_ICDC",
|
||||
"OVTM_TOTAL_BIDP_ICDC",
|
||||
"STCK_DEAL_CLS_CODE",
|
||||
"KMID_PRC",
|
||||
"KMID_TOTAL_RSQN",
|
||||
"KMID_CLS_CODE",
|
||||
"NMID_PRC",
|
||||
"NMID_TOTAL_RSQN",
|
||||
"NMID_CLS_CODE",
|
||||
]
|
||||
|
||||
return msg, columns
|
||||
@@ -0,0 +1,151 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from asking_price_nxt import asking_price_nxt
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간호가 (NXT)
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
"MKSC_SHRN_ISCD": "유가증권 단축 종목코드",
|
||||
"BSOP_HOUR": "영업 시간",
|
||||
"HOUR_CLS_CODE": "시간 구분 코드",
|
||||
"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",
|
||||
"TOTAL_ASKP_RSQN": "총 매도호가 잔량",
|
||||
"TOTAL_BIDP_RSQN": "총 매수호가 잔량",
|
||||
"OVTM_TOTAL_ASKP_RSQN": "시간외 총 매도호가 잔량",
|
||||
"OVTM_TOTAL_BIDP_RSQN": "시간외 총 매수호가 잔량",
|
||||
"ANTC_CNPR": "예상 체결가",
|
||||
"ANTC_CNQN": "예상 체결량",
|
||||
"ANTC_VOL": "예상 거래량",
|
||||
"ANTC_CNTG_VRSS": "예상 체결 대비",
|
||||
"ANTC_CNTG_VRSS_SIGN": "예상 체결 대비 부호",
|
||||
"ANTC_CNTG_PRDY_CTRT": "예상 체결 전일 대비율",
|
||||
"ACML_VOL": "누적 거래량",
|
||||
"TOTAL_ASKP_RSQN_ICDC": "총 매도호가 잔량 증감",
|
||||
"TOTAL_BIDP_RSQN_ICDC": "총 매수호가 잔량 증감",
|
||||
"OVTM_TOTAL_ASKP_ICDC": "시간외 총 매도호가 증감",
|
||||
"OVTM_TOTAL_BIDP_ICDC": "시간외 총 매수호가 증감",
|
||||
"STCK_DEAL_CLS_CODE": "주식 매매 구분 코드",
|
||||
"KMID_PRC": "KRX 중간가",
|
||||
"KMID_TOTAL_RSQN": "KRX 중간가잔량합계수량",
|
||||
"KMID_CLS_CODE": "KRX 중간가 매수매도 구분",
|
||||
"NMID_PRC": "NXT 중간가",
|
||||
"NMID_TOTAL_RSQN": "NXT 중간가잔량합계수량",
|
||||
"NMID_CLS_CODE": "NXT 중간가 매수매도 구분"
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = [
|
||||
"매도호가1", "매도호가2", "매도호가3", "매도호가4", "매도호가5",
|
||||
"매도호가6", "매도호가7", "매도호가8", "매도호가9", "매도호가10",
|
||||
"매수호가1", "매수호가2", "매수호가3", "매수호가4", "매수호가5",
|
||||
"매수호가6", "매수호가7", "매수호가8", "매수호가9", "매수호가10",
|
||||
"매도호가 잔량1", "매도호가 잔량2", "매도호가 잔량3", "매도호가 잔량4", "매도호가 잔량5",
|
||||
"매도호가 잔량6", "매도호가 잔량7", "매도호가 잔량8", "매도호가 잔량9", "매도호가 잔량10",
|
||||
"매수호가 잔량1", "매수호가 잔량2", "매수호가 잔량3", "매수호가 잔량4", "매수호가 잔량5",
|
||||
"매수호가 잔량6", "매수호가 잔량7", "매수호가 잔량8", "매수호가 잔량9", "매수호가 잔량10",
|
||||
"총 매도호가 잔량", "총 매수호가 잔량", "시간외 총 매도호가 잔량", "시간외 총 매수호가 잔량",
|
||||
"예상 체결가", "예상 체결량", "예상 거래량", "예상 체결 대비", "예상 체결 전일 대비율",
|
||||
"누적 거래량", "총 매도호가 잔량 증감", "총 매수호가 잔량 증감",
|
||||
"시간외 총 매도호가 증감", "시간외 총 매수호가 증감", "KRX 중간가",
|
||||
"KRX 중간가잔량합계수량", "NXT 중간가", "NXT 중간가잔량합계수량"
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내주식 실시간호가 (NXT)
|
||||
|
||||
국내주식 실시간호가 (NXT) API입니다.
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
ka.auth_ws()
|
||||
|
||||
# 인증(auth_ws()) 이후에 선언
|
||||
kws = ka.KISWebSocket(api_url="/tryitout")
|
||||
|
||||
# 조회
|
||||
kws.subscribe(request=asking_price_nxt, data=["005930", "000660"])
|
||||
|
||||
# 결과 표시
|
||||
def on_result(ws, tr_id: str, result: pd.DataFrame, data_map: dict):
|
||||
try:
|
||||
|
||||
# 컬럼명 매핑
|
||||
result.rename(columns=COLUMN_MAPPING, inplace=True)
|
||||
|
||||
# 숫자형 컬럼 변환
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce')
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
except Exception as e:
|
||||
logging.error(f"결과 처리 중 오류: {e}")
|
||||
logging.error(f"받은 데이터: {result}")
|
||||
|
||||
kws.start(on_result=on_result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,129 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간호가 (통합)
|
||||
##############################################################################################
|
||||
|
||||
|
||||
def asking_price_total(
|
||||
tr_type: str,
|
||||
tr_key: str,
|
||||
) -> tuple[dict, list[str]]:
|
||||
"""
|
||||
국내주식 실시간호가 (통합)[H0UNASP0]
|
||||
국내주식 실시간호가 (통합) API를 통해 실시간 데이터를 구독합니다.
|
||||
|
||||
Args:
|
||||
tr_type (str): [필수] 구독 등록("1") 또는 해제("0") 여부를 나타내는 값
|
||||
tr_key (str): [필수] 종목코드 (빈 문자열 불가)
|
||||
|
||||
Returns:
|
||||
message (dict): 실시간 데이터 메시지
|
||||
columns (list[str]): 응답 데이터의 컬럼 정보
|
||||
|
||||
Raises:
|
||||
ValueError: tr_key가 빈 문자열인 경우 발생
|
||||
|
||||
Example:
|
||||
>>> msg, columns = subscribe_asking_price("1", "005930")
|
||||
>>> print(msg, columns)
|
||||
|
||||
Note:
|
||||
이 함수는 웹소켓을 통해 실시간 데이터를 구독합니다. 구독을 시작하면 서버로부터 실시간 데이터가 지속적으로 전송됩니다.
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not tr_key:
|
||||
raise ValueError("tr_key는 빈 문자열일 수 없습니다.")
|
||||
|
||||
tr_id = "H0UNASP0"
|
||||
|
||||
params = {
|
||||
"tr_key": tr_key,
|
||||
}
|
||||
|
||||
# 웹소켓을 통해 실시간 데이터 구독
|
||||
msg = ka.data_fetch(tr_id, tr_type, params)
|
||||
|
||||
# 응답 데이터의 컬럼 정보
|
||||
columns = [
|
||||
"MKSC_SHRN_ISCD",
|
||||
"BSOP_HOUR",
|
||||
"HOUR_CLS_CODE",
|
||||
"ASKP1",
|
||||
"ASKP2",
|
||||
"ASKP3",
|
||||
"ASKP4",
|
||||
"ASKP5",
|
||||
"ASKP6",
|
||||
"ASKP7",
|
||||
"ASKP8",
|
||||
"ASKP9",
|
||||
"ASKP10",
|
||||
"BIDP1",
|
||||
"BIDP2",
|
||||
"BIDP3",
|
||||
"BIDP4",
|
||||
"BIDP5",
|
||||
"BIDP6",
|
||||
"BIDP7",
|
||||
"BIDP8",
|
||||
"BIDP9",
|
||||
"BIDP10",
|
||||
"ASKP_RSQN1",
|
||||
"ASKP_RSQN2",
|
||||
"ASKP_RSQN3",
|
||||
"ASKP_RSQN4",
|
||||
"ASKP_RSQN5",
|
||||
"ASKP_RSQN6",
|
||||
"ASKP_RSQN7",
|
||||
"ASKP_RSQN8",
|
||||
"ASKP_RSQN9",
|
||||
"ASKP_RSQN10",
|
||||
"BIDP_RSQN1",
|
||||
"BIDP_RSQN2",
|
||||
"BIDP_RSQN3",
|
||||
"BIDP_RSQN4",
|
||||
"BIDP_RSQN5",
|
||||
"BIDP_RSQN6",
|
||||
"BIDP_RSQN7",
|
||||
"BIDP_RSQN8",
|
||||
"BIDP_RSQN9",
|
||||
"BIDP_RSQN10",
|
||||
"TOTAL_ASKP_RSQN",
|
||||
"TOTAL_BIDP_RSQN",
|
||||
"OVTM_TOTAL_ASKP_RSQN",
|
||||
"OVTM_TOTAL_BIDP_RSQN",
|
||||
"ANTC_CNPR",
|
||||
"ANTC_CNQN",
|
||||
"ANTC_VOL",
|
||||
"ANTC_CNTG_VRSS",
|
||||
"ANTC_CNTG_VRSS_SIGN",
|
||||
"ANTC_CNTG_PRDY_CTRT",
|
||||
"ACML_VOL",
|
||||
"TOTAL_ASKP_RSQN_ICDC",
|
||||
"TOTAL_BIDP_RSQN_ICDC",
|
||||
"OVTM_TOTAL_ASKP_ICDC",
|
||||
"OVTM_TOTAL_BIDP_ICDC",
|
||||
"STCK_DEAL_CLS_CODE",
|
||||
"KMID_PRC",
|
||||
"KMID_TOTAL_RSQN",
|
||||
"KMID_CLS_CODE",
|
||||
"NMID_PRC",
|
||||
"NMID_TOTAL_RSQN",
|
||||
"NMID_CLS_CODE",
|
||||
]
|
||||
|
||||
return msg, columns
|
||||
@@ -0,0 +1,151 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from asking_price_total import asking_price_total
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간호가 (통합)
|
||||
##############################################################################################
|
||||
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
"MKSC_SHRN_ISCD": "유가증권 단축 종목코드",
|
||||
"BSOP_HOUR": "영업 시간",
|
||||
"HOUR_CLS_CODE": "시간 구분 코드",
|
||||
"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",
|
||||
"TOTAL_ASKP_RSQN": "총 매도호가 잔량",
|
||||
"TOTAL_BIDP_RSQN": "총 매수호가 잔량",
|
||||
"OVTM_TOTAL_ASKP_RSQN": "시간외 총 매도호가 잔량",
|
||||
"OVTM_TOTAL_BIDP_RSQN": "시간외 총 매수호가 잔량",
|
||||
"ANTC_CNPR": "예상 체결가",
|
||||
"ANTC_CNQN": "예상 체결량",
|
||||
"ANTC_VOL": "예상 거래량",
|
||||
"ANTC_CNTG_VRSS": "예상 체결 대비",
|
||||
"ANTC_CNTG_VRSS_SIGN": "예상 체결 대비 부호",
|
||||
"ANTC_CNTG_PRDY_CTRT": "예상 체결 전일 대비율",
|
||||
"ACML_VOL": "누적 거래량",
|
||||
"TOTAL_ASKP_RSQN_ICDC": "총 매도호가 잔량 증감",
|
||||
"TOTAL_BIDP_RSQN_ICDC": "총 매수호가 잔량 증감",
|
||||
"OVTM_TOTAL_ASKP_ICDC": "시간외 총 매도호가 증감",
|
||||
"OVTM_TOTAL_BIDP_ICDC": "시간외 총 매수호가 증감",
|
||||
"STCK_DEAL_CLS_CODE": "주식 매매 구분 코드",
|
||||
"KMID_PRC": "KRX 중간가",
|
||||
"KMID_TOTAL_RSQN": "KRX 중간가잔량합계수량",
|
||||
"KMID_CLS_CODE": "KRX 중간가 매수매도 구분",
|
||||
"NMID_PRC": "NXT 중간가",
|
||||
"NMID_TOTAL_RSQN": "NXT 중간가잔량합계수량",
|
||||
"NMID_CLS_CODE": "NXT 중간가 매수매도 구분"
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = [
|
||||
"매도호가1", "매도호가2", "매도호가3", "매도호가4", "매도호가5",
|
||||
"매도호가6", "매도호가7", "매도호가8", "매도호가9", "매도호가10",
|
||||
"매수호가1", "매수호가2", "매수호가3", "매수호가4", "매수호가5",
|
||||
"매수호가6", "매수호가7", "매수호가8", "매수호가9", "매수호가10",
|
||||
"매도호가 잔량1", "매도호가 잔량2", "매도호가 잔량3", "매도호가 잔량4", "매도호가 잔량5",
|
||||
"매도호가 잔량6", "매도호가 잔량7", "매도호가 잔량8", "매도호가 잔량9", "매도호가 잔량10",
|
||||
"매수호가 잔량1", "매수호가 잔량2", "매수호가 잔량3", "매수호가 잔량4", "매수호가 잔량5",
|
||||
"매수호가 잔량6", "매수호가 잔량7", "매수호가 잔량8", "매수호가 잔량9", "매수호가 잔량10",
|
||||
"총 매도호가 잔량", "총 매수호가 잔량", "시간외 총 매도호가 잔량", "시간외 총 매수호가 잔량",
|
||||
"예상 체결가", "예상 체결량", "예상 거래량", "예상 체결 대비", "예상 체결 전일 대비율",
|
||||
"누적 거래량", "총 매도호가 잔량 증감", "총 매수호가 잔량 증감", "시간외 총 매도호가 증감",
|
||||
"시간외 총 매수호가 증감", "KRX 중간가", "KRX 중간가잔량합계수량", "NXT 중간가", "NXT 중간가잔량합계수량"
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내주식 실시간호가 (통합)
|
||||
|
||||
국내주식 실시간호가 (통합) API입니다.
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
ka.auth_ws()
|
||||
|
||||
# 인증(auth_ws()) 이후에 선언
|
||||
kws = ka.KISWebSocket(api_url="/tryitout")
|
||||
|
||||
# 조회
|
||||
kws.subscribe(request=asking_price_total, data=["005930", "000660"])
|
||||
|
||||
# 결과 표시
|
||||
def on_result(ws, tr_id: str, result: pd.DataFrame, data_map: dict):
|
||||
try:
|
||||
|
||||
# 컬럼명 매핑
|
||||
result.rename(columns=COLUMN_MAPPING, inplace=True)
|
||||
|
||||
# 숫자형 컬럼 변환
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce')
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
except Exception as e:
|
||||
logging.error(f"결과 처리 중 오류: {e}")
|
||||
logging.error(f"받은 데이터: {result}")
|
||||
|
||||
kws.start(on_result=on_result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,187 @@
|
||||
"""
|
||||
Created on 2025-06-16
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > 국내주식 대량체결건수 상위[국내주식-107]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/ranking/bulk-trans-num"
|
||||
|
||||
def bulk_trans_num(
|
||||
fid_aply_rang_prc_2: str, # 적용 범위 가격2
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
fid_cond_scr_div_code: str, # 조건 화면 분류 코드
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
fid_rank_sort_cls_code: str, # 순위 정렬 구분 코드
|
||||
fid_div_cls_code: str, # 분류 구분 코드
|
||||
fid_input_price_1: str, # 입력 가격1
|
||||
fid_aply_rang_prc_1: str, # 적용 범위 가격1
|
||||
fid_input_iscd_2: str, # 입력 종목코드2
|
||||
fid_trgt_exls_cls_code: str, # 대상 제외 구분 코드
|
||||
fid_trgt_cls_code: str, # 대상 구분 코드
|
||||
fid_vol_cnt: str, # 거래량 수
|
||||
tr_cont: str = "", # 연속 거래 여부
|
||||
dataframe: Optional[pd.DataFrame] = None, # 누적 데이터프레임
|
||||
depth: int = 0, # 현재 재귀 깊이
|
||||
max_depth: int = 10 # 최대 재귀 깊이
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
국내주식 대량체결건수 상위[국내주식-107]
|
||||
국내주식 대량체결건수 상위 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_aply_rang_prc_2 (str): ~ 가격
|
||||
fid_cond_mrkt_div_code (str): 시장구분코드 (J:KRX, NX:NXT)
|
||||
fid_cond_scr_div_code (str): Unique key(11909)
|
||||
fid_input_iscd (str): 0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200, 4001: KRX100
|
||||
fid_rank_sort_cls_code (str): 0:매수상위, 1:매도상위
|
||||
fid_div_cls_code (str): 0:전체
|
||||
fid_input_price_1 (str): 건별금액 ~
|
||||
fid_aply_rang_prc_1 (str): 가격 ~
|
||||
fid_input_iscd_2 (str): 공백:전체종목, 개별종목 조회시 종목코드 (000660)
|
||||
fid_trgt_exls_cls_code (str): 0:전체
|
||||
fid_trgt_cls_code (str): 0:전체
|
||||
fid_vol_cnt (str): 거래량 ~
|
||||
tr_cont (str): 연속 거래 여부
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: 국내주식 대량체결건수 상위 데이터
|
||||
|
||||
Example:
|
||||
>>> df = bulk_trans_num(
|
||||
fid_aply_rang_prc_2="100000",
|
||||
fid_cond_mrkt_div_code="J",
|
||||
fid_cond_scr_div_code="11909",
|
||||
fid_input_iscd="0000",
|
||||
fid_rank_sort_cls_code="0",
|
||||
fid_div_cls_code="0",
|
||||
fid_input_price_1="50000",
|
||||
fid_aply_rang_prc_1="200000",
|
||||
fid_input_iscd_2="",
|
||||
fid_trgt_exls_cls_code="0",
|
||||
fid_trgt_cls_code="0",
|
||||
fid_vol_cnt="1000"
|
||||
)
|
||||
>>> print(df)
|
||||
"""
|
||||
# 로깅 설정
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
|
||||
if not fid_cond_scr_div_code:
|
||||
logger.error("fid_cond_scr_div_code is required. (e.g. '11909')")
|
||||
raise ValueError("fid_cond_scr_div_code is required. (e.g. '11909')")
|
||||
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '0000')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '0000')")
|
||||
|
||||
if not fid_rank_sort_cls_code:
|
||||
logger.error("fid_rank_sort_cls_code is required. (e.g. '0')")
|
||||
raise ValueError("fid_rank_sort_cls_code is required. (e.g. '0')")
|
||||
|
||||
if not fid_div_cls_code:
|
||||
logger.error("fid_div_cls_code is required. (e.g. '0')")
|
||||
raise ValueError("fid_div_cls_code is required. (e.g. '0')")
|
||||
|
||||
if not fid_trgt_exls_cls_code:
|
||||
logger.error("fid_trgt_exls_cls_code is required. (e.g. '0')")
|
||||
raise ValueError("fid_trgt_exls_cls_code is required. (e.g. '0')")
|
||||
|
||||
if not fid_trgt_cls_code:
|
||||
logger.error("fid_trgt_cls_code is required. (e.g. '0')")
|
||||
raise ValueError("fid_trgt_cls_code is required. (e.g. '0')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe if dataframe is not None else pd.DataFrame()
|
||||
|
||||
|
||||
tr_id = "FHKST190900C0"
|
||||
|
||||
params = {
|
||||
"fid_aply_rang_prc_2": fid_aply_rang_prc_2,
|
||||
"fid_cond_mrkt_div_code": fid_cond_mrkt_div_code,
|
||||
"fid_cond_scr_div_code": fid_cond_scr_div_code,
|
||||
"fid_input_iscd": fid_input_iscd,
|
||||
"fid_rank_sort_cls_code": fid_rank_sort_cls_code,
|
||||
"fid_div_cls_code": fid_div_cls_code,
|
||||
"fid_input_price_1": fid_input_price_1,
|
||||
"fid_aply_rang_prc_1": fid_aply_rang_prc_1,
|
||||
"fid_input_iscd_2": fid_input_iscd_2,
|
||||
"fid_trgt_exls_cls_code": fid_trgt_exls_cls_code,
|
||||
"fid_trgt_cls_code": fid_trgt_cls_code,
|
||||
"fid_vol_cnt": fid_vol_cnt,
|
||||
}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
# 응답 데이터 처리
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
current_data = pd.DataFrame(res.getBody().output)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
# 데이터프레임 병합
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
# 다음 페이지 여부 확인
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont == "M":
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return bulk_trans_num(
|
||||
fid_aply_rang_prc_2,
|
||||
fid_cond_mrkt_div_code,
|
||||
fid_cond_scr_div_code,
|
||||
fid_input_iscd,
|
||||
fid_rank_sort_cls_code,
|
||||
fid_div_cls_code,
|
||||
fid_input_price_1,
|
||||
fid_aply_rang_prc_1,
|
||||
fid_input_iscd_2,
|
||||
fid_trgt_exls_cls_code,
|
||||
fid_trgt_cls_code,
|
||||
fid_vol_cnt,
|
||||
"N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
# API 호출 실패 시 에러 로그
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,121 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-16
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from bulk_trans_num import bulk_trans_num
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > 국내주식 대량체결건수 상위[국내주식-107]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'mksc_shrn_iscd': '유가증권 단축 종목코드',
|
||||
'data_rank': '데이터 순위',
|
||||
'hts_kor_isnm': 'HTS 한글 종목명',
|
||||
'stck_prpr': '주식 현재가',
|
||||
'prdy_vrss_sign': '전일 대비 부호',
|
||||
'prdy_vrss': '전일 대비',
|
||||
'prdy_ctrt': '전일 대비율',
|
||||
'acml_vol': '누적 거래량',
|
||||
'shnu_cntg_csnu': '매수2 체결 건수',
|
||||
'seln_cntg_csnu': '매도 체결 건수',
|
||||
'ntby_cnqn': '순매수 체결량'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
국내주식 대량체결건수 상위[국내주식-107]
|
||||
|
||||
국내주식 대량체결건수 상위 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_aply_rang_prc_2 (str): 적용 범위 가격2 (~ 가격)
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (시장구분코드 (주식 J))
|
||||
- fid_cond_scr_div_code (str): 조건 화면 분류 코드 (Unique key(11909))
|
||||
- fid_input_iscd (str): 입력 종목코드 (0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200, 4001: KRX100)
|
||||
- fid_rank_sort_cls_code (str): 순위 정렬 구분 코드 (0:매수상위, 1:매도상위)
|
||||
- fid_div_cls_code (str): 분류 구분 코드 (0:전체)
|
||||
- fid_input_price_1 (str): 입력 가격1 (건별금액 ~)
|
||||
- fid_aply_rang_prc_1 (str): 적용 범위 가격1 (가격 ~)
|
||||
- fid_input_iscd_2 (str): 입력 종목코드2 (공백:전체종목, 개별종목 조회시 종목코드 (000660))
|
||||
- fid_trgt_exls_cls_code (str): 대상 제외 구분 코드 (0:전체)
|
||||
- fid_trgt_cls_code (str): 대상 구분 코드 (0:전체)
|
||||
- fid_vol_cnt (str): 거래량 수 (거래량 ~)
|
||||
Returns:
|
||||
- DataFrame: 국내주식 대량체결건수 상위 결과
|
||||
|
||||
Example:
|
||||
>>> df = bulk_trans_num(fid_aply_rang_prc_2="", fid_cond_mrkt_div_code="J", fid_cond_scr_div_code="11909", fid_input_iscd="0000", fid_rank_sort_cls_code="0", fid_div_cls_code="0", fid_input_price_1="", fid_aply_rang_prc_1="", fid_input_iscd_2="", fid_trgt_exls_cls_code="0", fid_trgt_cls_code="0", fid_vol_cnt="")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
|
||||
# API 호출
|
||||
logger.info("API 호출 시작: 국내주식 대량체결건수 상위")
|
||||
result = bulk_trans_num(
|
||||
fid_aply_rang_prc_2="", # 적용 범위 가격2
|
||||
fid_cond_mrkt_div_code="J", # 조건 시장 분류 코드
|
||||
fid_cond_scr_div_code="11909", # 조건 화면 분류 코드
|
||||
fid_input_iscd="0000", # 입력 종목코드
|
||||
fid_rank_sort_cls_code="0", # 순위 정렬 구분 코드
|
||||
fid_div_cls_code="0", # 분류 구분 코드
|
||||
fid_input_price_1="", # 입력 가격1
|
||||
fid_aply_rang_prc_1="", # 적용 범위 가격1
|
||||
fid_input_iscd_2="", # 입력 종목코드2
|
||||
fid_trgt_exls_cls_code="0", # 대상 제외 구분 코드
|
||||
fid_trgt_cls_code="0", # 대상 구분 코드
|
||||
fid_vol_cnt="", # 거래량 수
|
||||
)
|
||||
|
||||
if result is None or result.empty:
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# 컬럼명 출력
|
||||
logger.info("사용 가능한 컬럼 목록:")
|
||||
logger.info(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
logger.info("=== 국내주식 대량체결건수 상위 결과 ===")
|
||||
logger.info("조회된 데이터 건수: %d", len(result))
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,98 @@
|
||||
"""
|
||||
Created on 20250113
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 국내주식 상하한가 포착 [국내주식-190]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/capture-uplowprice"
|
||||
|
||||
|
||||
def capture_uplowprice(
|
||||
fid_cond_mrkt_div_code: str, # [필수] 조건시장분류코드 (ex. J:주식)
|
||||
fid_cond_scr_div_code: str, # [필수] 조건화면분류코드 (ex. 11300)
|
||||
fid_prc_cls_code: str, # [필수] 상하한가 구분코드 (ex. 0:상한가, 1:하한가)
|
||||
fid_div_cls_code: str,
|
||||
# [필수] 분류구분코드 (ex. 0:상하한가종목, 6:8%상하한가 근접, 5:10%상하한가 근접, 1:15%상하한가 근접, 2:20%상하한가 근접, 3:25%상하한가 근접)
|
||||
fid_input_iscd: str, # [필수] 입력종목코드 (ex. 0000:전체, 0001:코스피, 1001:코스닥)
|
||||
fid_trgt_cls_code: str = "", # 대상구분코드
|
||||
fid_trgt_exls_cls_code: str = "", # 대상제외구분코드
|
||||
fid_input_price_1: str = "", # 입력가격1
|
||||
fid_input_price_2: str = "", # 입력가격2
|
||||
fid_vol_cnt: str = "" # 거래량수
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
국내주식 상하한가 포착 API입니다.
|
||||
한국투자 HTS(eFriend Plus) > [0917] 실시간 상하한가 포착 화면 의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.
|
||||
|
||||
Args:
|
||||
fid_cond_mrkt_div_code (str): [필수] 조건시장분류코드 (ex. J:주식)
|
||||
fid_cond_scr_div_code (str): [필수] 조건화면분류코드 (ex. 11300)
|
||||
fid_prc_cls_code (str): [필수] 상하한가 구분코드 (ex. 0:상한가, 1:하한가)
|
||||
fid_div_cls_code (str): [필수] 분류구분코드 (ex. 0:상하한가종목, 6:8%상하한가 근접, 5:10%상하한가 근접, 1:15%상하한가 근접, 2:20%상하한가 근접, 3:25%상하한가 근접)
|
||||
fid_input_iscd (str): [필수] 입력종목코드 (ex. 0000:전체, 0001:코스피, 1001:코스닥)
|
||||
fid_trgt_cls_code (str): 대상구분코드
|
||||
fid_trgt_exls_cls_code (str): 대상제외구분코드
|
||||
fid_input_price_1 (str): 입력가격1
|
||||
fid_input_price_2 (str): 입력가격2
|
||||
fid_vol_cnt (str): 거래량수
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: 상하한가 포착 데이터
|
||||
|
||||
Example:
|
||||
>>> df = capture_uplowprice("J", "11300", "0", "0", "0000")
|
||||
>>> print(df)
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if fid_cond_mrkt_div_code == "":
|
||||
raise ValueError("fid_cond_mrkt_div_code is required (e.g. 'J')")
|
||||
|
||||
if fid_cond_scr_div_code == "":
|
||||
raise ValueError("fid_cond_scr_div_code is required (e.g. '11300')")
|
||||
|
||||
if fid_prc_cls_code == "":
|
||||
raise ValueError("fid_prc_cls_code is required (e.g. '0', '1')")
|
||||
|
||||
if fid_div_cls_code == "":
|
||||
raise ValueError("fid_div_cls_code is required (e.g. '0', '6', '5', '1', '2', '3')")
|
||||
|
||||
if fid_input_iscd == "":
|
||||
raise ValueError("fid_input_iscd is required (e.g. '0000', '0001', '1001')")
|
||||
|
||||
tr_id = "FHKST130000C0"
|
||||
|
||||
params = {
|
||||
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code,
|
||||
"FID_COND_SCR_DIV_CODE": fid_cond_scr_div_code,
|
||||
"FID_PRC_CLS_CODE": fid_prc_cls_code,
|
||||
"FID_DIV_CLS_CODE": fid_div_cls_code,
|
||||
"FID_INPUT_ISCD": fid_input_iscd,
|
||||
"FID_TRGT_CLS_CODE": fid_trgt_cls_code,
|
||||
"FID_TRGT_EXLS_CLS_CODE": fid_trgt_exls_cls_code,
|
||||
"FID_INPUT_PRICE_1": fid_input_price_1,
|
||||
"FID_INPUT_PRICE_2": fid_input_price_2,
|
||||
"FID_VOL_CNT": fid_vol_cnt
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, "", params)
|
||||
|
||||
if res.isOK():
|
||||
return pd.DataFrame(res.getBody().output)
|
||||
else:
|
||||
res.printError(url=API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,91 @@
|
||||
"""
|
||||
Created on 20250113
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from capture_uplowprice import capture_uplowprice
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 국내주식 상하한가 포착 [국내주식-190]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'mksc_shrn_iscd': '유가증권단축종목코드',
|
||||
'hts_kor_isnm': 'HTS한글종목명',
|
||||
'stck_prpr': '주식현재가',
|
||||
'prdy_vrss_sign': '전일대비부호',
|
||||
'prdy_vrss': '전일대비',
|
||||
'prdy_ctrt': '전일대비율',
|
||||
'acml_vol': '누적거래량',
|
||||
'total_askp_rsqn': '총매도호가잔량',
|
||||
'total_bidp_rsqn': '총매수호가잔량',
|
||||
'askp_rsqn1': '매도호가잔량1',
|
||||
'bidp_rsqn1': '매수호가잔량1',
|
||||
'prdy_vol': '전일거래량',
|
||||
'seln_cnqn': '매도체결량',
|
||||
'shnu_cnqn': '매수2체결량',
|
||||
'stck_llam': '주식하한가',
|
||||
'stck_mxpr': '주식상한가',
|
||||
'prdy_vrss_vol_rate': '전일대비거래량비율'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내주식 상하한가 포착 조회 테스트 함수
|
||||
|
||||
이 함수는 국내주식 상하한가 포착 API를 호출하여 결과를 출력합니다.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
# case1 조회
|
||||
logging.info("=== case1 조회 ===")
|
||||
try:
|
||||
result = capture_uplowprice(
|
||||
fid_cond_mrkt_div_code="J",
|
||||
fid_cond_scr_div_code="11300",
|
||||
fid_prc_cls_code="0",
|
||||
fid_div_cls_code="0",
|
||||
fid_input_iscd="0000"
|
||||
)
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
logging.info("사용 가능한 컬럼: %s", result.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환 및 데이터 출력
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
85
한국투자증권(API)/examples_llm/domestic_stock/ccnl_krx/ccnl_krx.py
Normal file
85
한국투자증권(API)/examples_llm/domestic_stock/ccnl_krx/ccnl_krx.py
Normal file
@@ -0,0 +1,85 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간체결가(KRX) [실시간-003]
|
||||
##############################################################################################
|
||||
|
||||
def ccnl_krx(
|
||||
tr_type: str,
|
||||
tr_key: str,
|
||||
env_dv: str = "real", # 실전모의구분
|
||||
) -> tuple[dict, list[str]]:
|
||||
"""
|
||||
국내주식 실시간체결가 (KRX)[H0STCNT0] 구독 함수
|
||||
|
||||
이 함수는 한국투자증권 웹소켓 API를 통해 국내 주식의 실시간 체결가 데이터를 구독합니다.
|
||||
실시간 데이터를 구독하거나 구독 해제할 수 있습니다.
|
||||
|
||||
Args:
|
||||
tr_type (str): [필수] 구독 등록("1") 또는 해제("0") 여부
|
||||
tr_key (str): [필수] 종목코드 (빈 문자열 불가)
|
||||
env_dv (str): 실전모의구분 (real:실전, demo:모의)
|
||||
|
||||
Returns:
|
||||
message (dict): 메시지 데이터
|
||||
columns (list[str]): 컬럼 정보
|
||||
|
||||
Raises:
|
||||
ValueError: tr_key가 빈 문자열인 경우
|
||||
ValueError: env_dv가 'real' 또는 'demo'가 아닌 경우
|
||||
|
||||
Example:
|
||||
>>> msg, columns = ccnl_krx("1", "005930", env_dv="real")
|
||||
>>> print(msg, columns)
|
||||
|
||||
실시간 데이터는 웹소켓을 통해 지속적으로 업데이트됩니다.
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not tr_key:
|
||||
raise ValueError("tr_key is required and cannot be an empty string")
|
||||
|
||||
# TR ID 설정 (모의투자 지원 로직)
|
||||
if env_dv == "real":
|
||||
tr_id = "H0STCNT0" # 실전투자용 TR ID
|
||||
elif env_dv == "demo":
|
||||
tr_id = "H0STCNT0" # 모의투자용 TR ID (웹소켓은 동일한 TR ID 사용)
|
||||
else:
|
||||
raise ValueError("env_dv can only be 'real' or 'demo'")
|
||||
|
||||
params = {
|
||||
"tr_key": tr_key,
|
||||
}
|
||||
|
||||
# 데이터 구독 요청
|
||||
msg = ka.data_fetch(tr_id, tr_type, params)
|
||||
|
||||
# 응답 데이터 컬럼 정보
|
||||
columns = [
|
||||
"MKSC_SHRN_ISCD", "STCK_CNTG_HOUR", "STCK_PRPR", "PRDY_VRSS_SIGN",
|
||||
"PRDY_VRSS", "PRDY_CTRT", "WGHN_AVRG_STCK_PRC", "STCK_OPRC",
|
||||
"STCK_HGPR", "STCK_LWPR", "ASKP1", "BIDP1", "CNTG_VOL", "ACML_VOL",
|
||||
"ACML_TR_PBMN", "SELN_CNTG_CSNU", "SHNU_CNTG_CSNU", "NTBY_CNTG_CSNU",
|
||||
"CTTR", "SELN_CNTG_SMTN", "SHNU_CNTG_SMTN", "CCLD_DVSN", "SHNU_RATE",
|
||||
"PRDY_VOL_VRSS_ACML_VOL_RATE", "OPRC_HOUR", "OPRC_VRSS_PRPR_SIGN",
|
||||
"OPRC_VRSS_PRPR", "HGPR_HOUR", "HGPR_VRSS_PRPR_SIGN", "HGPR_VRSS_PRPR",
|
||||
"LWPR_HOUR", "LWPR_VRSS_PRPR_SIGN", "LWPR_VRSS_PRPR", "BSOP_DATE",
|
||||
"NEW_MKOP_CLS_CODE", "TRHT_YN", "ASKP_RSQN1", "BIDP_RSQN1",
|
||||
"TOTAL_ASKP_RSQN", "TOTAL_BIDP_RSQN", "VOL_TNRT",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL", "PRDY_SMNS_HOUR_ACML_VOL_RATE",
|
||||
"HOUR_CLS_CODE", "MRKT_TRTM_CLS_CODE", "VI_STND_PRC"
|
||||
]
|
||||
|
||||
return msg, columns
|
||||
149
한국투자증권(API)/examples_llm/domestic_stock/ccnl_krx/chk_ccnl_krx.py
Normal file
149
한국투자증권(API)/examples_llm/domestic_stock/ccnl_krx/chk_ccnl_krx.py
Normal file
@@ -0,0 +1,149 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from ccnl_krx import ccnl_krx
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간체결가(KRX) [실시간-003]
|
||||
##############################################################################################
|
||||
|
||||
|
||||
# 컬럼 매핑
|
||||
COLUMN_MAPPING = {
|
||||
"MKSC_SHRN_ISCD": "유가증권 단축 종목코드",
|
||||
"STCK_CNTG_HOUR": "주식 체결 시간",
|
||||
"STCK_PRPR": "주식 현재가",
|
||||
"PRDY_VRSS_SIGN": "전일 대비 부호",
|
||||
"PRDY_VRSS": "전일 대비",
|
||||
"PRDY_CTRT": "전일 대비율",
|
||||
"WGHN_AVRG_STCK_PRC": "가중 평균 주식 가격",
|
||||
"STCK_OPRC": "주식 시가",
|
||||
"STCK_HGPR": "주식 최고가",
|
||||
"STCK_LWPR": "주식 최저가",
|
||||
"ASKP1": "매도호가1",
|
||||
"BIDP1": "매수호가1",
|
||||
"CNTG_VOL": "체결 거래량",
|
||||
"ACML_VOL": "누적 거래량",
|
||||
"ACML_TR_PBMN": "누적 거래 대금",
|
||||
"SELN_CNTG_CSNU": "매도 체결 건수",
|
||||
"SHNU_CNTG_CSNU": "매수 체결 건수",
|
||||
"NTBY_CNTG_CSNU": "순매수 체결 건수",
|
||||
"CTTR": "체결강도",
|
||||
"SELN_CNTG_SMTN": "총 매도 수량",
|
||||
"SHNU_CNTG_SMTN": "총 매수 수량",
|
||||
"CCLD_DVSN": "체결구분",
|
||||
"SHNU_RATE": "매수비율",
|
||||
"PRDY_VOL_VRSS_ACML_VOL_RATE": "전일 거래량 대비 등락율",
|
||||
"OPRC_HOUR": "시가 시간",
|
||||
"OPRC_VRSS_PRPR_SIGN": "시가대비구분",
|
||||
"OPRC_VRSS_PRPR": "시가대비",
|
||||
"HGPR_HOUR": "최고가 시간",
|
||||
"HGPR_VRSS_PRPR_SIGN": "고가대비구분",
|
||||
"HGPR_VRSS_PRPR": "고가대비",
|
||||
"LWPR_HOUR": "최저가 시간",
|
||||
"LWPR_VRSS_PRPR_SIGN": "저가대비구분",
|
||||
"LWPR_VRSS_PRPR": "저가대비",
|
||||
"BSOP_DATE": "영업 일자",
|
||||
"NEW_MKOP_CLS_CODE": "신 장운영 구분 코드",
|
||||
"TRHT_YN": "거래정지 여부",
|
||||
"ASKP_RSQN1": "매도호가 잔량1",
|
||||
"BIDP_RSQN1": "매수호가 잔량1",
|
||||
"TOTAL_ASKP_RSQN": "총 매도호가 잔량",
|
||||
"TOTAL_BIDP_RSQN": "총 매수호가 잔량",
|
||||
"VOL_TNRT": "거래량 회전율",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL": "전일 동시간 누적 거래량",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL_RATE": "전일 동시간 누적 거래량 비율",
|
||||
"HOUR_CLS_CODE": "시간 구분 코드",
|
||||
"MRKT_TRTM_CLS_CODE": "임의종료구분코드",
|
||||
"VI_STND_PRC": "정적VI발동기준가"
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = [
|
||||
"주식 현재가", "전일 대비", "전일 대비율", "가중 평균 주식 가격", "주식 시가", "주식 최고가", "주식 최저가",
|
||||
"매도호가1", "매수호가1", "체결 거래량", "누적 거래량", "누적 거래 대금", "매도 체결 건수", "매수 체결 건수",
|
||||
"순매수 체결 건수", "체결강도", "총 매도 수량", "총 매수 수량", "매수비율", "전일 거래량 대비 등락율",
|
||||
"시가대비", "고가대비", "저가대비", "매도호가 잔량1", "매수호가 잔량1", "총 매도호가 잔량", "총 매수호가 잔량",
|
||||
"거래량 회전율", "전일 동시간 누적 거래량", "전일 동시간 누적 거래량 비율", "정적VI발동기준가"
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내주식 실시간체결가 (KRX)
|
||||
|
||||
[참고자료]
|
||||
|
||||
종목코드 마스터파일 파이썬 정제코드는 한국투자증권 Github 참고 부탁드립니다.
|
||||
https://github.com/koreainvestment/open-trading-api/tree/main/stocks_info
|
||||
|
||||
[호출 데이터]
|
||||
헤더와 바디 값을 합쳐 JSON 형태로 전송합니다.
|
||||
|
||||
[응답 데이터]
|
||||
1. 정상 등록 여부 (JSON)
|
||||
- JSON["body"]["msg1"] - 정상 응답 시, SUBSCRIBE SUCCESS
|
||||
- JSON["body"]["output"]["iv"] - 실시간 결과 복호화에 필요한 AES256 IV (Initialize Vector)
|
||||
- JSON["body"]["output"]["key"] - 실시간 결과 복호화에 필요한 AES256 Key
|
||||
|
||||
2. 실시간 결과 응답 ( | 로 구분되는 값)
|
||||
ex) 0|H0STCNT0|004|005930^123929^73100^5^...
|
||||
- 암호화 유무 : 0 암호화 되지 않은 데이터 / 1 암호화된 데이터
|
||||
- TR_ID : 등록한 tr_id (ex. H0STCNT0)
|
||||
- 데이터 건수 : (ex. 001 인 경우 데이터 건수 1건, 004인 경우 데이터 건수 4건)
|
||||
- 응답 데이터 : 아래 response 데이터 참조 ( ^로 구분됨)
|
||||
|
||||
※ 데이터가 많은 경우 여러 건을 페이징 처리해서 데이터를 보내는 점 참고 부탁드립니다.
|
||||
ex) 0|H0STCNT0|004|... 인 경우 004가 데이터 개수를 의미하여, 뒤에 체결데이터가 4건 들어옴
|
||||
→ 0|H0STCNT0|004|005930^123929...(체결데이터1)...^005930^123929...(체결데이터2)...^005930^123929...(체결데이터3)...^005930^123929...(체결데이터4)...
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
ka.auth_ws()
|
||||
|
||||
# 인증(auth_ws()) 이후에 선언
|
||||
kws = ka.KISWebSocket(api_url="/tryitout")
|
||||
|
||||
# 조회
|
||||
kws.subscribe(request=ccnl_krx, data=["005930", "000660"])
|
||||
|
||||
# 결과 표시
|
||||
def on_result(ws, tr_id: str, result: pd.DataFrame, data_map: dict):
|
||||
try:
|
||||
|
||||
# 컬럼명 매핑
|
||||
result.rename(columns=COLUMN_MAPPING, inplace=True)
|
||||
|
||||
# 숫자형 컬럼 변환
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce')
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
except Exception as e:
|
||||
logging.error(f"결과 처리 중 오류: {e}")
|
||||
logging.error(f"받은 데이터: {result}")
|
||||
|
||||
kws.start(on_result=on_result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,78 @@
|
||||
"""
|
||||
Created on 2025-07-08
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 주식체결통보 [실시간-005]
|
||||
##############################################################################################
|
||||
|
||||
def ccnl_notice(
|
||||
tr_type: str,
|
||||
tr_key: str,
|
||||
env_dv: str = "real", # 실전모의구분
|
||||
) -> tuple[dict, list[str]]:
|
||||
"""
|
||||
국내주식 실시간체결통보[H0STCNI0]
|
||||
국내주식 실시간 체결통보 수신 시에 (1) 주문·정정·취소·거부 접수 통보 와 (2) 체결 통보 가 모두 수신됩니다.
|
||||
(14번째 값(CNTG_YN;체결여부)가 2이면 체결통보, 1이면 주문·정정·취소·거부 접수 통보입니다.)
|
||||
|
||||
※ 모의투자는 H0STCNI9 로 변경하여 사용합니다.
|
||||
|
||||
실시간 데이터 구독을 위한 웹소켓 함수입니다. 구독을 등록하거나 해제할 수 있습니다.
|
||||
|
||||
Args:
|
||||
tr_type (str): [필수] 구독 등록("1")/해제("0") 여부
|
||||
tr_key (str): [필수] 종목코드 (예: "005930")
|
||||
env_dv (str): 실전모의구분 (real:실전, demo:모의)
|
||||
|
||||
Returns:
|
||||
message (dict): 메시지 데이터
|
||||
columns (list[str]): 컬럼 정보
|
||||
|
||||
Example:
|
||||
>>> msg, columns = ccnl_notice("1", "005930", env_dv="real")
|
||||
>>> print(msg, columns)
|
||||
|
||||
웹소켓을 통해 실시간 데이터를 수신하며, 데이터는 암호화되어 제공됩니다.
|
||||
AES256 KEY와 IV를 사용하여 복호화해야 합니다.
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not tr_key:
|
||||
raise ValueError("tr_key는 필수 입력값입니다.")
|
||||
|
||||
# TR ID 설정 (모의투자 지원 로직)
|
||||
if env_dv == "real":
|
||||
tr_id = "H0STCNI0" # 실전투자용 TR ID
|
||||
elif env_dv == "demo":
|
||||
tr_id = "H0STCNI9" # 모의투자용 TR ID
|
||||
else:
|
||||
raise ValueError("env_dv는 'real' 또는 'demo'만 가능합니다.")
|
||||
|
||||
params = {
|
||||
"tr_key": tr_key,
|
||||
}
|
||||
|
||||
# 데이터 요청
|
||||
msg = ka.data_fetch(tr_id, tr_type, params)
|
||||
|
||||
# 응답 데이터 컬럼 정보
|
||||
columns = [
|
||||
"CUST_ID", "ACNT_NO", "ODER_NO", "ODER_QTY", "SELN_BYOV_CLS", "RCTF_CLS",
|
||||
"ODER_KIND", "ODER_COND", "STCK_SHRN_ISCD", "CNTG_QTY", "CNTG_UNPR",
|
||||
"STCK_CNTG_HOUR", "RFUS_YN", "CNTG_YN", "ACPT_YN", "BRNC_NO", "ACNT_NO2",
|
||||
"ACNT_NAME", "ORD_COND_PRC", "ORD_EXG_GB", "POPUP_YN", "FILLER", "CRDT_CLS",
|
||||
"CRDT_LOAN_DATE", "CNTG_ISNM40", "ODER_PRC"
|
||||
]
|
||||
|
||||
return msg, columns
|
||||
@@ -0,0 +1,117 @@
|
||||
"""
|
||||
Created on 2025-07-08
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from ccnl_notice import ccnl_notice
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 주식체결통보 [실시간-005]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
"CUST_ID": "고객 ID",
|
||||
"ACNT_NO": "계좌번호",
|
||||
"ODER_NO": "주문번호",
|
||||
"ODER_QTY": "주문수량",
|
||||
"SELN_BYOV_CLS": "매도매수구분",
|
||||
"RCTF_CLS": "접수구분",
|
||||
"ODER_KIND": "주문종류",
|
||||
"ODER_COND": "주문조건",
|
||||
"STCK_SHRN_ISCD": "종목코드",
|
||||
"CNTG_QTY": "체결수량",
|
||||
"CNTG_UNPR": "체결단가",
|
||||
"STCK_CNTG_HOUR": "주식체결시간",
|
||||
"RFUS_YN": "거부여부",
|
||||
"CNTG_YN": "체결여부",
|
||||
"ACPT_YN": "접수여부",
|
||||
"BRNC_NO": "지점번호",
|
||||
"ACNT_NO2": "계좌번호2",
|
||||
"ACNT_NAME": "계좌명",
|
||||
"ORD_COND_PRC": "호가조건가격",
|
||||
"ORD_EXG_GB": "주문거래소 구분",
|
||||
"POPUP_YN": "체결정보 표시",
|
||||
"FILLER": "필러",
|
||||
"CRDT_CLS": "신용거래구분",
|
||||
"CRDT_LOAN_DATE": "신용대출일자",
|
||||
"CNTG_ISNM40": "체결일자",
|
||||
"ODER_PRC": "주문가격"
|
||||
}
|
||||
NUMERIC_COLUMNS = ["주문수량", "체결수량", "체결단가", "호가조건가격", "주문가격"]
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내주식 실시간체결통보
|
||||
|
||||
국내주식 실시간 체결통보 수신 시에 (1) 주문·정정·취소·거부 접수 통보 와 (2) 체결 통보 가 모두 수신됩니다.
|
||||
(14번째 값(CNTG_YN;체결여부)가 2이면 체결통보, 1이면 주문·정정·취소·거부 접수 통보입니다.)
|
||||
|
||||
※ 모의투자는 H0STCNI9 로 변경하여 사용합니다.
|
||||
|
||||
[호출 데이터]
|
||||
헤더와 바디 값을 합쳐 JSON 형태로 전송합니다.
|
||||
|
||||
[응답 데이터]
|
||||
1. 정상 등록 여부 (JSON)
|
||||
- JSON["body"]["msg1"] - 정상 응답 시, SUBSCRIBE SUCCESS
|
||||
- JSON["body"]["output"]["iv"] - 실시간 결과 복호화에 필요한 AES256 IV (Initialize Vector)
|
||||
- JSON["body"]["output"]["key"] - 실시간 결과 복호화에 필요한 AES256 Key
|
||||
|
||||
2. 실시간 결과 응답 ( | 로 구분되는 값)
|
||||
- 암호화 유무 : 0 암호화 되지 않은 데이터 / 1 암호화된 데이터
|
||||
- TR_ID : 등록한 tr_id
|
||||
- 데이터 건수 : (ex. 001 데이터 건수를 참조하여 활용)
|
||||
- 응답 데이터 : 아래 response 데이터 참조 ( ^로 구분됨)
|
||||
|
||||
체결 통보 응답 결과는 암호화되어 출력됩니다. AES256 KEY IV를 활용해 복호화하여 활용하세요. 자세한 예제는 [도구>wikidocs]에 준비되어 있습니다.
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
ka.auth_ws()
|
||||
trenv = ka.getTREnv()
|
||||
|
||||
# 인증(auth_ws()) 이후에 선언
|
||||
kws = ka.KISWebSocket(api_url="/tryitout")
|
||||
|
||||
# 조회
|
||||
kws.subscribe(request=ccnl_notice, data=[trenv.my_htsid])
|
||||
|
||||
# 결과 표시
|
||||
def on_result(ws, tr_id: str, result: pd.DataFrame, data_map: dict):
|
||||
try:
|
||||
# 컬럼 매핑
|
||||
result.rename(columns=COLUMN_MAPPING, inplace=True)
|
||||
|
||||
# 숫자형 컬럼 변환
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce')
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
except Exception as e:
|
||||
logging.error(f"결과 처리 중 오류: {e}")
|
||||
logging.error(f"받은 데이터: {result}")
|
||||
|
||||
kws.start(on_result=on_result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
75
한국투자증권(API)/examples_llm/domestic_stock/ccnl_nxt/ccnl_nxt.py
Normal file
75
한국투자증권(API)/examples_llm/domestic_stock/ccnl_nxt/ccnl_nxt.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간체결가 (NXT)
|
||||
##############################################################################################
|
||||
|
||||
|
||||
def ccnl_nxt(
|
||||
tr_type: str,
|
||||
tr_key: str,
|
||||
) -> tuple[dict, list[str]]:
|
||||
"""
|
||||
국내주식 실시간체결가 (NXT)[H0NXCNT0]
|
||||
국내주식 실시간체결가 (NXT) API를 통해 실시간 데이터를 구독합니다.
|
||||
|
||||
Args:
|
||||
tr_type (str): [필수] 구독 등록("1") 또는 해제("0") 여부를 나타내는 값
|
||||
tr_key (str): [필수] 종목코드 (빈 문자열 불가)
|
||||
|
||||
Returns:
|
||||
message (dict): 실시간 체결가 데이터 메시지
|
||||
columns (list[str]): 데이터의 컬럼 정보 리스트
|
||||
|
||||
Example:
|
||||
>>> msg, columns = ccnl_nxt("1", "005930")
|
||||
>>> print(msg, columns)
|
||||
|
||||
Note:
|
||||
이 함수는 웹소켓을 통해 실시간 데이터를 구독합니다. 구독을 시작하려면 tr_type을 "1"로 설정하고,
|
||||
구독을 해제하려면 "0"으로 설정하세요. tr_key는 유효한 종목코드를 입력해야 합니다.
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not tr_key:
|
||||
raise ValueError("tr_key는 필수 입력값입니다. 유효한 종목코드를 입력하세요.")
|
||||
|
||||
tr_id = "H0NXCNT0"
|
||||
|
||||
params = {
|
||||
"tr_key": tr_key,
|
||||
}
|
||||
|
||||
# 데이터 페치
|
||||
msg = ka.data_fetch(tr_id, tr_type, params)
|
||||
|
||||
# 컬럼 정보
|
||||
columns = [
|
||||
"MKSC_SHRN_ISCD", "STCK_CNTG_HOUR", "STCK_PRPR", "PRDY_VRSS_SIGN",
|
||||
"PRDY_VRSS", "PRDY_CTRT", "WGHN_AVRG_STCK_PRC", "STCK_OPRC",
|
||||
"STCK_HGPR", "STCK_LWPR", "ASKP1", "BIDP1", "CNTG_VOL", "ACML_VOL",
|
||||
"ACML_TR_PBMN", "SELN_CNTG_CSNU", "SHNU_CNTG_CSNU", "NTBY_CNTG_CSNU",
|
||||
"CTTR", "SELN_CNTG_SMTN", "SHNU_CNTG_SMTN", "CNTG_CLS_CODE",
|
||||
"SHNU_RATE", "PRDY_VOL_VRSS_ACML_VOL_RATE", "OPRC_HOUR",
|
||||
"OPRC_VRSS_PRPR_SIGN", "OPRC_VRSS_PRPR", "HGPR_HOUR",
|
||||
"HGPR_VRSS_PRPR_SIGN", "HGPR_VRSS_PRPR", "LWPR_HOUR",
|
||||
"LWPR_VRSS_PRPR_SIGN", "LWPR_VRSS_PRPR", "BSOP_DATE",
|
||||
"NEW_MKOP_CLS_CODE", "TRHT_YN", "ASKP_RSQN1", "BIDP_RSQN1",
|
||||
"TOTAL_ASKP_RSQN", "TOTAL_BIDP_RSQN", "VOL_TNRT",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL", "PRDY_SMNS_HOUR_ACML_VOL_RATE",
|
||||
"HOUR_CLS_CODE", "MRKT_TRTM_CLS_CODE", "VI_STND_PRC"
|
||||
]
|
||||
|
||||
return msg, columns
|
||||
128
한국투자증권(API)/examples_llm/domestic_stock/ccnl_nxt/chk_ccnl_nxt.py
Normal file
128
한국투자증권(API)/examples_llm/domestic_stock/ccnl_nxt/chk_ccnl_nxt.py
Normal file
@@ -0,0 +1,128 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from ccnl_nxt import ccnl_nxt
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간체결가 (NXT)
|
||||
##############################################################################################
|
||||
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
"MKSC_SHRN_ISCD": "유가증권 단축 종목코드",
|
||||
"STCK_CNTG_HOUR": "주식 체결 시간",
|
||||
"STCK_PRPR": "주식 현재가",
|
||||
"PRDY_VRSS_SIGN": "전일 대비 부호",
|
||||
"PRDY_VRSS": "전일 대비",
|
||||
"PRDY_CTRT": "전일 대비율",
|
||||
"WGHN_AVRG_STCK_PRC": "가중 평균 주식 가격",
|
||||
"STCK_OPRC": "주식 시가",
|
||||
"STCK_HGPR": "주식 최고가",
|
||||
"STCK_LWPR": "주식 최저가",
|
||||
"ASKP1": "매도호가1",
|
||||
"BIDP1": "매수호가1",
|
||||
"CNTG_VOL": "체결 거래량",
|
||||
"ACML_VOL": "누적 거래량",
|
||||
"ACML_TR_PBMN": "누적 거래 대금",
|
||||
"SELN_CNTG_CSNU": "매도 체결 건수",
|
||||
"SHNU_CNTG_CSNU": "매수 체결 건수",
|
||||
"NTBY_CNTG_CSNU": "순매수 체결 건수",
|
||||
"CTTR": "체결강도",
|
||||
"SELN_CNTG_SMTN": "총 매도 수량",
|
||||
"SHNU_CNTG_SMTN": "총 매수 수량",
|
||||
"CNTG_CLS_CODE": "체결구분",
|
||||
"SHNU_RATE": "매수비율",
|
||||
"PRDY_VOL_VRSS_ACML_VOL_RATE": "전일 거래량 대비 등락율",
|
||||
"OPRC_HOUR": "시가 시간",
|
||||
"OPRC_VRSS_PRPR_SIGN": "시가대비구분",
|
||||
"OPRC_VRSS_PRPR": "시가대비",
|
||||
"HGPR_HOUR": "최고가 시간",
|
||||
"HGPR_VRSS_PRPR_SIGN": "고가대비구분",
|
||||
"HGPR_VRSS_PRPR": "고가대비",
|
||||
"LWPR_HOUR": "최저가 시간",
|
||||
"LWPR_VRSS_PRPR_SIGN": "저가대비구분",
|
||||
"LWPR_VRSS_PRPR": "저가대비",
|
||||
"BSOP_DATE": "영업 일자",
|
||||
"NEW_MKOP_CLS_CODE": "신 장운영 구분 코드",
|
||||
"TRHT_YN": "거래정지 여부",
|
||||
"ASKP_RSQN1": "매도호가 잔량1",
|
||||
"BIDP_RSQN1": "매수호가 잔량1",
|
||||
"TOTAL_ASKP_RSQN": "총 매도호가 잔량",
|
||||
"TOTAL_BIDP_RSQN": "총 매수호가 잔량",
|
||||
"VOL_TNRT": "거래량 회전율",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL": "전일 동시간 누적 거래량",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL_RATE": "전일 동시간 누적 거래량 비율",
|
||||
"HOUR_CLS_CODE": "시간 구분 코드",
|
||||
"MRKT_TRTM_CLS_CODE": "임의종료구분코드",
|
||||
"VI_STND_PRC": "정적VI발동기준가"
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = [
|
||||
"주식 현재가", "전일 대비", "전일 대비율", "가중 평균 주식 가격", "주식 시가",
|
||||
"주식 최고가", "주식 최저가", "매도호가1", "매수호가1", "체결 거래량",
|
||||
"누적 거래량", "누적 거래 대금", "매도 체결 건수", "매수 체결 건수",
|
||||
"순매수 체결 건수", "체결강도", "총 매도 수량", "총 매수 수량",
|
||||
"매수비율", "전일 거래량 대비 등락율", "시가대비", "고가대비", "저가대비",
|
||||
"매도호가 잔량1", "매수호가 잔량1", "총 매도호가 잔량", "총 매수호가 잔량",
|
||||
"거래량 회전율", "전일 동시간 누적 거래량", "전일 동시간 누적 거래량 비율",
|
||||
"정적VI발동기준가"
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내주식 실시간체결가 (NXT)
|
||||
|
||||
국내주식 실시간체결가 (NXT) API입니다.
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
ka.auth_ws()
|
||||
|
||||
# 인증(auth_ws()) 이후에 선언
|
||||
kws = ka.KISWebSocket(api_url="/tryitout")
|
||||
|
||||
# 조회
|
||||
kws.subscribe(request=ccnl_nxt, data=["005930", "000660"])
|
||||
|
||||
# 결과 표시
|
||||
def on_result(ws, tr_id: str, result: pd.DataFrame, data_map: dict):
|
||||
try:
|
||||
# 컬럼 매핑
|
||||
|
||||
result.rename(columns=COLUMN_MAPPING, inplace=True)
|
||||
|
||||
# 숫자형 컬럼 변환
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce')
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
except Exception as e:
|
||||
logging.error(f"결과 처리 중 오류: {e}")
|
||||
logging.error(f"받은 데이터: {result}")
|
||||
|
||||
kws.start(on_result=on_result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
111
한국투자증권(API)/examples_llm/domestic_stock/ccnl_total/ccnl_total.py
Normal file
111
한국투자증권(API)/examples_llm/domestic_stock/ccnl_total/ccnl_total.py
Normal file
@@ -0,0 +1,111 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간체결가 (통합)
|
||||
##############################################################################################
|
||||
|
||||
|
||||
def ccnl_total(
|
||||
tr_type: str,
|
||||
tr_key: str,
|
||||
) -> tuple[dict, list[str]]:
|
||||
"""
|
||||
국내주식 실시간체결가 (통합)[H0UNCNT0]
|
||||
국내주식 실시간체결가 (통합) API를 통해 실시간 데이터를 구독합니다.
|
||||
|
||||
Args:
|
||||
tr_type (str): [필수] 구독 등록("1") 또는 해제("0") 여부를 나타내는 값
|
||||
tr_key (str): [필수] 종목코드, 실시간 데이터를 구독할 주식의 종목코드
|
||||
|
||||
Returns:
|
||||
message (dict): 실시간 체결가 데이터 메시지
|
||||
columns (list[str]): 데이터의 컬럼 정보 리스트
|
||||
|
||||
Raises:
|
||||
ValueError: tr_key가 빈 문자열인 경우 발생
|
||||
|
||||
Example:
|
||||
>>> msg, columns = ccnl_total("1", "005930")
|
||||
>>> print(msg, columns)
|
||||
|
||||
Note:
|
||||
이 함수는 웹소켓을 통해 실시간 데이터를 구독합니다. 구독을 시작하려면 tr_type을 "1"로 설정하고,
|
||||
구독을 해제하려면 "0"으로 설정하십시오.
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not tr_key:
|
||||
raise ValueError("tr_key is required and cannot be an empty string")
|
||||
|
||||
tr_id = "H0UNCNT0"
|
||||
|
||||
params = {
|
||||
"tr_key": tr_key,
|
||||
}
|
||||
|
||||
# 웹소켓을 통해 실시간 데이터를 가져옵니다.
|
||||
msg = ka.data_fetch(tr_id, tr_type, params)
|
||||
|
||||
# API 메타데이터에 기반한 정확한 컬럼 리스트
|
||||
columns = [
|
||||
"MKSC_SHRN_ISCD",
|
||||
"STCK_CNTG_HOUR",
|
||||
"STCK_PRPR",
|
||||
"PRDY_VRSS_SIGN",
|
||||
"PRDY_VRSS",
|
||||
"PRDY_CTRT",
|
||||
"WGHN_AVRG_STCK_PRC",
|
||||
"STCK_OPRC",
|
||||
"STCK_HGPR",
|
||||
"STCK_LWPR",
|
||||
"ASKP1",
|
||||
"BIDP1",
|
||||
"CNTG_VOL",
|
||||
"ACML_VOL",
|
||||
"ACML_TR_PBMN",
|
||||
"SELN_CNTG_CSNU",
|
||||
"SHNU_CNTG_CSNU",
|
||||
"NTBY_CNTG_CSNU",
|
||||
"CTTR",
|
||||
"SELN_CNTG_SMTN",
|
||||
"SHNU_CNTG_SMTN",
|
||||
"CNTG_CLS_CODE",
|
||||
"SHNU_RATE",
|
||||
"PRDY_VOL_VRSS_ACML_VOL_RATE",
|
||||
"OPRC_HOUR",
|
||||
"OPRC_VRSS_PRPR_SIGN",
|
||||
"OPRC_VRSS_PRPR",
|
||||
"HGPR_HOUR",
|
||||
"HGPR_VRSS_PRPR_SIGN",
|
||||
"HGPR_VRSS_PRPR",
|
||||
"LWPR_HOUR",
|
||||
"LWPR_VRSS_PRPR_SIGN",
|
||||
"LWPR_VRSS_PRPR",
|
||||
"BSOP_DATE",
|
||||
"NEW_MKOP_CLS_CODE",
|
||||
"TRHT_YN",
|
||||
"ASKP_RSQN1",
|
||||
"BIDP_RSQN1",
|
||||
"TOTAL_ASKP_RSQN",
|
||||
"TOTAL_BIDP_RSQN",
|
||||
"VOL_TNRT",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL_RATE",
|
||||
"HOUR_CLS_CODE",
|
||||
"MRKT_TRTM_CLS_CODE",
|
||||
"VI_STND_PRC",
|
||||
]
|
||||
|
||||
return msg, columns
|
||||
@@ -0,0 +1,126 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from ccnl_total import ccnl_total
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간체결가 (통합)
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
"MKSC_SHRN_ISCD": "유가증권 단축 종목코드",
|
||||
"STCK_CNTG_HOUR": "주식 체결 시간",
|
||||
"STCK_PRPR": "주식 현재가",
|
||||
"PRDY_VRSS_SIGN": "전일 대비 부호",
|
||||
"PRDY_VRSS": "전일 대비",
|
||||
"PRDY_CTRT": "전일 대비율",
|
||||
"WGHN_AVRG_STCK_PRC": "가중 평균 주식 가격",
|
||||
"STCK_OPRC": "주식 시가",
|
||||
"STCK_HGPR": "주식 최고가",
|
||||
"STCK_LWPR": "주식 최저가",
|
||||
"ASKP1": "매도호가1",
|
||||
"BIDP1": "매수호가1",
|
||||
"CNTG_VOL": "체결 거래량",
|
||||
"ACML_VOL": "누적 거래량",
|
||||
"ACML_TR_PBMN": "누적 거래 대금",
|
||||
"SELN_CNTG_CSNU": "매도 체결 건수",
|
||||
"SHNU_CNTG_CSNU": "매수 체결 건수",
|
||||
"NTBY_CNTG_CSNU": "순매수 체결 건수",
|
||||
"CTTR": "체결강도",
|
||||
"SELN_CNTG_SMTN": "총 매도 수량",
|
||||
"SHNU_CNTG_SMTN": "총 매수 수량",
|
||||
"CNTG_CLS_CODE": "체결구분",
|
||||
"SHNU_RATE": "매수비율",
|
||||
"PRDY_VOL_VRSS_ACML_VOL_RATE": "전일 거래량 대비 등락율",
|
||||
"OPRC_HOUR": "시가 시간",
|
||||
"OPRC_VRSS_PRPR_SIGN": "시가대비구분",
|
||||
"OPRC_VRSS_PRPR": "시가대비",
|
||||
"HGPR_HOUR": "최고가 시간",
|
||||
"HGPR_VRSS_PRPR_SIGN": "고가대비구분",
|
||||
"HGPR_VRSS_PRPR": "고가대비",
|
||||
"LWPR_HOUR": "최저가 시간",
|
||||
"LWPR_VRSS_PRPR_SIGN": "저가대비구분",
|
||||
"LWPR_VRSS_PRPR": "저가대비",
|
||||
"BSOP_DATE": "영업 일자",
|
||||
"NEW_MKOP_CLS_CODE": "신 장운영 구분 코드",
|
||||
"TRHT_YN": "거래정지 여부",
|
||||
"ASKP_RSQN1": "매도호가 잔량1",
|
||||
"BIDP_RSQN1": "매수호가 잔량1",
|
||||
"TOTAL_ASKP_RSQN": "총 매도호가 잔량",
|
||||
"TOTAL_BIDP_RSQN": "총 매수호가 잔량",
|
||||
"VOL_TNRT": "거래량 회전율",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL": "전일 동시간 누적 거래량",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL_RATE": "전일 동시간 누적 거래량 비율",
|
||||
"HOUR_CLS_CODE": "시간 구분 코드",
|
||||
"MRKT_TRTM_CLS_CODE": "임의종료구분코드",
|
||||
"VI_STND_PRC": "정적VI발동기준가"
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = [
|
||||
"주식 현재가", "전일 대비", "전일 대비율", "가중 평균 주식 가격", "주식 시가",
|
||||
"주식 최고가", "주식 최저가", "매도호가1", "매수호가1", "체결 거래량",
|
||||
"누적 거래량", "누적 거래 대금", "매도 체결 건수", "매수 체결 건수",
|
||||
"순매수 체결 건수", "체결강도", "총 매도 수량", "총 매수 수량", "매수비율",
|
||||
"전일 거래량 대비 등락율", "시가대비", "고가대비", "저가대비", "매도호가 잔량1",
|
||||
"매수호가 잔량1", "총 매도호가 잔량", "총 매수호가 잔량", "거래량 회전율",
|
||||
"전일 동시간 누적 거래량", "전일 동시간 누적 거래량 비율", "정적VI발동기준가"
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내주식 실시간체결가 (통합)
|
||||
|
||||
국내주식 실시간체결가 (통합) API입니다.
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
ka.auth_ws()
|
||||
|
||||
# 인증(auth_ws()) 이후에 선언
|
||||
kws = ka.KISWebSocket(api_url="/tryitout")
|
||||
|
||||
# 조회
|
||||
kws.subscribe(request=ccnl_total, data=["005930", "000660"])
|
||||
|
||||
# 결과 표시
|
||||
def on_result(ws, tr_id: str, result: pd.DataFrame, data_map: dict):
|
||||
try:
|
||||
# 컬럼명 매핑
|
||||
result.rename(columns=COLUMN_MAPPING, inplace=True)
|
||||
|
||||
# 숫자형 컬럼 변환
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce')
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
except Exception as e:
|
||||
logging.error(f"결과 처리 중 오류: {e}")
|
||||
logging.error(f"받은 데이터: {result}")
|
||||
|
||||
kws.start(on_result=on_result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,74 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from chk_holiday import chk_holiday
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 업종/기타 > 국내휴장일조회[국내주식-040]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'bass_dt': '기준일자',
|
||||
'wday_dvsn_cd': '요일구분코드',
|
||||
'bzdy_yn': '영업일여부',
|
||||
'tr_day_yn': '거래일여부',
|
||||
'opnd_yn': '개장일여부',
|
||||
'sttl_day_yn': '결제일여부'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내휴장일조회 테스트 함수
|
||||
|
||||
이 함수는 국내휴장일조회 API를 호출하여 결과를 출력합니다.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
# case1 조회
|
||||
logging.info("=== case1 조회 ===")
|
||||
try:
|
||||
result = chk_holiday(bass_dt="20250630")
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
logging.info("사용 가능한 컬럼: %s", result.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환 및 데이터 출력
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,109 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
from typing import Optional
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 업종/기타 > 국내휴장일조회[국내주식-040]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/chk-holiday"
|
||||
|
||||
|
||||
def chk_holiday(
|
||||
bass_dt: str, # 기준일자 (YYYYMMDD)
|
||||
NK100: str = "", # 연속조회키
|
||||
FK100: str = "", # 연속조회검색조건
|
||||
tr_cont: str = "", # 연속거래여부
|
||||
dataframe: Optional[pd.DataFrame] = None, # 누적 데이터프레임
|
||||
depth: int = 0, # 내부 재귀깊이 (자동관리)
|
||||
max_depth: int = 10 # 최대 재귀 횟수 제한
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
(★중요) 국내휴장일조회(TCA0903R) 서비스는 당사 원장서비스와 연관되어 있어
|
||||
단시간 내 다수 호출시 서비스에 영향을 줄 수 있어 가급적 1일 1회 호출 부탁드립니다.
|
||||
|
||||
국내휴장일조회 API입니다.
|
||||
영업일, 거래일, 개장일, 결제일 여부를 조회할 수 있습니다.
|
||||
주문을 넣을 수 있는지 확인하고자 하실 경우 개장일여부(opnd_yn)을 사용하시면 됩니다.
|
||||
|
||||
Args:
|
||||
bass_dt (str): [필수] 기준일자 (ex. YYYYMMDD)
|
||||
NK100 (str): 연속조회키
|
||||
FK100 (str): 연속조회검색조건
|
||||
tr_cont (str): 연속거래여부
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
depth (int): 내부 재귀깊이 (자동관리)
|
||||
max_depth (int): 최대 재귀 횟수 제한
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: 국내휴장일조회 데이터
|
||||
|
||||
Example:
|
||||
>>> df = chk_holiday(bass_dt="20250630")
|
||||
>>> print(df)
|
||||
"""
|
||||
|
||||
if bass_dt == "":
|
||||
raise ValueError("bass_dt is required (e.g. 'YYYYMMDD')")
|
||||
|
||||
if depth > max_depth:
|
||||
logging.warning("Max recursive depth reached.")
|
||||
if dataframe is None:
|
||||
return pd.DataFrame()
|
||||
else:
|
||||
return dataframe
|
||||
|
||||
tr_id = "CTCA0903R" # 국내휴장일조회
|
||||
|
||||
params = {
|
||||
"BASS_DT": bass_dt,
|
||||
"CTX_AREA_FK": FK100,
|
||||
"CTX_AREA_NK": NK100
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
output_data = res.getBody().output
|
||||
if not isinstance(output_data, list):
|
||||
output_data = [output_data]
|
||||
current_data = pd.DataFrame(output_data)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
FK100 = res.getBody().ctx_area_fk
|
||||
NK100 = res.getBody().ctx_area_nk
|
||||
|
||||
if tr_cont in ["M", "F"]: # 다음 페이지 존재
|
||||
logging.info("Call Next page...")
|
||||
ka.smart_sleep() # 시스템 안정적 운영을 위한 지연
|
||||
return chk_holiday(
|
||||
bass_dt, NK100, FK100, "N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logging.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
res.printError(url=API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,130 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from comp_interest import comp_interest
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 업종/기타 > 금리 종합(국내채권_금리)[국내주식-155]
|
||||
##############################################################################################
|
||||
|
||||
# 통합 컬럼 매핑 (모든 output에서 공통 사용)
|
||||
COLUMN_MAPPING = {
|
||||
'bcdt_code': '자료코드',
|
||||
'hts_kor_isnm': 'HTS한글종목명',
|
||||
'bond_mnrt_prpr': '채권금리현재가',
|
||||
'prdy_vrss_sign': '전일대비부호',
|
||||
'bond_mnrt_prdy_vrss': '채권금리전일대비',
|
||||
'prdy_ctrt': '전일대비율',
|
||||
'stck_bsop_date': '주식영업일자',
|
||||
'bcdt_code': '자료코드',
|
||||
'hts_kor_isnm': 'HTS한글종목명',
|
||||
'bond_mnrt_prpr': '채권금리현재가',
|
||||
'prdy_vrss_sign': '전일대비부호',
|
||||
'bond_mnrt_prdy_vrss': '채권금리전일대비',
|
||||
'bstp_nmix_prdy_ctrt': '업종지수전일대비율',
|
||||
'stck_bsop_date': '주식영업일자'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 업종/기타
|
||||
금리 종합(국내채권_금리)[국내주식-155]
|
||||
|
||||
금리 종합(국내채권_금리) 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_cond_mrkt_div_code (str): 조건시장분류코드 (Unique key(I))
|
||||
- fid_cond_scr_div_code (str): 조건화면분류코드 (Unique key(20702))
|
||||
- fid_div_cls_code (str): 분류구분코드 (1: 해외금리지표)
|
||||
- fid_div_cls_code1 (str): 분류구분코드 (공백 : 전체)
|
||||
|
||||
Returns:
|
||||
- Tuple[DataFrame, ...]: 금리 종합(국내채권_금리) 결과
|
||||
|
||||
Example:
|
||||
>>> df1, df2 = comp_interest(fid_cond_mrkt_div_code="I", fid_cond_scr_div_code="20702", fid_div_cls_code="1", fid_div_cls_code1="")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
|
||||
# API 호출
|
||||
result1, result2 = comp_interest(
|
||||
fid_cond_mrkt_div_code="I", # 조건시장분류코드
|
||||
fid_cond_scr_div_code="20702", # 조건화면분류코드
|
||||
fid_div_cls_code="1", # 분류구분코드
|
||||
fid_div_cls_code1="", # 분류구분코드
|
||||
)
|
||||
|
||||
# 결과 확인
|
||||
results = [result1, result2]
|
||||
if all(result is None or result.empty for result in results):
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# output1 결과 처리
|
||||
logger.info("=== output1 조회 ===")
|
||||
if not result1.empty:
|
||||
logger.info("사용 가능한 컬럼: %s", result1.columns.tolist())
|
||||
|
||||
# 통합 컬럼명 한글 변환 (필요한 컬럼만 자동 매핑됨)
|
||||
result1 = result1.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result1.columns:
|
||||
result1[col] = pd.to_numeric(result1[col], errors='coerce').round(2)
|
||||
|
||||
logger.info("output1 결과:")
|
||||
print(result1)
|
||||
else:
|
||||
logger.info("output1 데이터가 없습니다.")
|
||||
|
||||
# output2 결과 처리
|
||||
logger.info("=== output2 조회 ===")
|
||||
if not result2.empty:
|
||||
logger.info("사용 가능한 컬럼: %s", result2.columns.tolist())
|
||||
|
||||
# 통합 컬럼명 한글 변환 (필요한 컬럼만 자동 매핑됨)
|
||||
result2 = result2.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result2.columns:
|
||||
result2[col] = pd.to_numeric(result2[col], errors='coerce').round(2)
|
||||
|
||||
logger.info("output2 결과:")
|
||||
print(result2)
|
||||
else:
|
||||
logger.info("output2 데이터가 없습니다.")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,135 @@
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional, Tuple
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 업종/기타 > 금리 종합(국내채권_금리)[국내주식-155]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/comp-interest"
|
||||
|
||||
def comp_interest(
|
||||
fid_cond_mrkt_div_code: str, # 조건시장분류코드
|
||||
fid_cond_scr_div_code: str, # 조건화면분류코드
|
||||
fid_div_cls_code: str, # 분류구분코드
|
||||
fid_div_cls_code1: str, # 분류구분코드
|
||||
dataframe1: Optional[pd.DataFrame] = None, # 누적 데이터프레임 (output1)
|
||||
dataframe2: Optional[pd.DataFrame] = None, # 누적 데이터프레임 (output2)
|
||||
tr_cont: str = "",
|
||||
depth: int = 0,
|
||||
max_depth: int = 10
|
||||
) -> Tuple[pd.DataFrame, pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 업종/기타
|
||||
금리 종합(국내채권_금리)[국내주식-155]
|
||||
금리 종합(국내채권_금리) API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_cond_mrkt_div_code (str): 조건시장분류코드 (필수)
|
||||
fid_cond_scr_div_code (str): 조건화면분류코드 (필수)
|
||||
fid_div_cls_code (str): 분류구분코드 (필수)
|
||||
fid_div_cls_code1 (str): 분류구분코드 (공백 허용)
|
||||
dataframe1 (Optional[pd.DataFrame]): 누적 데이터프레임 (output1)
|
||||
dataframe2 (Optional[pd.DataFrame]): 누적 데이터프레임 (output2)
|
||||
tr_cont (str): 연속 거래 여부
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Tuple[pd.DataFrame, pd.DataFrame]: 금리 종합(국내채권_금리) 데이터
|
||||
|
||||
Example:
|
||||
>>> df1, df2 = comp_interest('01', '20702', '1', '')
|
||||
>>> print(df1)
|
||||
>>> print(df2)
|
||||
"""
|
||||
# 로깅 설정
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. '01')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. '01')")
|
||||
|
||||
if not fid_cond_scr_div_code:
|
||||
logger.error("fid_cond_scr_div_code is required. (e.g. '20702')")
|
||||
raise ValueError("fid_cond_scr_div_code is required. (e.g. '20702')")
|
||||
|
||||
if not fid_div_cls_code:
|
||||
logger.error("fid_div_cls_code is required. (e.g. '1')")
|
||||
raise ValueError("fid_div_cls_code is required. (e.g. '1')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe1 if dataframe1 is not None else pd.DataFrame(), dataframe2 if dataframe2 is not None else pd.DataFrame()
|
||||
|
||||
|
||||
tr_id = "FHPST07020000"
|
||||
|
||||
params = {
|
||||
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code,
|
||||
"FID_COND_SCR_DIV_CODE": fid_cond_scr_div_code,
|
||||
"FID_DIV_CLS_CODE": fid_div_cls_code,
|
||||
"FID_DIV_CLS_CODE1": fid_div_cls_code1,
|
||||
}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
# output1 처리
|
||||
if hasattr(res.getBody(), 'output1'):
|
||||
output_data = res.getBody().output1
|
||||
if output_data:
|
||||
current_data1 = pd.DataFrame(output_data if isinstance(output_data, list) else [output_data])
|
||||
dataframe1 = pd.concat([dataframe1, current_data1],
|
||||
ignore_index=True) if dataframe1 is not None else current_data1
|
||||
else:
|
||||
dataframe1 = dataframe1 if dataframe1 is not None else pd.DataFrame()
|
||||
|
||||
# output2 처리
|
||||
if hasattr(res.getBody(), 'output2'):
|
||||
output_data = res.getBody().output2
|
||||
if output_data:
|
||||
current_data2 = pd.DataFrame(output_data if isinstance(output_data, list) else [output_data])
|
||||
dataframe2 = pd.concat([dataframe2, current_data2],
|
||||
ignore_index=True) if dataframe2 is not None else current_data2
|
||||
else:
|
||||
dataframe2 = dataframe2 if dataframe2 is not None else pd.DataFrame()
|
||||
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont in ["M", "F"]:
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return comp_interest(
|
||||
fid_cond_mrkt_div_code,
|
||||
fid_cond_scr_div_code,
|
||||
fid_div_cls_code,
|
||||
fid_div_cls_code1,
|
||||
"N", dataframe1, dataframe2, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe1, dataframe2
|
||||
else:
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame(), pd.DataFrame()
|
||||
@@ -0,0 +1,145 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from comp_program_trade_daily import comp_program_trade_daily
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 프로그램매매 종합현황(일별)[국내주식-115]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'stck_bsop_date': '주식 영업 일자',
|
||||
'nabt_entm_seln_tr_pbmn': '비차익 위탁 매도 거래 대금',
|
||||
'nabt_onsl_seln_vol': '비차익 자기 매도 거래량',
|
||||
'whol_onsl_seln_tr_pbmn': '전체 자기 매도 거래 대금',
|
||||
'arbt_smtn_shnu_vol': '차익 합계 매수2 거래량',
|
||||
'nabt_smtn_shnu_tr_pbmn': '비차익 합계 매수2 거래 대금',
|
||||
'arbt_entm_ntby_qty': '차익 위탁 순매수 수량',
|
||||
'nabt_entm_ntby_tr_pbmn': '비차익 위탁 순매수 거래 대금',
|
||||
'arbt_entm_seln_vol': '차익 위탁 매도 거래량',
|
||||
'nabt_entm_seln_vol_rate': '비차익 위탁 매도 거래량 비율',
|
||||
'nabt_onsl_seln_vol_rate': '비차익 자기 매도 거래량 비율',
|
||||
'whol_onsl_seln_tr_pbmn_rate': '전체 자기 매도 거래 대금 비율',
|
||||
'arbt_smtm_shun_vol_rate': '차익 합계 매수 거래량 비율',
|
||||
'nabt_smtm_shun_tr_pbmn_rate': '비차익 합계 매수 거래대금 비율',
|
||||
'arbt_entm_ntby_qty_rate': '차익 위탁 순매수 수량 비율',
|
||||
'nabt_entm_ntby_tr_pbmn_rate': '비차익 위탁 순매수 거래 대금',
|
||||
'arbt_entm_seln_vol_rate': '차익 위탁 매도 거래량 비율',
|
||||
'nabt_entm_seln_tr_pbmn_rate': '비차익 위탁 매도 거래 대금 비',
|
||||
'nabt_onsl_seln_tr_pbmn': '비차익 자기 매도 거래 대금',
|
||||
'whol_smtn_seln_vol': '전체 합계 매도 거래량',
|
||||
'arbt_smtn_shnu_tr_pbmn': '차익 합계 매수2 거래 대금',
|
||||
'whol_entm_shnu_vol': '전체 위탁 매수2 거래량',
|
||||
'arbt_entm_ntby_tr_pbmn': '차익 위탁 순매수 거래 대금',
|
||||
'nabt_onsl_ntby_qty': '비차익 자기 순매수 수량',
|
||||
'arbt_entm_seln_tr_pbmn': '차익 위탁 매도 거래 대금',
|
||||
'whol_seln_vol_rate': '전체 매도 거래량 비율',
|
||||
'whol_entm_shnu_vol_rate': '전체 위탁 매수 거래량 비율',
|
||||
'whol_entm_seln_tr_pbmn': '전체 위탁 매도 거래 대금',
|
||||
'nabt_smtm_seln_vol': '비차익 합계 매도 거래량',
|
||||
'arbt_entm_shnu_vol': '차익 위탁 매수2 거래량',
|
||||
'nabt_entm_shnu_tr_pbmn': '비차익 위탁 매수2 거래 대금',
|
||||
'whol_onsl_shnu_vol': '전체 자기 매수2 거래량',
|
||||
'arbt_onsl_ntby_tr_pbmn': '차익 자기 순매수 거래 대금',
|
||||
'nabt_smtn_ntby_qty': '비차익 합계 순매수 수량',
|
||||
'arbt_onsl_seln_vol': '차익 자기 매도 거래량',
|
||||
'whol_entm_ntby_qty': '전체 위탁 순매수 수량',
|
||||
'nabt_onsl_ntby_tr_pbmn': '비차익 자기 순매수 거래 대금',
|
||||
'arbt_onsl_seln_tr_pbmn': '차익 자기 매도 거래 대금',
|
||||
'nabt_smtm_seln_tr_pbmn_rate': '비차익 합계 매도 거래대금 비율',
|
||||
'arbt_entm_shnu_vol_rate': '차익 위탁 매수 거래량 비율',
|
||||
'nabt_entm_shnu_tr_pbmn_rate': '비차익 위탁 매수 거래 대금 비',
|
||||
'whol_onsl_shnu_tr_pbmn': '전체 자기 매수2 거래 대금',
|
||||
'arbt_onsl_ntby_tr_pbmn_rate': '차익 자기 순매수 거래 대금 비',
|
||||
'nabt_smtm_ntby_qty_rate': '비차익 합계 순매수 수량 비율',
|
||||
'arbt_onsl_seln_vol_rate': '차익 자기 매도 거래량 비율',
|
||||
'whol_entm_seln_vol': '전체 위탁 매도 거래량',
|
||||
'arbt_entm_shnu_tr_pbmn': '차익 위탁 매수2 거래 대금',
|
||||
'nabt_onsl_shnu_vol': '비차익 자기 매수2 거래량',
|
||||
'whol_smtn_shnu_vol': '전체 합계 매수2 거래량',
|
||||
'arbt_smtn_ntby_tr_pbmn': '차익 합계 순매수 거래 대금',
|
||||
'arbt_smtn_seln_vol': '차익 합계 매도 거래량',
|
||||
'whol_entm_seln_tr_pbmn_rate': '전체 위탁 매도 거래 대금 비율',
|
||||
'nabt_onsl_seln_vol_rate': '전체 자기 매도 거래량 비율',
|
||||
'arbt_onsl_shnu_vol_rate': '차익 자기 매수 거래량 비율',
|
||||
'nabt_smtm_shun_vol_rate': '비차익 합계 매수 거래량 비율',
|
||||
'whol_shun_tr_pbmn_rate': '전체 매수 거래대금 비율',
|
||||
'nabt_entm_ntby_qty_rate': '비차익 위탁 순매수 수량 비율',
|
||||
'arbt_smtm_seln_tr_pbmn_rate': '차익 합계 매도 거래대금 비율',
|
||||
'arbt_onsl_shnu_vol': '차익 자기 매수2 거래량',
|
||||
'nabt_onsl_shnu_tr_pbmn': '비차익 자기 매수2 거래 대금',
|
||||
'nabt_smtn_shnu_vol': '비차익 합계 매수2 거래량',
|
||||
'whol_smtn_shnu_tr_pbmn': '전체 합계 매수2 거래 대금',
|
||||
'arbt_smtm_ntby_qty': '차익 합계 순매수 수량',
|
||||
'nabt_smtn_ntby_tr_pbmn': '비차익 합계 순매수 거래 대금',
|
||||
'arbt_smtn_seln_tr_pbmn': '차익 합계 매도 거래 대금',
|
||||
'arbt_onsl_shnu_tr_pbmn_rate': '차익 자기 매수 거래 대금 비율',
|
||||
'whol_shun_vol_rate': '전체 매수 거래량 비율',
|
||||
'arbt_smtm_ntby_tr_pbmn_rate': '차익 합계 순매수 거래대금 비율',
|
||||
'whol_entm_ntby_qty_rate': '전체 위탁 순매수 수량 비율',
|
||||
'arbt_smtm_seln_tr_pbmn_rate': '차익 합계 매도 거래대금 비율'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
프로그램매매 종합현황(일별) 조회 테스트 함수
|
||||
|
||||
이 함수는 프로그램매매 종합현황(일별) API를 호출하여 결과를 출력합니다.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
# case1 조회
|
||||
logging.info("=== case1 조회 ===")
|
||||
try:
|
||||
result = comp_program_trade_daily(
|
||||
fid_cond_mrkt_div_code="J",
|
||||
fid_mrkt_cls_code="K",
|
||||
fid_input_date_1="20250101",
|
||||
fid_input_date_2="20250617"
|
||||
)
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
logging.info("사용 가능한 컬럼: %s", result.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환 및 데이터 출력
|
||||
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 (메타데이터에 number로 명시적으로 선언된 필드가 없음)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,69 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 프로그램매매 종합현황(일별)[국내주식-115]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/comp-program-trade-daily"
|
||||
|
||||
|
||||
def comp_program_trade_daily(
|
||||
fid_cond_mrkt_div_code: str, # [필수] 조건시장분류코드 (ex. J:주식,NX:NXT,UN:통합)
|
||||
fid_mrkt_cls_code: str, # [필수] 시장구분코드 (ex. K:코스피,Q:코스닥)
|
||||
fid_input_date_1: str = "", # 검색시작일
|
||||
fid_input_date_2: str = "" # 검색종료일
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
프로그램매매 종합현황(일별) API입니다.
|
||||
한국투자 HTS(eFriend Plus) > [0460] 프로그램매매 종합현황 화면의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.
|
||||
|
||||
Args:
|
||||
fid_cond_mrkt_div_code (str): [필수] 조건시장분류코드 (ex. J:주식,NX:NXT,UN:통합)
|
||||
fid_mrkt_cls_code (str): [필수] 시장구분코드 (ex. K:코스피,Q:코스닥)
|
||||
fid_input_date_1 (str): 검색시작일
|
||||
fid_input_date_2 (str): 검색종료일
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: 프로그램매매 종합현황(일별) 데이터
|
||||
|
||||
Example:
|
||||
>>> df = comp_program_trade_daily("J", "K", "20250101", "20250617")
|
||||
>>> print(df)
|
||||
"""
|
||||
|
||||
if fid_cond_mrkt_div_code == "":
|
||||
raise ValueError("fid_cond_mrkt_div_code is required (e.g. 'J:주식,NX:NXT,UN:통합')")
|
||||
|
||||
if fid_mrkt_cls_code == "":
|
||||
raise ValueError("fid_mrkt_cls_code is required (e.g. 'K:코스피,Q:코스닥')")
|
||||
|
||||
tr_id = "FHPPG04600001"
|
||||
|
||||
params = {
|
||||
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code,
|
||||
"FID_MRKT_CLS_CODE": fid_mrkt_cls_code,
|
||||
"FID_INPUT_DATE_1": fid_input_date_1,
|
||||
"FID_INPUT_DATE_2": fid_input_date_2
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, "", params)
|
||||
|
||||
if res.isOK():
|
||||
return pd.DataFrame(res.getBody().output)
|
||||
else:
|
||||
res.printError(url=API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,85 @@
|
||||
"""
|
||||
Created on 20250101
|
||||
"""
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from comp_program_trade_today import comp_program_trade_today
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 프로그램매매 종합현황(시간) [국내주식-114]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'stck_bsop_date': '주식영업일자',
|
||||
'stck_clpr': '주식종가',
|
||||
'prdy_vrss': '전일대비',
|
||||
'prdy_vrss_sign': '전일대비부호',
|
||||
'prdy_ctrt': '전일대비율',
|
||||
'acml_vol': '누적거래량',
|
||||
'acml_tr_pbmn': '누적거래대금',
|
||||
'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_icdc2': '전체순매수거래대금증감2'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = ['전일대비율', '누적거래량', '누적거래대금', '전체합계매도거래량', '전체합계매수2',
|
||||
'전체합계순매수수량', '전체합계매도거래대금', '전체합계매수2거래대금', '전체합계순매수거래대금']
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
프로그램매매 종합현황(시간) 조회 테스트 함수
|
||||
|
||||
이 함수는 프로그램매매 종합현황(시간) API를 호출하여 결과를 출력합니다.
|
||||
테스트 데이터로 코스피(K) 시장을 사용합니다.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
# case1 조회
|
||||
logging.info("=== case1 조회 ===")
|
||||
try:
|
||||
result = comp_program_trade_today(fid_cond_mrkt_div_code="J", fid_mrkt_cls_code="K")
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
logging.info("사용 가능한 컬럼: %s", result.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환 및 데이터 출력
|
||||
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시 (메타데이터에서 number로 명시된 컬럼만)
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,81 @@
|
||||
"""
|
||||
Created on 20250101
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 프로그램매매 종합현황(시간) [국내주식-114]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/comp-program-trade-today"
|
||||
|
||||
def comp_program_trade_today(
|
||||
fid_cond_mrkt_div_code: str, # [필수] 시장 구분 코드 (J:KRX,NX:NXT,UN:통합)
|
||||
fid_mrkt_cls_code: str, # [필수] 시장구분코드 (K:코스피, Q:코스닥)
|
||||
fid_sctn_cls_code: str = "", # 구간 구분 코드
|
||||
fid_input_iscd: str = "", # 입력종목코드
|
||||
fid_cond_mrkt_div_code1: str = "", # 시장분류코드
|
||||
fid_input_hour_1: str = "" # 입력시간
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
프로그램매매 종합현황(시간) API입니다.
|
||||
한국투자 HTS(eFriend Plus) > [0460] 프로그램매매 종합현황 화면의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.
|
||||
|
||||
※ 장시간(09:00~15:30) 동안의 최근 30분간의 데이터 확인이 가능하며, 다음조회가 불가합니다.
|
||||
※ 장시간(09:00~15:30) 이후에는 bsop_hour 에 153000 ~ 170000 까지의 시간데이터가 출력되지만 데이터는 모두 동일한 장마감 데이터인 점 유의 부탁드립니다.
|
||||
|
||||
Args:
|
||||
fid_cond_mrkt_div_code (str): [필수] 시장 구분 코드 (ex. J:KRX,NX:NXT,UN:통합)
|
||||
fid_mrkt_cls_code (str): [필수] 시장구분코드 (ex. K:코스피, Q:코스닥)
|
||||
fid_sctn_cls_code (str): 구간 구분 코드
|
||||
fid_input_iscd (str): 입력종목코드
|
||||
fid_cond_mrkt_div_code1 (str): 시장분류코드
|
||||
fid_input_hour_1 (str): 입력시간
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: 프로그램매매 종합현황 데이터
|
||||
|
||||
Example:
|
||||
>>> df = comp_program_trade_today("J", "K")
|
||||
>>> print(df)
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if fid_cond_mrkt_div_code == "":
|
||||
raise ValueError("fid_cond_mrkt_div_code is required (e.g. 'J:KRX,NX:NXT,UN:통합')")
|
||||
|
||||
if fid_mrkt_cls_code == "":
|
||||
raise ValueError("fid_mrkt_cls_code is required (e.g. 'K:코스피, Q:코스닥')")
|
||||
|
||||
tr_id = "FHPPG04600101" # 프로그램매매 종합현황(시간)
|
||||
|
||||
params = {
|
||||
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code, # 시장 구분 코드
|
||||
"FID_MRKT_CLS_CODE": fid_mrkt_cls_code, # 시장구분코드
|
||||
"FID_SCTN_CLS_CODE": fid_sctn_cls_code, # 구간 구분 코드
|
||||
"FID_INPUT_ISCD": fid_input_iscd, # 입력종목코드
|
||||
"FID_COND_MRKT_DIV_CODE1": fid_cond_mrkt_div_code1,# 시장분류코드
|
||||
"FID_INPUT_HOUR_1": fid_input_hour_1 # 입력시간
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, "", params)
|
||||
|
||||
if res.isOK():
|
||||
# array 타입이므로 DataFrame으로 반환
|
||||
current_data = pd.DataFrame(res.getBody().output)
|
||||
logging.info("Data fetch complete.")
|
||||
return current_data
|
||||
else:
|
||||
res.printError(url=API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,137 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from credit_balance import credit_balance
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > 국내주식 신용잔고 상위 [국내주식-109]
|
||||
##############################################################################################
|
||||
|
||||
# 통합 컬럼 매핑 (모든 output에서 공통 사용)
|
||||
COLUMN_MAPPING = {
|
||||
'bstp_cls_code': '업종 구분 코드',
|
||||
'hts_kor_isnm': 'HTS 한글 종목명',
|
||||
'stnd_date1': '기준 일자1',
|
||||
'stnd_date2': '기준 일자2',
|
||||
'mksc_shrn_iscd': '유가증권 단축 종목코드',
|
||||
'hts_kor_isnm': 'HTS 한글 종목명',
|
||||
'stck_prpr': '주식 현재가',
|
||||
'prdy_vrss': '전일 대비',
|
||||
'prdy_vrss_sign': '전일 대비 부호',
|
||||
'prdy_ctrt': '전일 대비율',
|
||||
'acml_vol': '누적 거래량',
|
||||
'whol_loan_rmnd_stcn': '전체 융자 잔고 주수',
|
||||
'whol_loan_rmnd_amt': '전체 융자 잔고 금액',
|
||||
'whol_loan_rmnd_rate': '전체 융자 잔고 비율',
|
||||
'whol_stln_rmnd_stcn': '전체 대주 잔고 주수',
|
||||
'whol_stln_rmnd_amt': '전체 대주 잔고 금액',
|
||||
'whol_stln_rmnd_rate': '전체 대주 잔고 비율',
|
||||
'nday_vrss_loan_rmnd_inrt': 'N일 대비 융자 잔고 증가율',
|
||||
'nday_vrss_stln_rmnd_inrt': 'N일 대비 대주 잔고 증가율'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
국내주식 신용잔고 상위[국내주식-109]
|
||||
|
||||
국내주식 신용잔고 상위 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_cond_scr_div_code (str): 조건 화면 분류 코드 (Unique key(11701))
|
||||
- fid_input_iscd (str): 입력 종목코드 (0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200,)
|
||||
- fid_option (str): 증가율기간 (2~999)
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (시장구분코드 (주식 J))
|
||||
- fid_rank_sort_cls_code (str): 순위 정렬 구분 코드 ('(융자)0:잔고비율 상위, 1: 잔고수량 상위, 2: 잔고금액 상위, 3: 잔고비율 증가상위, 4: 잔고비율 감소상위 (대주)5:잔고비율 상위, 6: 잔고수량 상위, 7: 잔고금액 상위, 8: 잔고비율 증가상위, 9: 잔고비율 감소상위 ')
|
||||
|
||||
Returns:
|
||||
- Tuple[DataFrame, ...]: 국내주식 신용잔고 상위 결과
|
||||
|
||||
Example:
|
||||
>>> df1, df2 = credit_balance(fid_cond_scr_div_code="11701", fid_input_iscd="0000", fid_option="2", fid_cond_mrkt_div_code="J", fid_rank_sort_cls_code="0")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
|
||||
# API 호출
|
||||
logger.info("API 호출 시작: 국내주식 신용잔고 상위")
|
||||
result1, result2 = credit_balance(
|
||||
fid_cond_scr_div_code="11701", # 조건 화면 분류 코드
|
||||
fid_input_iscd="0000", # 입력 종목코드
|
||||
fid_option="2", # 증가율기간
|
||||
fid_cond_mrkt_div_code="J", # 조건 시장 분류 코드
|
||||
fid_rank_sort_cls_code="0", # 순위 정렬 구분 코드
|
||||
)
|
||||
|
||||
# 결과 확인
|
||||
results = [result1, result2]
|
||||
if all(result is None or result.empty for result in results):
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
|
||||
# output1 결과 처리
|
||||
logger.info("=== output1 조회 ===")
|
||||
if not result1.empty:
|
||||
logger.info("사용 가능한 컬럼: %s", result1.columns.tolist())
|
||||
|
||||
# 통합 컬럼명 한글 변환 (필요한 컬럼만 자동 매핑됨)
|
||||
result1 = result1.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result1.columns:
|
||||
result1[col] = pd.to_numeric(result1[col], errors='coerce').round(2)
|
||||
|
||||
logger.info("output1 결과:")
|
||||
print(result1)
|
||||
else:
|
||||
logger.info("output1 데이터가 없습니다.")
|
||||
|
||||
# output2 결과 처리
|
||||
logger.info("=== output2 조회 ===")
|
||||
if not result2.empty:
|
||||
logger.info("사용 가능한 컬럼: %s", result2.columns.tolist())
|
||||
|
||||
# 통합 컬럼명 한글 변환 (필요한 컬럼만 자동 매핑됨)
|
||||
result2 = result2.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result2.columns:
|
||||
result2[col] = pd.to_numeric(result2[col], errors='coerce').round(2)
|
||||
|
||||
logger.info("output2 결과:")
|
||||
print(result2)
|
||||
else:
|
||||
logger.info("output2 데이터가 없습니다.")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,164 @@
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional, Tuple
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > 국내주식 신용잔고 상위 [국내주식-109]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/ranking/credit-balance"
|
||||
|
||||
def credit_balance(
|
||||
fid_cond_scr_div_code: str, # 조건 화면 분류 코드
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
fid_option: str, # 증가율기간
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
fid_rank_sort_cls_code: str, # 순위 정렬 구분 코드
|
||||
dataframe1: Optional[pd.DataFrame] = None, # 누적 데이터프레임 (output1)
|
||||
dataframe2: Optional[pd.DataFrame] = None, # 누적 데이터프레임 (output2)
|
||||
tr_cont: str = "",
|
||||
depth: int = 0,
|
||||
max_depth: int = 10
|
||||
) -> Tuple[pd.DataFrame, pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
국내주식 신용잔고 상위[국내주식-109]
|
||||
국내주식 신용잔고 상위 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_cond_scr_div_code (str): Unique key(11701)
|
||||
fid_input_iscd (str): 0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200,
|
||||
fid_option (str): 2~999
|
||||
fid_cond_mrkt_div_code (str): 시장구분코드 (주식 J)
|
||||
fid_rank_sort_cls_code (str): '(융자)0:잔고비율 상위, 1: 잔고수량 상위, 2: 잔고금액 상위, 3: 잔고비율 증가상위, 4: 잔고비율 감소상위 (대주)5:잔고비율 상위, 6: 잔고수량 상위, 7: 잔고금액 상위, 8: 잔고비율 증가상위, 9: 잔고비율 감소상위 '
|
||||
dataframe1 (Optional[pd.DataFrame]): 누적 데이터프레임 (output1)
|
||||
dataframe2 (Optional[pd.DataFrame]): 누적 데이터프레임 (output2)
|
||||
tr_cont (str): 연속 거래 여부
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Tuple[pd.DataFrame, pd.DataFrame]: 국내주식 신용잔고 상위 데이터
|
||||
|
||||
Example:
|
||||
>>> df1, df2 = credit_balance('11701', '0000', '2', 'J', '0')
|
||||
>>> print(df1)
|
||||
>>> print(df2)
|
||||
"""
|
||||
# 필수 파라미터 검증
|
||||
if not fid_cond_scr_div_code:
|
||||
logger.error("fid_cond_scr_div_code is required. (e.g. '11701')")
|
||||
raise ValueError("fid_cond_scr_div_code is required. (e.g. '11701')")
|
||||
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '0000')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '0000')")
|
||||
|
||||
if not fid_option:
|
||||
logger.error("fid_option is required. (e.g. '2')")
|
||||
raise ValueError("fid_option is required. (e.g. '2')")
|
||||
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
|
||||
if fid_rank_sort_cls_code not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']:
|
||||
logger.error("fid_rank_sort_cls_code is required. (e.g. '0')")
|
||||
raise ValueError("fid_rank_sort_cls_code is required. (e.g. '0')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe1 if dataframe1 is not None else pd.DataFrame(), dataframe2 if dataframe2 is not None else pd.DataFrame()
|
||||
|
||||
tr_id = "FHKST17010000"
|
||||
|
||||
params = {
|
||||
"FID_COND_SCR_DIV_CODE": fid_cond_scr_div_code,
|
||||
"FID_INPUT_ISCD": fid_input_iscd,
|
||||
"FID_OPTION": fid_option,
|
||||
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code,
|
||||
"FID_RANK_SORT_CLS_CODE": fid_rank_sort_cls_code,
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
# output1 처리
|
||||
if hasattr(res.getBody(), 'output1'):
|
||||
output_data = res.getBody().output1
|
||||
if output_data:
|
||||
# output1은 단일 객체, output2는 배열일 수 있음
|
||||
if isinstance(output_data, list):
|
||||
current_data1 = pd.DataFrame(output_data)
|
||||
else:
|
||||
# 단일 객체인 경우 리스트로 감싸서 DataFrame 생성
|
||||
current_data1 = pd.DataFrame([output_data])
|
||||
|
||||
if dataframe1 is not None:
|
||||
dataframe1 = pd.concat([dataframe1, current_data1], ignore_index=True)
|
||||
else:
|
||||
dataframe1 = current_data1
|
||||
else:
|
||||
if dataframe1 is None:
|
||||
dataframe1 = pd.DataFrame()
|
||||
else:
|
||||
if dataframe1 is None:
|
||||
dataframe1 = pd.DataFrame()
|
||||
# output2 처리
|
||||
if hasattr(res.getBody(), 'output2'):
|
||||
output_data = res.getBody().output2
|
||||
if output_data:
|
||||
# output1은 단일 객체, output2는 배열일 수 있음
|
||||
if isinstance(output_data, list):
|
||||
current_data2 = pd.DataFrame(output_data)
|
||||
else:
|
||||
# 단일 객체인 경우 리스트로 감싸서 DataFrame 생성
|
||||
current_data2 = pd.DataFrame([output_data])
|
||||
|
||||
if dataframe2 is not None:
|
||||
dataframe2 = pd.concat([dataframe2, current_data2], ignore_index=True)
|
||||
else:
|
||||
dataframe2 = current_data2
|
||||
else:
|
||||
if dataframe2 is None:
|
||||
dataframe2 = pd.DataFrame()
|
||||
else:
|
||||
if dataframe2 is None:
|
||||
dataframe2 = pd.DataFrame()
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont in ["M", "F"]:
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return credit_balance(
|
||||
fid_cond_scr_div_code,
|
||||
fid_input_iscd,
|
||||
fid_option,
|
||||
fid_cond_mrkt_div_code,
|
||||
fid_rank_sort_cls_code,
|
||||
"N", dataframe1, dataframe2, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe1, dataframe2
|
||||
else:
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame(), pd.DataFrame()
|
||||
@@ -0,0 +1,96 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from credit_by_company import credit_by_company
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 당사 신용가능종목[국내주식-111]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'stck_shrn_iscd': '주식 단축 종목코드',
|
||||
'hts_kor_isnm': 'HTS 한글 종목명',
|
||||
'crdt_rate': '신용 비율'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 당사 신용가능종목[국내주식-111]
|
||||
|
||||
국내주식 당사 신용가능종목 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_rank_sort_cls_code (str): 순위 정렬 구분 코드 (0:코드순, 1:이름순)
|
||||
- fid_slct_yn (str): 선택 여부 (0:신용주문가능, 1: 신용주문불가)
|
||||
- fid_input_iscd (str): 입력 종목코드 (0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200, 4001: KRX100)
|
||||
- fid_cond_scr_div_code (str): 조건 화면 분류 코드 (Unique key(20477))
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (시장구분코드 (주식 J))
|
||||
Returns:
|
||||
- DataFrame: 국내주식 당사 신용가능종목 결과
|
||||
|
||||
Example:
|
||||
>>> df = credit_by_company(fid_rank_sort_cls_code="0", fid_slct_yn="0", fid_input_iscd="0000", fid_cond_scr_div_code="20477", fid_cond_mrkt_div_code="J")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
|
||||
# API 호출
|
||||
result = credit_by_company(
|
||||
fid_rank_sort_cls_code="0", # 순위 정렬 구분 코드
|
||||
fid_slct_yn="0", # 선택 여부
|
||||
fid_input_iscd="0000", # 입력 종목코드
|
||||
fid_cond_scr_div_code="20477", # 조건 화면 분류 코드
|
||||
fid_cond_mrkt_div_code="J", # 조건 시장 분류 코드
|
||||
)
|
||||
|
||||
if result is None or result.empty:
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# 컬럼명 출력
|
||||
logger.info("사용 가능한 컬럼 목록:")
|
||||
logger.info(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
logger.info("=== 국내주식 당사 신용가능종목 결과 ===")
|
||||
logger.info("조회된 데이터 건수: %d", len(result))
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,151 @@
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 당사 신용가능종목[국내주식-111]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/credit-by-company"
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def credit_by_company(
|
||||
fid_rank_sort_cls_code: str, # 순위 정렬 구분 코드
|
||||
fid_slct_yn: str, # 선택 여부
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
fid_cond_scr_div_code: str, # 조건 화면 분류 코드
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
tr_cont: str = "", # 연속 거래 여부
|
||||
dataframe: Optional[pd.DataFrame] = None, # 누적 데이터프레임
|
||||
depth: int = 0, # 현재 재귀 깊이
|
||||
max_depth: int = 10 # 최대 재귀 깊이
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 당사 신용가능종목[국내주식-111]
|
||||
국내주식 당사 신용가능종목 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_rank_sort_cls_code (str): 0:코드순, 1:이름순
|
||||
fid_slct_yn (str): 0:신용주문가능, 1: 신용주문불가
|
||||
fid_input_iscd (str): 0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200, 4001: KRX100
|
||||
fid_cond_scr_div_code (str): Unique key(20477)
|
||||
fid_cond_mrkt_div_code (str): 시장구분코드 (주식 J)
|
||||
tr_cont (str): 연속 거래 여부
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: 국내주식 당사 신용가능종목 데이터
|
||||
|
||||
Example:
|
||||
>>> df = credit_by_company(
|
||||
... fid_rank_sort_cls_code="1",
|
||||
... fid_slct_yn="0",
|
||||
... fid_input_iscd="0000",
|
||||
... fid_cond_scr_div_code="20477",
|
||||
... fid_cond_mrkt_div_code="J"
|
||||
... )
|
||||
>>> print(df)
|
||||
"""
|
||||
# 로깅 설정
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not fid_rank_sort_cls_code:
|
||||
logger.error("fid_rank_sort_cls_code is required. (e.g. '1')")
|
||||
raise ValueError("fid_rank_sort_cls_code is required. (e.g. '1')")
|
||||
|
||||
if not fid_slct_yn:
|
||||
logger.error("fid_slct_yn is required. (e.g. '0')")
|
||||
raise ValueError("fid_slct_yn is required. (e.g. '0')")
|
||||
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '0000')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '0000')")
|
||||
|
||||
if not fid_cond_scr_div_code:
|
||||
logger.error("fid_cond_scr_div_code is required. (e.g. '20477')")
|
||||
raise ValueError("fid_cond_scr_div_code is required. (e.g. '20477')")
|
||||
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe if dataframe is not None else pd.DataFrame()
|
||||
|
||||
# API 호출 URL 및 ID 설정
|
||||
|
||||
tr_id = "FHPST04770000"
|
||||
|
||||
# 요청 파라미터 설정
|
||||
params = {
|
||||
"fid_rank_sort_cls_code": fid_rank_sort_cls_code,
|
||||
"fid_slct_yn": fid_slct_yn,
|
||||
"fid_input_iscd": fid_input_iscd,
|
||||
"fid_cond_scr_div_code": fid_cond_scr_div_code,
|
||||
"fid_cond_mrkt_div_code": fid_cond_mrkt_div_code,
|
||||
}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
# API 호출 성공 시 데이터 처리
|
||||
if res.isOK():
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
output_data = res.getBody().output
|
||||
if not isinstance(output_data, list):
|
||||
output_data = [output_data]
|
||||
current_data = pd.DataFrame(output_data)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
# 기존 데이터프레임과 병합
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
# 연속 거래 여부 확인
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
# 다음 페이지 호출
|
||||
if tr_cont == "M":
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return credit_by_company(
|
||||
fid_rank_sort_cls_code,
|
||||
fid_slct_yn,
|
||||
fid_input_iscd,
|
||||
fid_cond_scr_div_code,
|
||||
fid_cond_mrkt_div_code,
|
||||
"N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
# API 호출 실패 시 에러 로그 출력
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,122 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from daily_credit_balance import daily_credit_balance
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 국내주식 신용잔고 일별추이[국내주식-110]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'deal_date': '매매 일자',
|
||||
'stck_prpr': '주식 현재가',
|
||||
'prdy_vrss_sign': '전일 대비 부호',
|
||||
'prdy_vrss': '전일 대비',
|
||||
'prdy_ctrt': '전일 대비율',
|
||||
'acml_vol': '누적 거래량',
|
||||
'stlm_date': '결제 일자',
|
||||
'whol_loan_new_stcn': '전체 융자 신규 주수',
|
||||
'whol_loan_rdmp_stcn': '전체 융자 상환 주수',
|
||||
'whol_loan_rmnd_stcn': '전체 융자 잔고 주수',
|
||||
'whol_loan_new_amt': '전체 융자 신규 금액',
|
||||
'whol_loan_rdmp_amt': '전체 융자 상환 금액',
|
||||
'whol_loan_rmnd_amt': '전체 융자 잔고 금액',
|
||||
'whol_loan_rmnd_rate': '전체 융자 잔고 비율',
|
||||
'whol_loan_gvrt': '전체 융자 공여율',
|
||||
'whol_stln_new_stcn': '전체 대주 신규 주수',
|
||||
'whol_stln_rdmp_stcn': '전체 대주 상환 주수',
|
||||
'whol_stln_rmnd_stcn': '전체 대주 잔고 주수',
|
||||
'whol_stln_new_amt': '전체 대주 신규 금액',
|
||||
'whol_stln_rdmp_amt': '전체 대주 상환 금액',
|
||||
'whol_stln_rmnd_amt': '전체 대주 잔고 금액',
|
||||
'whol_stln_rmnd_rate': '전체 대주 잔고 비율',
|
||||
'whol_stln_gvrt': '전체 대주 공여율',
|
||||
'stck_oprc': '주식 시가2',
|
||||
'stck_hgpr': '주식 최고가',
|
||||
'stck_lwpr': '주식 최저가'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = ['전일 대비율', '누적 거래량', '전체 융자 신규 주수', '전체 융자 상환 주수', '전체 융자 잔고 주수',
|
||||
'전체 융자 신규 금액', '전체 융자 상환 금액', '전체 융자 잔고 금액', '전체 융자 잔고 비율', '전체 융자 공여율',
|
||||
'전체 대주 신규 주수', '전체 대주 상환 주수', '전체 대주 잔고 주수', '전체 대주 신규 금액', '전체 대주 상환 금액',
|
||||
'전체 대주 잔고 금액', '전체 대주 잔고 비율', '전체 대주 공여율', '주식 시가2', '주식 최고가', '주식 최저가']
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내주식 신용잔고 일별추이 조회 테스트 함수
|
||||
|
||||
이 함수는 국내주식 신용잔고 일별추이 API를 호출하여 결과를 출력합니다.
|
||||
테스트 데이터로 셀트리온(068270)을 사용합니다.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
# case1 조회
|
||||
logging.info("=== case1 조회 ===")
|
||||
try:
|
||||
result1 = daily_credit_balance(fid_cond_mrkt_div_code="J", fid_cond_scr_div_code="20476",
|
||||
fid_input_iscd="068270", fid_input_date_1="20240508")
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
logging.info("사용 가능한 컬럼: %s", result1.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환 및 데이터 출력
|
||||
result1 = result1.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result1.columns:
|
||||
result1[col] = pd.to_numeric(result1[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result1)
|
||||
|
||||
# case2 조회
|
||||
logging.info("=== case2 조회 ===")
|
||||
try:
|
||||
result2 = daily_credit_balance(fid_cond_mrkt_div_code="J", fid_cond_scr_div_code="20476",
|
||||
fid_input_iscd="068270", fid_input_date_1="20240501")
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
logging.info("사용 가능한 컬럼: %s", result2.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환 및 데이터 출력
|
||||
result2 = result2.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result2.columns:
|
||||
result2[col] = pd.to_numeric(result2[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,112 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
import time
|
||||
from typing import Optional
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 국내주식 신용잔고 일별추이[국내주식-110]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/daily-credit-balance"
|
||||
|
||||
def daily_credit_balance(
|
||||
fid_cond_mrkt_div_code: str, # [필수] 시장 분류 코드
|
||||
fid_cond_scr_div_code: str, # [필수] 화면 분류 코드
|
||||
fid_input_iscd: str, # [필수] 종목코드
|
||||
fid_input_date_1: str, # [필수] 결제일자
|
||||
tr_cont: str = "", # 연속 거래 여부
|
||||
dataframe: Optional[pd.DataFrame] = None, # 누적 데이터프레임
|
||||
depth: int = 0, # 내부 재귀깊이 (자동관리)
|
||||
max_depth: int = 10 # 최대 재귀 횟수 제한
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
국내주식 신용잔고 일별추이 API입니다.
|
||||
한국투자 HTS(eFriend Plus) > [0476] 국내주식 신용잔고 일별추이 화면의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.
|
||||
한 번의 호출에 최대 30건 확인 가능하며, fid_input_date_1 을 입력하여 다음 조회가 가능합니다.
|
||||
|
||||
※ 상환수량은 "매도상환수량+현금상환수량"의 합계 수치입니다.
|
||||
|
||||
Args:
|
||||
fid_cond_mrkt_div_code (str): [필수] 시장 분류 코드 (ex. J: 주식)
|
||||
fid_cond_scr_div_code (str): [필수] 화면 분류 코드 (ex. 20476)
|
||||
fid_input_iscd (str): [필수] 종목코드 (ex. 005930)
|
||||
fid_input_date_1 (str): [필수] 결제일자 (ex. 20240313)
|
||||
tr_cont (str): 연속 거래 여부
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
depth (int): 내부 재귀깊이 (자동관리)
|
||||
max_depth (int): 최대 재귀 횟수 제한
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: 국내주식 신용잔고 일별추이 데이터
|
||||
|
||||
Example:
|
||||
>>> df = daily_credit_balance("J", "20476", "005930", "20240313")
|
||||
>>> print(df)
|
||||
"""
|
||||
|
||||
if fid_cond_mrkt_div_code == "":
|
||||
raise ValueError("fid_cond_mrkt_div_code is required (e.g. 'J')")
|
||||
|
||||
if fid_cond_scr_div_code == "":
|
||||
raise ValueError("fid_cond_scr_div_code is required (e.g. '20476')")
|
||||
|
||||
if fid_input_iscd == "":
|
||||
raise ValueError("fid_input_iscd is required (e.g. '005930')")
|
||||
|
||||
if fid_input_date_1 == "":
|
||||
raise ValueError("fid_input_date_1 is required (e.g. '20240313')")
|
||||
|
||||
if depth > max_depth:
|
||||
logging.warning("Max recursive depth reached.")
|
||||
if dataframe is None:
|
||||
return pd.DataFrame()
|
||||
else:
|
||||
return dataframe
|
||||
|
||||
tr_id = "FHPST04760000" # 국내주식 신용잔고 일별추이
|
||||
|
||||
params = {
|
||||
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code, # 시장 분류 코드
|
||||
"FID_COND_SCR_DIV_CODE": fid_cond_scr_div_code, # 화면 분류 코드
|
||||
"FID_INPUT_ISCD": fid_input_iscd, # 종목코드
|
||||
"FID_INPUT_DATE_1": fid_input_date_1 # 결제일자
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
current_data = pd.DataFrame(res.getBody().output)
|
||||
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont in ["M", "F"]: # 다음 페이지 존재
|
||||
logging.info("Call Next page...")
|
||||
ka.smart_sleep() # 시스템 안정적 운영을 위한 지연
|
||||
return daily_credit_balance(
|
||||
fid_cond_mrkt_div_code, fid_cond_scr_div_code, fid_input_iscd, fid_input_date_1, "N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logging.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
res.printError(url=API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,84 @@
|
||||
"""
|
||||
Created on 20250114
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from daily_loan_trans import daily_loan_trans
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 종목별 일별 대차거래추이 [국내주식-135]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'bsop_date': '일자',
|
||||
'stck_prpr': '주식 종가',
|
||||
'prdy_vrss_sign': '전일 대비 부호',
|
||||
'prdy_vrss': '전일 대비',
|
||||
'prdy_ctrt': '전일 대비율',
|
||||
'acml_vol': '누적 거래량',
|
||||
'new_stcn': '당일 증가 주수 (체결)',
|
||||
'rdmp_stcn': '당일 감소 주수 (상환)',
|
||||
'prdy_rmnd_vrss': '대차거래 증감',
|
||||
'rmnd_stcn': '당일 잔고 주수',
|
||||
'rmnd_amt': '당일 잔고 금액'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
종목별 일별 대차거래추이 조회 테스트 함수
|
||||
|
||||
이 함수는 종목별 일별 대차거래추이 API를 호출하여 결과를 출력합니다.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
# case1 조회
|
||||
logging.info("=== case1 조회 ===")
|
||||
try:
|
||||
result = daily_loan_trans(
|
||||
mrkt_div_cls_code="1",
|
||||
mksc_shrn_iscd="005930",
|
||||
start_date="20240301",
|
||||
end_date="20240328"
|
||||
)
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
logging.info("사용 가능한 컬럼: %s", result.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환 및 데이터 출력
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,74 @@
|
||||
"""
|
||||
Created on 20250114
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 종목별 일별 대차거래추이 [국내주식-135]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/daily-loan-trans"
|
||||
|
||||
def daily_loan_trans(
|
||||
mrkt_div_cls_code: str, # [필수] 조회구분 (ex. 1:코스피,2:코스닥,3:종목)
|
||||
mksc_shrn_iscd: str, # [필수] 종목코드 (ex. 123456)
|
||||
start_date: str = "", # 시작일자
|
||||
end_date: str = "", # 종료일자
|
||||
cts: str = "" # 이전조회KEY
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
종목별 일별 대차거래추이 API입니다.
|
||||
한 번의 조회에 최대 100건까지 조회 가능하며, start_date, end_date 를 수정하여 다음 조회가 가능합니다.
|
||||
|
||||
Args:
|
||||
mrkt_div_cls_code (str): [필수] 조회구분 (ex. 1:코스피,2:코스닥,3:종목)
|
||||
mksc_shrn_iscd (str): [필수] 종목코드 (ex. 123456)
|
||||
start_date (str): 시작일자
|
||||
end_date (str): 종료일자
|
||||
cts (str): 이전조회KEY
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: 종목별 일별 대차거래추이 데이터
|
||||
|
||||
Example:
|
||||
>>> df = daily_loan_trans(mrkt_div_cls_code="1", mksc_shrn_iscd="005930")
|
||||
>>> print(df)
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if mrkt_div_cls_code == "":
|
||||
raise ValueError("mrkt_div_cls_code is required (e.g. '1', '2', '3')")
|
||||
|
||||
if mksc_shrn_iscd == "":
|
||||
raise ValueError("mksc_shrn_iscd is required (e.g. '123456')")
|
||||
|
||||
tr_id = "HHPST074500C0"
|
||||
|
||||
params = {
|
||||
"MRKT_DIV_CLS_CODE": mrkt_div_cls_code,
|
||||
"MKSC_SHRN_ISCD": mksc_shrn_iscd,
|
||||
"START_DATE": start_date,
|
||||
"END_DATE": end_date,
|
||||
"CTS": cts
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, "", params)
|
||||
|
||||
if res.isOK():
|
||||
result_data = pd.DataFrame(res.getBody().output1)
|
||||
return result_data
|
||||
else:
|
||||
res.printError(url=API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,118 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from daily_short_sale import daily_short_sale
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 국내주식 공매도 일별추이[국내주식-134]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'stck_prpr': '주식 현재가',
|
||||
'prdy_vrss': '전일 대비',
|
||||
'prdy_vrss_sign': '전일 대비 부호',
|
||||
'prdy_ctrt': '전일 대비율',
|
||||
'acml_vol': '누적 거래량',
|
||||
'prdy_vol': '전일 거래량',
|
||||
'stck_bsop_date': '주식 영업 일자',
|
||||
'stck_clpr': '주식 종가',
|
||||
'prdy_vrss': '전일 대비',
|
||||
'prdy_vrss_sign': '전일 대비 부호',
|
||||
'prdy_ctrt': '전일 대비율',
|
||||
'acml_vol': '누적 거래량',
|
||||
'stnd_vol_smtn': '기준 거래량 합계',
|
||||
'ssts_cntg_qty': '공매도 체결 수량',
|
||||
'ssts_vol_rlim': '공매도 거래량 비중',
|
||||
'acml_ssts_cntg_qty': '누적 공매도 체결 수량',
|
||||
'acml_ssts_cntg_qty_rlim': '누적 공매도 체결 수량 비중',
|
||||
'acml_tr_pbmn': '누적 거래 대금',
|
||||
'stnd_tr_pbmn_smtn': '기준 거래대금 합계',
|
||||
'ssts_tr_pbmn': '공매도 거래 대금',
|
||||
'ssts_tr_pbmn_rlim': '공매도 거래대금 비중',
|
||||
'acml_ssts_tr_pbmn': '누적 공매도 거래 대금',
|
||||
'acml_ssts_tr_pbmn_rlim': '누적 공매도 거래 대금 비중',
|
||||
'stck_oprc': '주식 시가2',
|
||||
'stck_hgpr': '주식 최고가',
|
||||
'stck_lwpr': '주식 최저가',
|
||||
'avrg_prc': '평균가격'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내주식 공매도 일별추이 조회 테스트 함수
|
||||
|
||||
이 함수는 국내주식 공매도 일별추이 API를 호출하여 결과를 출력합니다.
|
||||
테스트 데이터로 삼성전자(005930)를 사용합니다.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
# case1 조회
|
||||
logging.info("=== case1 조회 ===")
|
||||
try:
|
||||
result1, result2 = daily_short_sale(
|
||||
fid_cond_mrkt_div_code="J",
|
||||
fid_input_iscd="005930",
|
||||
fid_input_date_1="20240301",
|
||||
fid_input_date_2="20240328"
|
||||
)
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
# output1 결과 처리
|
||||
logging.info("=== output1 결과 ===")
|
||||
logging.info("사용 가능한 컬럼: %s", result1.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환 및 데이터 출력
|
||||
result1 = result1.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시 (메타데이터에 number 타입 명시된 것이 없으므로 비어있음)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result1.columns:
|
||||
result1[col] = pd.to_numeric(result1[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result1)
|
||||
|
||||
# output2 결과 처리
|
||||
logging.info("=== output2 결과 ===")
|
||||
logging.info("사용 가능한 컬럼: %s" % result2.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환 및 데이터 출력
|
||||
result2 = result2.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시 (메타데이터에 number 타입 명시된 것이 없으므로 비어있음)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result2.columns:
|
||||
result2[col] = pd.to_numeric(result2[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,77 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
from typing import Tuple
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 국내주식 공매도 일별추이[국내주식-134]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/daily-short-sale"
|
||||
|
||||
def daily_short_sale(
|
||||
fid_cond_mrkt_div_code: str, # [필수] 시장분류코드 (ex. J:주식)
|
||||
fid_input_iscd: str, # [필수] 종목코드 (ex. 123456)
|
||||
fid_input_date_1: str = "", # 시작일자
|
||||
fid_input_date_2: str = "" # 종료일자
|
||||
) -> Tuple[pd.DataFrame, pd.DataFrame]:
|
||||
"""
|
||||
국내주식 공매도 일별추이를 조회합니다.
|
||||
|
||||
Args:
|
||||
fid_cond_mrkt_div_code (str): [필수] 시장분류코드 (ex. J:주식)
|
||||
fid_input_iscd (str): [필수] 종목코드 (ex. 123456)
|
||||
fid_input_date_1 (str): 시작일자
|
||||
fid_input_date_2 (str): 종료일자
|
||||
|
||||
Returns:
|
||||
Tuple[pd.DataFrame, pd.DataFrame]: (output1, output2) 데이터프레임 쌍
|
||||
|
||||
Example:
|
||||
>>> df1, df2 = daily_short_sale("J", "005930", "20240301", "20240328")
|
||||
>>> print(df1)
|
||||
>>> print(df2)
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if fid_cond_mrkt_div_code == "":
|
||||
raise ValueError("fid_cond_mrkt_div_code is required (e.g. 'J:주식')")
|
||||
|
||||
if fid_input_iscd == "":
|
||||
raise ValueError("fid_input_iscd is required (e.g. '123456')")
|
||||
|
||||
tr_id = "FHPST04830000"
|
||||
|
||||
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,
|
||||
"FID_INPUT_DATE_2": fid_input_date_2
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, "", params)
|
||||
|
||||
if res.isOK():
|
||||
# output1 처리 (object 타입 -> DataFrame)
|
||||
output1_data = pd.DataFrame(res.getBody().output1, index=[0])
|
||||
|
||||
# output2 처리 (array 타입 -> DataFrame)
|
||||
output2_data = pd.DataFrame(res.getBody().output2)
|
||||
|
||||
return output1_data, output2_data
|
||||
else:
|
||||
res.printError(url=API_URL)
|
||||
return pd.DataFrame(), pd.DataFrame()
|
||||
@@ -0,0 +1,119 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-16
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from disparity import disparity
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > 국내주식 이격도 순위 [v1_국내주식-095]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'mksc_shrn_iscd': '유가증권 단축 종목코드',
|
||||
'data_rank': '데이터 순위',
|
||||
'hts_kor_isnm': 'HTS 한글 종목명',
|
||||
'stck_prpr': '주식 현재가',
|
||||
'prdy_vrss': '전일 대비',
|
||||
'prdy_ctrt': '전일 대비율',
|
||||
'prdy_vrss_sign': '전일 대비 부호',
|
||||
'acml_vol': '누적 거래량',
|
||||
'd5_dsrt': '5일 이격도',
|
||||
'd10_dsrt': '10일 이격도',
|
||||
'd20_dsrt': '20일 이격도',
|
||||
'd60_dsrt': '60일 이격도',
|
||||
'd120_dsrt': '120일 이격도'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
국내주식 이격도 순위[v1_국내주식-095]
|
||||
|
||||
국내주식 이격도 순위 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_input_price_2 (str): 입력 가격2 (입력값 없을때 전체 (~ 가격))
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (시장구분코드 (주식 J))
|
||||
- fid_cond_scr_div_code (str): 조건 화면 분류 코드 (Unique key( 20178 ))
|
||||
- fid_div_cls_code (str): 분류 구분 코드 (0: 전체, 1:관리종목, 2:투자주의, 3:투자경고, 4:투자위험예고, 5:투자위험, 6:보톧주, 7:우선주)
|
||||
- fid_rank_sort_cls_code (str): 순위 정렬 구분 코드 (0: 이격도상위순, 1:이격도하위순)
|
||||
- fid_hour_cls_code (str): 시간 구분 코드 (5:이격도5, 10:이격도10, 20:이격도20, 60:이격도60, 120:이격도120)
|
||||
- fid_input_iscd (str): 입력 종목코드 (0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200)
|
||||
- fid_trgt_cls_code (str): 대상 구분 코드 (0 : 전체)
|
||||
- fid_trgt_exls_cls_code (str): 대상 제외 구분 코드 (0 : 전체)
|
||||
- fid_input_price_1 (str): 입력 가격1 (입력값 없을때 전체 (가격 ~))
|
||||
- fid_vol_cnt (str): 거래량 수 (입력값 없을때 전체 (거래량 ~))
|
||||
Returns:
|
||||
- DataFrame: 국내주식 이격도 순위 결과
|
||||
|
||||
Example:
|
||||
>>> df = disparity(fid_input_price_2="", fid_cond_mrkt_div_code="J", fid_cond_scr_div_code="20178", fid_div_cls_code="0", fid_rank_sort_cls_code="0", fid_hour_cls_code="5", fid_input_iscd="0000", fid_trgt_cls_code="0", fid_trgt_exls_cls_code="0", fid_input_price_1="", fid_vol_cnt="")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
|
||||
# API 호출
|
||||
logger.info("API 호출 시작: 국내주식 이격도 순위")
|
||||
result = disparity(
|
||||
fid_input_price_2="", # 입력 가격2
|
||||
fid_cond_mrkt_div_code="J", # 조건 시장 분류 코드
|
||||
fid_cond_scr_div_code="20178", # 조건 화면 분류 코드
|
||||
fid_div_cls_code="0", # 분류 구분 코드
|
||||
fid_rank_sort_cls_code="0", # 순위 정렬 구분 코드
|
||||
fid_hour_cls_code="5", # 시간 구분 코드
|
||||
fid_input_iscd="0000", # 입력 종목코드
|
||||
fid_trgt_cls_code="0", # 대상 구분 코드
|
||||
fid_trgt_exls_cls_code="0", # 대상 제외 구분 코드
|
||||
fid_input_price_1="", # 입력 가격1
|
||||
fid_vol_cnt="" # 거래량 수
|
||||
)
|
||||
|
||||
if result is None or result.empty:
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# 컬럼명 출력
|
||||
logger.info("사용 가능한 컬럼 목록:")
|
||||
logger.info(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
logger.info("=== 국내주식 이격도 순위 결과 ===")
|
||||
logger.info("조회된 데이터 건수: %d", len(result))
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
169
한국투자증권(API)/examples_llm/domestic_stock/disparity/disparity.py
Normal file
169
한국투자증권(API)/examples_llm/domestic_stock/disparity/disparity.py
Normal file
@@ -0,0 +1,169 @@
|
||||
"""
|
||||
Created on 2025-06-16
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > 국내주식 이격도 순위 [v1_국내주식-095]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/ranking/disparity"
|
||||
|
||||
def disparity(
|
||||
fid_input_price_2: str, # 입력 가격2
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
fid_cond_scr_div_code: str, # 조건 화면 분류 코드
|
||||
fid_div_cls_code: str, # 분류 구분 코드
|
||||
fid_rank_sort_cls_code: str, # 순위 정렬 구분 코드
|
||||
fid_hour_cls_code: str, # 시간 구분 코드
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
fid_trgt_cls_code: str, # 대상 구분 코드
|
||||
fid_trgt_exls_cls_code: str, # 대상 제외 구분 코드
|
||||
fid_input_price_1: str, # 입력 가격1
|
||||
fid_vol_cnt: str, # 거래량 수
|
||||
tr_cont: str = "", # 연속 거래 여부
|
||||
dataframe: Optional[pd.DataFrame] = None, # 누적 데이터프레임
|
||||
depth: int = 0, # 현재 재귀 깊이
|
||||
max_depth: int = 10 # 최대 재귀 깊이
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
국내주식 이격도 순위[v1_국내주식-095]
|
||||
국내주식 이격도 순위 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_input_price_2 (str): 입력값 없을때 전체 (~ 가격)
|
||||
fid_cond_mrkt_div_code (str): 시장구분코드 (J:KRX, NX:NXT)
|
||||
fid_cond_scr_div_code (str): Unique key( 20178 )
|
||||
fid_div_cls_code (str): 0: 전체, 1:관리종목, 2:투자주의, 3:투자경고, 4:투자위험예고, 5:투자위험, 6:보톧주, 7:우선주
|
||||
fid_rank_sort_cls_code (str): 0: 이격도상위순, 1:이격도하위순
|
||||
fid_hour_cls_code (str): 5:이격도5, 10:이격도10, 20:이격도20, 60:이격도60, 120:이격도120
|
||||
fid_input_iscd (str): 0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200
|
||||
fid_trgt_cls_code (str): 0 : 전체
|
||||
fid_trgt_exls_cls_code (str): 0 : 전체
|
||||
fid_input_price_1 (str): 입력값 없을때 전체 (가격 ~)
|
||||
fid_vol_cnt (str): 입력값 없을때 전체 (거래량 ~)
|
||||
tr_cont (str): 연속 거래 여부
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: 국내주식 이격도 순위 데이터
|
||||
|
||||
Example:
|
||||
>>> df = disparity(
|
||||
... fid_input_price_2="",
|
||||
... fid_cond_mrkt_div_code="J",
|
||||
... fid_cond_scr_div_code="20178",
|
||||
... fid_div_cls_code="0",
|
||||
... fid_rank_sort_cls_code="0",
|
||||
... fid_hour_cls_code="5",
|
||||
... fid_input_iscd="0000",
|
||||
... fid_trgt_cls_code="0",
|
||||
... fid_trgt_exls_cls_code="0",
|
||||
... fid_input_price_1="",
|
||||
... fid_vol_cnt=""
|
||||
... )
|
||||
>>> print(df)
|
||||
"""
|
||||
# 필수 파라미터 검증
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
|
||||
if not fid_cond_scr_div_code:
|
||||
logger.error("fid_cond_scr_div_code is required. (e.g. '20178')")
|
||||
raise ValueError("fid_cond_scr_div_code is required. (e.g. '20178')")
|
||||
|
||||
if not fid_div_cls_code:
|
||||
logger.error("fid_div_cls_code is required. (e.g. '0')")
|
||||
raise ValueError("fid_div_cls_code is required. (e.g. '0')")
|
||||
|
||||
if not fid_rank_sort_cls_code:
|
||||
logger.error("fid_rank_sort_cls_code is required. (e.g. '0')")
|
||||
raise ValueError("fid_rank_sort_cls_code is required. (e.g. '0')")
|
||||
|
||||
if not fid_hour_cls_code:
|
||||
logger.error("fid_hour_cls_code is required. (e.g. '5')")
|
||||
raise ValueError("fid_hour_cls_code is required. (e.g. '5')")
|
||||
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '0000')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '0000')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe if dataframe is not None else pd.DataFrame()
|
||||
|
||||
tr_id = "FHPST01780000"
|
||||
|
||||
params = {
|
||||
"fid_input_price_2": fid_input_price_2,
|
||||
"fid_cond_mrkt_div_code": fid_cond_mrkt_div_code,
|
||||
"fid_cond_scr_div_code": fid_cond_scr_div_code,
|
||||
"fid_div_cls_code": fid_div_cls_code,
|
||||
"fid_rank_sort_cls_code": fid_rank_sort_cls_code,
|
||||
"fid_hour_cls_code": fid_hour_cls_code,
|
||||
"fid_input_iscd": fid_input_iscd,
|
||||
"fid_trgt_cls_code": fid_trgt_cls_code,
|
||||
"fid_trgt_exls_cls_code": fid_trgt_exls_cls_code,
|
||||
"fid_input_price_1": fid_input_price_1,
|
||||
"fid_vol_cnt": fid_vol_cnt,
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
current_data = pd.DataFrame(res.getBody().output)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont == "M":
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return disparity(
|
||||
fid_input_price_2,
|
||||
fid_cond_mrkt_div_code,
|
||||
fid_cond_scr_div_code,
|
||||
fid_div_cls_code,
|
||||
fid_rank_sort_cls_code,
|
||||
fid_hour_cls_code,
|
||||
fid_input_iscd,
|
||||
fid_trgt_cls_code,
|
||||
fid_trgt_exls_cls_code,
|
||||
fid_input_price_1,
|
||||
fid_vol_cnt,
|
||||
"N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,106 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-16
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from dividend_rate import dividend_rate
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > 국내주식 배당률 상위[국내주식-106]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'rank': '순위',
|
||||
'sht_cd': '종목코드',
|
||||
'record_date': '기준일',
|
||||
'per_sto_divi_amt': '현금/주식배당금',
|
||||
'divi_rate': '현금/주식배당률(%)',
|
||||
'divi_kind': '배당종류'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
국내주식 배당률 상위[국내주식-106]
|
||||
|
||||
국내주식 배당률 상위 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- cts_area (str): CTS_AREA (공백)
|
||||
- gb1 (str): KOSPI (0:전체, 1:코스피, 2: 코스피200, 3: 코스닥)
|
||||
- upjong (str): 업종구분 ('코스피(0001:종합, 0002:대형주.…0027:제조업 ), 코스닥(1001:종합, …. 1041:IT부품 코스피200 (2001:KOSPI200, 2007:KOSPI100, 2008:KOSPI50)')
|
||||
- gb2 (str): 종목선택 (0:전체, 6:보통주, 7:우선주)
|
||||
- gb3 (str): 배당구분 (1:주식배당, 2: 현금배당)
|
||||
- f_dt (str): 기준일From ()
|
||||
- t_dt (str): 기준일To ()
|
||||
- gb4 (str): 결산/중간배당 (0:전체, 1:결산배당, 2:중간배당)
|
||||
Returns:
|
||||
- DataFrame: 국내주식 배당률 상위 결과
|
||||
|
||||
Example:
|
||||
>>> df = dividend_rate(cts_area="", gb1="0", upjong="0001", gb2="0", gb3="1", f_dt="20230101", t_dt="20231231", gb4="0")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
|
||||
# API 호출
|
||||
result = dividend_rate(
|
||||
cts_area="", # CTS_AREA
|
||||
gb1="0", # KOSPI
|
||||
upjong="0001", # 업종구분
|
||||
gb2="0", # 종목선택
|
||||
gb3="1", # 배당구분
|
||||
f_dt="20230101", # 기준일From
|
||||
t_dt="20231231", # 기준일To
|
||||
gb4="0", # 결산/중간배당
|
||||
)
|
||||
|
||||
if result is None or result.empty:
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# 컬럼명 출력
|
||||
logger.info("사용 가능한 컬럼 목록:")
|
||||
logger.info(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
logger.info("=== 국내주식 배당률 상위 결과 ===")
|
||||
logger.info("조회된 데이터 건수: %d", len(result))
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,160 @@
|
||||
"""
|
||||
Created on 2025-06-16
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > 국내주식 배당률 상위[국내주식-106]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/ranking/dividend-rate"
|
||||
|
||||
def dividend_rate(
|
||||
cts_area: str, # CTS_AREA
|
||||
gb1: str, # KOSPI
|
||||
upjong: str, # 업종구분
|
||||
gb2: str, # 종목선택
|
||||
gb3: str, # 배당구분
|
||||
f_dt: str, # 기준일From
|
||||
t_dt: str, # 기준일To
|
||||
gb4: str, # 결산/중간배당
|
||||
tr_cont: str = "",
|
||||
dataframe: Optional[pd.DataFrame] = None,
|
||||
depth: int = 0,
|
||||
max_depth: int = 10
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
국내주식 배당률 상위[국내주식-106]
|
||||
국내주식 배당률 상위 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
cts_area (str): 공백
|
||||
gb1 (str): 0:전체, 1:코스피, 2: 코스피200, 3: 코스닥,
|
||||
upjong (str): '코스피(0001:종합, 0002:대형주.…0027:제조업 ), 코스닥(1001:종합, …. 1041:IT부품 코스피200 (2001:KOSPI200, 2007:KOSPI100, 2008:KOSPI50)'
|
||||
gb2 (str): 0:전체, 6:보통주, 7:우선주
|
||||
gb3 (str): 1:주식배당, 2: 현금배당
|
||||
f_dt (str): 기준일 시작
|
||||
t_dt (str): 기준일 종료
|
||||
gb4 (str): 0:전체, 1:결산배당, 2:중간배당
|
||||
tr_cont (str): 연속 거래 여부
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: 국내주식 배당률 상위 데이터
|
||||
|
||||
Example:
|
||||
>>> df = dividend_rate(
|
||||
... cts_area=" ",
|
||||
... gb1="1",
|
||||
... upjong="0001",
|
||||
... gb2="0",
|
||||
... gb3="1",
|
||||
... f_dt="20230101",
|
||||
... t_dt="20231231",
|
||||
... gb4="0"
|
||||
... )
|
||||
>>> print(df)
|
||||
"""
|
||||
# 필수 파라미터 검증
|
||||
if not gb1:
|
||||
logger.error("gb1 is required. (e.g. '1')")
|
||||
raise ValueError("gb1 is required. (e.g. '1')")
|
||||
|
||||
if not upjong:
|
||||
logger.error("upjong is required. (e.g. '0001')")
|
||||
raise ValueError("upjong is required. (e.g. '0001')")
|
||||
|
||||
if not gb2:
|
||||
logger.error("gb2 is required. (e.g. '0')")
|
||||
raise ValueError("gb2 is required. (e.g. '0')")
|
||||
|
||||
if not gb3:
|
||||
logger.error("gb3 is required. (e.g. '1')")
|
||||
raise ValueError("gb3 is required. (e.g. '1')")
|
||||
|
||||
if not f_dt:
|
||||
logger.error("f_dt is required. (e.g. '20230101')")
|
||||
raise ValueError("f_dt is required. (e.g. '20230101')")
|
||||
|
||||
if not t_dt:
|
||||
logger.error("t_dt is required. (e.g. '20231231')")
|
||||
raise ValueError("t_dt is required. (e.g. '20231231')")
|
||||
|
||||
if not gb4:
|
||||
logger.error("gb4 is required. (e.g. '0')")
|
||||
raise ValueError("gb4 is required. (e.g. '0')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe if dataframe is not None else pd.DataFrame()
|
||||
|
||||
|
||||
tr_id = "HHKDB13470100"
|
||||
|
||||
params = {
|
||||
"CTS_AREA": cts_area,
|
||||
"GB1": gb1,
|
||||
"UPJONG": upjong,
|
||||
"GB2": gb2,
|
||||
"GB3": gb3,
|
||||
"F_DT": f_dt,
|
||||
"T_DT": t_dt,
|
||||
"GB4": gb4,
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
current_data = pd.DataFrame(res.getBody().output)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont == "M":
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return dividend_rate(
|
||||
cts_area,
|
||||
gb1,
|
||||
upjong,
|
||||
gb2,
|
||||
gb3,
|
||||
f_dt,
|
||||
t_dt,
|
||||
gb4,
|
||||
"N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,163 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from estimate_perform import estimate_perform
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 종목추정실적[국내주식-187]
|
||||
##############################################################################################
|
||||
|
||||
# 통합 컬럼 매핑 (모든 output에서 공통 사용)
|
||||
COLUMN_MAPPING = {
|
||||
'sht_cd': 'ELW단축종목코드',
|
||||
'item_kor_nm': 'HTS한글종목명',
|
||||
'estdate': '전일대비부호',
|
||||
'capital': '누적거래량',
|
||||
'forn_item_lmtrt': '행사가',
|
||||
'data1': 'DATA1',
|
||||
'data2': 'DATA2',
|
||||
'data3': 'DATA3',
|
||||
'data4': 'DATA4',
|
||||
'data5': 'DATA5',
|
||||
'output3': '응답상세',
|
||||
'data1': 'DATA1',
|
||||
'data2': 'DATA2',
|
||||
'data3': 'DATA3',
|
||||
'data4': 'DATA4',
|
||||
'data5': 'DATA5',
|
||||
'output4': '응답상세',
|
||||
'dt': '결산년월'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 종목추정실적[국내주식-187]
|
||||
|
||||
국내주식 종목추정실적 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- sht_cd (str): 종목코드 (ex) 265520)
|
||||
|
||||
Returns:
|
||||
- Tuple[DataFrame, ...]: 국내주식 종목추정실적 결과
|
||||
|
||||
Example:
|
||||
>>> df1, df2, df3, df4 = estimate_perform(sht_cd="265520")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
|
||||
# API 호출
|
||||
logger.info("API 호출 시작: 국내주식 종목추정실적")
|
||||
result1, result2, result3, result4 = estimate_perform(
|
||||
sht_cd="265520", # 종목코드
|
||||
)
|
||||
|
||||
# 결과 확인
|
||||
results = [result1, result2, result3, result4]
|
||||
if all(result is None or result.empty for result in results):
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# output1 결과 처리
|
||||
logger.info("=== output1 조회 ===")
|
||||
if not result1.empty:
|
||||
logger.info("사용 가능한 컬럼: %s", result1.columns.tolist())
|
||||
|
||||
# 통합 컬럼명 한글 변환 (필요한 컬럼만 자동 매핑됨)
|
||||
result1 = result1.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result1.columns:
|
||||
result1[col] = pd.to_numeric(result1[col], errors='coerce').round(2)
|
||||
|
||||
logger.info("output1 결과:")
|
||||
print(result1)
|
||||
else:
|
||||
logger.info("output1 데이터가 없습니다.")
|
||||
|
||||
# output2 결과 처리
|
||||
logger.info("=== output2 조회 ===")
|
||||
if not result2.empty:
|
||||
logger.info("사용 가능한 컬럼: %s", result2.columns.tolist())
|
||||
|
||||
# 통합 컬럼명 한글 변환 (필요한 컬럼만 자동 매핑됨)
|
||||
result2 = result2.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result2.columns:
|
||||
result2[col] = pd.to_numeric(result2[col], errors='coerce').round(2)
|
||||
|
||||
logger.info("output2 결과:")
|
||||
print(result2)
|
||||
else:
|
||||
logger.info("output2 데이터가 없습니다.")
|
||||
|
||||
# output3 결과 처리
|
||||
logger.info("=== output3 조회 ===")
|
||||
if not result3.empty:
|
||||
logger.info("사용 가능한 컬럼: %s", result3.columns.tolist())
|
||||
|
||||
# 통합 컬럼명 한글 변환 (필요한 컬럼만 자동 매핑됨)
|
||||
result3 = result3.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result3.columns:
|
||||
result3[col] = pd.to_numeric(result3[col], errors='coerce').round(2)
|
||||
|
||||
logger.info("output3 결과:")
|
||||
print(result3)
|
||||
else:
|
||||
logger.info("output3 데이터가 없습니다.")
|
||||
|
||||
# output4 결과 처리
|
||||
logger.info("=== output4 조회 ===")
|
||||
if not result4.empty:
|
||||
logger.info("사용 가능한 컬럼: %s", result4.columns.tolist())
|
||||
|
||||
# 통합 컬럼명 한글 변환 (필요한 컬럼만 자동 매핑됨)
|
||||
result4 = result4.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result4.columns:
|
||||
result4[col] = pd.to_numeric(result4[col], errors='coerce').round(2)
|
||||
|
||||
logger.info("output4 결과:")
|
||||
print(result4)
|
||||
else:
|
||||
logger.info("output4 데이터가 없습니다.")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,138 @@
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional, Tuple
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 종목추정실적[국내주식-187]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/estimate-perform"
|
||||
|
||||
def estimate_perform(
|
||||
sht_cd: str, # 종목코드
|
||||
dataframe1: Optional[pd.DataFrame] = None, # 누적 데이터프레임 (output1)
|
||||
dataframe2: Optional[pd.DataFrame] = None, # 누적 데이터프레임 (output2)
|
||||
dataframe3: Optional[pd.DataFrame] = None, # 누적 데이터프레임 (output3)
|
||||
dataframe4: Optional[pd.DataFrame] = None, # 누적 데이터프레임 (output4)
|
||||
tr_cont: str = "",
|
||||
depth: int = 0,
|
||||
max_depth: int = 10
|
||||
) -> Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame, pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 종목추정실적[국내주식-187]
|
||||
국내주식 종목추정실적 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
sht_cd (str): 종목코드 (예: 265520)
|
||||
dataframe1 (Optional[pd.DataFrame]): 누적 데이터프레임 (output1)
|
||||
dataframe2 (Optional[pd.DataFrame]): 누적 데이터프레임 (output2)
|
||||
dataframe3 (Optional[pd.DataFrame]): 누적 데이터프레임 (output3)
|
||||
dataframe4 (Optional[pd.DataFrame]): 누적 데이터프레임 (output4)
|
||||
tr_cont (str): 연속 거래 여부
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame, pd.DataFrame]: 국내주식 종목추정실적 데이터
|
||||
|
||||
Example:
|
||||
>>> df1, df2, df3, df4 = estimate_perform("265520")
|
||||
>>> print(df1)
|
||||
>>> print(df2)
|
||||
"""
|
||||
# 필수 파라미터 검증
|
||||
if not sht_cd:
|
||||
logger.error("sht_cd is required. (e.g. '265520')")
|
||||
raise ValueError("sht_cd is required. (e.g. '265520')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return (
|
||||
dataframe1 if dataframe1 is not None else pd.DataFrame(),
|
||||
dataframe2 if dataframe2 is not None else pd.DataFrame(),
|
||||
dataframe3 if dataframe3 is not None else pd.DataFrame(),
|
||||
dataframe4 if dataframe4 is not None else pd.DataFrame()
|
||||
)
|
||||
|
||||
tr_id = "HHKST668300C0"
|
||||
|
||||
params = {
|
||||
"SHT_CD": sht_cd,
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
# output1 처리
|
||||
if hasattr(res.getBody(), 'output1'):
|
||||
output_data = res.getBody().output1
|
||||
if output_data:
|
||||
current_data1 = pd.DataFrame(output_data if isinstance(output_data, list) else [output_data])
|
||||
dataframe1 = pd.concat([dataframe1, current_data1],
|
||||
ignore_index=True) if dataframe1 is not None else current_data1
|
||||
else:
|
||||
dataframe1 = pd.DataFrame() if dataframe1 is None else dataframe1
|
||||
|
||||
# output2 처리
|
||||
if hasattr(res.getBody(), 'output2'):
|
||||
output_data = res.getBody().output2
|
||||
if output_data:
|
||||
current_data2 = pd.DataFrame(output_data if isinstance(output_data, list) else [output_data])
|
||||
dataframe2 = pd.concat([dataframe2, current_data2],
|
||||
ignore_index=True) if dataframe2 is not None else current_data2
|
||||
else:
|
||||
dataframe2 = pd.DataFrame() if dataframe2 is None else dataframe2
|
||||
|
||||
# output3 처리
|
||||
if hasattr(res.getBody(), 'output3'):
|
||||
output_data = res.getBody().output3
|
||||
if output_data:
|
||||
current_data3 = pd.DataFrame(output_data if isinstance(output_data, list) else [output_data])
|
||||
dataframe3 = pd.concat([dataframe3, current_data3],
|
||||
ignore_index=True) if dataframe3 is not None else current_data3
|
||||
else:
|
||||
dataframe3 = pd.DataFrame() if dataframe3 is None else dataframe3
|
||||
|
||||
# output4 처리
|
||||
if hasattr(res.getBody(), 'output4'):
|
||||
output_data = res.getBody().output4
|
||||
if output_data:
|
||||
current_data4 = pd.DataFrame(output_data if isinstance(output_data, list) else [output_data])
|
||||
dataframe4 = pd.concat([dataframe4, current_data4],
|
||||
ignore_index=True) if dataframe4 is not None else current_data4
|
||||
else:
|
||||
dataframe4 = pd.DataFrame() if dataframe4 is None else dataframe4
|
||||
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont in ["M", "F"]:
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return estimate_perform(
|
||||
sht_cd, dataframe1, dataframe2, dataframe3, dataframe4, "N", depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe1, dataframe2, dataframe3, dataframe4
|
||||
else:
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame(), pd.DataFrame(), pd.DataFrame(), pd.DataFrame()
|
||||
@@ -0,0 +1,145 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from exp_ccnl_krx import exp_ccnl_krx
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
"mksc_shrn_iscd": "유가증권단축종목코드",
|
||||
"stck_cntg_hour": "주식체결시간",
|
||||
"stck_prpr": "주식현재가",
|
||||
"prdy_vrss_sign": "전일대비구분",
|
||||
"prdy_vrss": "전일대비",
|
||||
"prdy_ctrt": "등락율",
|
||||
"wghn_avrg_stck_prc": "가중평균주식가격",
|
||||
"stck_oprc": "시가",
|
||||
"stck_hgpr": "고가",
|
||||
"stck_lwpr": "저가",
|
||||
"askp1": "매도호가",
|
||||
"bidp1": "매수호가",
|
||||
"cntg_vol": "거래량",
|
||||
"acml_vol": "누적거래량",
|
||||
"acml_tr_pbmn": "누적거래대금",
|
||||
"seln_cntg_csnu": "매도체결건수",
|
||||
"shnu_cntg_csnu": "매수체결건수",
|
||||
"ntby_cntg_csnu": "순매수체결건수",
|
||||
"cttr": "체결강도",
|
||||
"seln_cntg_smtn": "총매도수량",
|
||||
"shnu_cntg_smtn": "총매수수량",
|
||||
"cntg_cls_code": "체결구분",
|
||||
"shnu_rate": "매수비율",
|
||||
"prdy_vol_vrss_acml_vol_rate": "전일거래량대비등락율",
|
||||
"oprc_hour": "시가시간",
|
||||
"oprc_vrss_prpr_sign": "시가대비구분",
|
||||
"oprc_vrss_prpr": "시가대비",
|
||||
"hgpr_hour": "최고가시간",
|
||||
"hgpr_vrss_prpr_sign": "고가대비구분",
|
||||
"hgpr_vrss_prpr": "고가대비",
|
||||
"lwpr_hour": "최저가시간",
|
||||
"lwpr_vrss_prpr_sign": "저가대비구분",
|
||||
"lwpr_vrss_prpr": "저가대비",
|
||||
"bsop_date": "영업일자",
|
||||
"new_mkop_cls_code": "신장운영구분코드",
|
||||
"trht_yn": "거래정지여부",
|
||||
"askp_rsqn1": "매도호가잔량1",
|
||||
"bidp_rsqn1": "매수호가잔량1",
|
||||
"total_askp_rsqn": "총매도호가잔량",
|
||||
"total_bidp_rsqn": "총매수호가잔량",
|
||||
"vol_tnrt": "거래량회전율",
|
||||
"prdy_smns_hour_acml_vol": "전일동시간누적거래량",
|
||||
"prdy_smns_hour_acml_vol_rate": "전일동시간누적거래량비율",
|
||||
"hour_cls_code": "시간구분코드",
|
||||
"mrkt_trtm_cls_code": "임의종료구분코드"
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = [
|
||||
"주식현재가", "전일대비", "등락율", "가중평균주식가격", "시가", "고가", "저가",
|
||||
"매도호가", "매수호가", "거래량", "누적거래량", "누적거래대금", "매도체결건수",
|
||||
"매수체결건수", "순매수체결건수", "체결강도", "총매도수량", "총매수수량", "매수비율",
|
||||
"전일거래량대비등락율", "시가대비", "고가대비", "저가대비", "매도호가잔량1",
|
||||
"매수호가잔량1", "총매도호가잔량", "총매수호가잔량", "거래량회전율",
|
||||
"전일동시간누적거래량", "전일동시간누적거래량비율"
|
||||
]
|
||||
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간예상체결 (KRX) [실시간-041]
|
||||
##############################################################################################
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내주식 실시간예상체결 (KRX)
|
||||
|
||||
국내주식 실시간예상체결 API입니다.
|
||||
|
||||
[참고자료]
|
||||
종목코드 마스터파일 파이썬 정제코드는 한국투자증권 Github 참고 부탁드립니다.
|
||||
https://github.com/koreainvestment/open-trading-api/tree/main/stocks_info
|
||||
|
||||
|
||||
[호출 데이터]
|
||||
헤더와 바디 값을 합쳐 JSON 형태로 전송합니다.
|
||||
|
||||
[응답 데이터]
|
||||
1. 정상 등록 여부 (JSON)
|
||||
- JSON["body"]["msg1"] - 정상 응답 시, SUBSCRIBE SUCCESS
|
||||
- JSON["body"]["output"]["iv"] - 실시간 결과 복호화에 필요한 AES256 IV (Initialize Vector)
|
||||
- JSON["body"]["output"]["key"] - 실시간 결과 복호화에 필요한 AES256 Key
|
||||
|
||||
2. 실시간 결과 응답 ( | 로 구분되는 값)
|
||||
ex) 0|H0STCNT0|004|005930^123929^73100^5^...
|
||||
- 암호화 유무 : 0 암호화 되지 않은 데이터 / 1 암호화된 데이터
|
||||
- TR_ID : 등록한 tr_id (ex. H0STCNT0)
|
||||
- 데이터 건수 : (ex. 001 인 경우 데이터 건수 1건, 004인 경우 데이터 건수 4건)
|
||||
- 응답 데이터 : 아래 response 데이터 참조 ( ^로 구분됨)
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
ka.auth_ws()
|
||||
|
||||
# 인증(auth_ws()) 이후에 선언
|
||||
kws = ka.KISWebSocket(api_url="/tryitout")
|
||||
|
||||
# 조회
|
||||
kws.subscribe(request=exp_ccnl_krx, data=["005930", "000660"])
|
||||
|
||||
# 결과 표시
|
||||
def on_result(ws, tr_id: str, result: pd.DataFrame, data_map: dict):
|
||||
try:
|
||||
|
||||
# 컬럼명 매핑
|
||||
result.rename(columns=COLUMN_MAPPING, inplace=True)
|
||||
|
||||
# 숫자형 컬럼 변환
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce')
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
except Exception as e:
|
||||
logging.error(f"결과 처리 중 오류: {e}")
|
||||
logging.error(f"받은 데이터: {result}")
|
||||
|
||||
kws.start(on_result=on_result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,107 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간예상체결 (KRX) [실시간-041]
|
||||
##############################################################################################
|
||||
|
||||
|
||||
def exp_ccnl_krx(
|
||||
tr_type: str,
|
||||
tr_key: str,
|
||||
) -> tuple[dict, list[str]]:
|
||||
"""
|
||||
국내주식 실시간예상체결 (KRX)[H0STANC0]
|
||||
국내주식 실시간예상체결 API를 통해 실시간 데이터를 구독합니다.
|
||||
|
||||
Args:
|
||||
tr_type (str): [필수] 구독 등록("1") 또는 해제("0") 여부를 나타냅니다.
|
||||
tr_key (str): [필수] 종목코드. 빈 문자열이 아니어야 하며, 유효한 종목코드 형식이어야 합니다.
|
||||
|
||||
Returns:
|
||||
message (dict): 실시간 데이터 구독에 대한 메시지 데이터.
|
||||
columns (list[str]): 실시간 데이터의 컬럼 정보.
|
||||
|
||||
Raises:
|
||||
ValueError: tr_key가 빈 문자열인 경우 발생합니다.
|
||||
|
||||
Example:
|
||||
>>> msg, columns = exp_ccnl_krx("1", "005930")
|
||||
>>> print(msg, columns)
|
||||
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not tr_key:
|
||||
raise ValueError("tr_key is required and cannot be an empty string")
|
||||
|
||||
tr_id = "H0STANC0"
|
||||
|
||||
params = {
|
||||
"tr_key": tr_key,
|
||||
}
|
||||
|
||||
# 데이터 구독 요청
|
||||
msg = ka.data_fetch(tr_id, tr_type, params)
|
||||
|
||||
# 응답 데이터 컬럼 정보
|
||||
columns = [
|
||||
"mksc_shrn_iscd",
|
||||
"stck_cntg_hour",
|
||||
"stck_prpr",
|
||||
"prdy_vrss_sign",
|
||||
"prdy_vrss",
|
||||
"prdy_ctrt",
|
||||
"wghn_avrg_stck_prc",
|
||||
"stck_oprc",
|
||||
"stck_hgpr",
|
||||
"stck_lwpr",
|
||||
"askp1",
|
||||
"bidp1",
|
||||
"cntg_vol",
|
||||
"acml_vol",
|
||||
"acml_tr_pbmn",
|
||||
"seln_cntg_csnu",
|
||||
"shnu_cntg_csnu",
|
||||
"ntby_cntg_csnu",
|
||||
"cttr",
|
||||
"seln_cntg_smtn",
|
||||
"shnu_cntg_smtn",
|
||||
"cntg_cls_code",
|
||||
"shnu_rate",
|
||||
"prdy_vol_vrss_acml_vol_rate",
|
||||
"oprc_hour",
|
||||
"oprc_vrss_prpr_sign",
|
||||
"oprc_vrss_prpr",
|
||||
"hgpr_hour",
|
||||
"hgpr_vrss_prpr_sign",
|
||||
"hgpr_vrss_prpr",
|
||||
"lwpr_hour",
|
||||
"lwpr_vrss_prpr_sign",
|
||||
"lwpr_vrss_prpr",
|
||||
"bsop_date",
|
||||
"new_mkop_cls_code",
|
||||
"trht_yn",
|
||||
"askp_rsqn1",
|
||||
"bidp_rsqn1",
|
||||
"total_askp_rsqn",
|
||||
"total_bidp_rsqn",
|
||||
"vol_tnrt",
|
||||
"prdy_smns_hour_acml_vol",
|
||||
"prdy_smns_hour_acml_vol_rate",
|
||||
"hour_cls_code",
|
||||
"mrkt_trtm_cls_code",
|
||||
]
|
||||
|
||||
return msg, columns
|
||||
@@ -0,0 +1,127 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from exp_ccnl_nxt import exp_ccnl_nxt
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간예상체결 (NXT)
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
"MKSC_SHRN_ISCD": "유가증권단축종목코드",
|
||||
"STCK_CNTG_HOUR": "주식체결시간",
|
||||
"STCK_PRPR": "주식현재가",
|
||||
"PRDY_VRSS_SIGN": "전일대비구분",
|
||||
"PRDY_VRSS": "전일대비",
|
||||
"PRDY_CTRT": "등락율",
|
||||
"WGHN_AVRG_STCK_PRC": "가중평균주식가격",
|
||||
"STCK_OPRC": "시가",
|
||||
"STCK_HGPR": "고가",
|
||||
"STCK_LWPR": "저가",
|
||||
"ASKP1": "매도호가",
|
||||
"BIDP1": "매수호가",
|
||||
"CNTG_VOL": "거래량",
|
||||
"ACML_VOL": "누적거래량",
|
||||
"ACML_TR_PBMN": "누적거래대금",
|
||||
"SELN_CNTG_CSNU": "매도체결건수",
|
||||
"SHNU_CNTG_CSNU": "매수체결건수",
|
||||
"NTBY_CNTG_CSNU": "순매수체결건수",
|
||||
"CTTR": "체결강도",
|
||||
"SELN_CNTG_SMTN": "총매도수량",
|
||||
"SHNU_CNTG_SMTN": "총매수수량",
|
||||
"CNTG_CLS_CODE": "체결구분",
|
||||
"SHNU_RATE": "매수비율",
|
||||
"PRDY_VOL_VRSS_ACML_VOL_RATE": "전일거래량대비등락율",
|
||||
"OPRC_HOUR": "시가시간",
|
||||
"OPRC_VRSS_PRPR_SIGN": "시가대비구분",
|
||||
"OPRC_VRSS_PRPR": "시가대비",
|
||||
"HGPR_HOUR": "최고가시간",
|
||||
"HGPR_VRSS_PRPR_SIGN": "고가대비구분",
|
||||
"HGPR_VRSS_PRPR": "고가대비",
|
||||
"LWPR_HOUR": "최저가시간",
|
||||
"LWPR_VRSS_PRPR_SIGN": "저가대비구분",
|
||||
"LWPR_VRSS_PRPR": "저가대비",
|
||||
"BSOP_DATE": "영업일자",
|
||||
"NEW_MKOP_CLS_CODE": "신장운영구분코드",
|
||||
"TRHT_YN": "거래정지여부",
|
||||
"ASKP_RSQN1": "매도호가잔량1",
|
||||
"BIDP_RSQN1": "매수호가잔량1",
|
||||
"TOTAL_ASKP_RSQN": "총매도호가잔량",
|
||||
"TOTAL_BIDP_RSQN": "총매수호가잔량",
|
||||
"VOL_TNRT": "거래량회전율",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL": "전일동시간누적거래량",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL_RATE": "전일동시간누적거래량비율",
|
||||
"HOUR_CLS_CODE": "시간구분코드",
|
||||
"MRKT_TRTM_CLS_CODE": "임의종료구분코드",
|
||||
"VI_STND_PRC": "VI 상태값"
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = [
|
||||
"주식현재가", "전일대비", "등락율", "가중평균주식가격", "시가", "고가", "저가",
|
||||
"매도호가", "매수호가", "거래량", "누적거래량", "누적거래대금", "매도체결건수",
|
||||
"매수체결건수", "순매수체결건수", "체결강도", "총매도수량", "총매수수량", "매수비율",
|
||||
"전일거래량대비등락율", "시가대비", "고가대비", "저가대비", "매도호가잔량1",
|
||||
"매수호가잔량1", "총매도호가잔량", "총매수호가잔량", "거래량회전율", "전일동시간누적거래량",
|
||||
"전일동시간누적거래량비율", "VI 상태값"
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내주식 실시간예상체결 (NXT)
|
||||
|
||||
국내주식 실시간예상체결 (NXT) API입니다.
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
ka.auth_ws()
|
||||
|
||||
# 인증(auth_ws()) 이후에 선언
|
||||
kws = ka.KISWebSocket(api_url="/tryitout")
|
||||
|
||||
# 조회
|
||||
kws.subscribe(
|
||||
request=exp_ccnl_nxt,
|
||||
data=["005930", "000660", "005380"]
|
||||
)
|
||||
|
||||
# 결과 표시
|
||||
def on_result(ws, tr_id: str, result: pd.DataFrame, data_map: dict):
|
||||
try:
|
||||
# 컬럼 매핑
|
||||
result.rename(columns=COLUMN_MAPPING, inplace=True)
|
||||
|
||||
# 숫자형 컬럼 변환
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce')
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
except Exception as e:
|
||||
logging.error(f"결과 처리 중 오류: {e}")
|
||||
logging.error(f"받은 데이터: {result}")
|
||||
|
||||
kws.start(on_result=on_result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,109 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간예상체결 (NXT)
|
||||
##############################################################################################
|
||||
|
||||
def exp_ccnl_nxt(
|
||||
tr_type: str,
|
||||
tr_key: str,
|
||||
) -> tuple[dict, list[str]]:
|
||||
"""
|
||||
국내주식 실시간예상체결 (NXT)[H0NXANC0]
|
||||
국내주식 실시간예상체결 (NXT) API를 통해 실시간 데이터를 구독합니다.
|
||||
|
||||
Args:
|
||||
tr_type (str): [필수] 구독 등록("1") 또는 해제("0") 여부를 나타내는 값
|
||||
tr_key (str): [필수] 종목코드 (빈 문자열 불가)
|
||||
|
||||
Returns:
|
||||
message (dict): 실시간 데이터 메시지
|
||||
columns (list[str]): 응답 데이터의 컬럼 정보
|
||||
|
||||
Raises:
|
||||
ValueError: tr_key가 빈 문자열인 경우 발생
|
||||
|
||||
Example:
|
||||
>>> msg, columns = exp_ccnl_nxt("1", "005930")
|
||||
>>> print(msg, columns)
|
||||
|
||||
Note:
|
||||
이 함수는 웹소켓을 통해 실시간 데이터를 구독합니다. 구독을 시작하면 실시간으로 데이터가 수신됩니다.
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not tr_key:
|
||||
raise ValueError("tr_key is required and cannot be an empty string")
|
||||
|
||||
tr_id = "H0NXANC0"
|
||||
|
||||
params = {
|
||||
"tr_key": tr_key,
|
||||
}
|
||||
|
||||
# 데이터 구독 요청
|
||||
msg = ka.data_fetch(tr_id, tr_type, params)
|
||||
|
||||
# 응답 데이터의 컬럼 정보
|
||||
columns = [
|
||||
"MKSC_SHRN_ISCD",
|
||||
"STCK_CNTG_HOUR",
|
||||
"STCK_PRPR",
|
||||
"PRDY_VRSS_SIGN",
|
||||
"PRDY_VRSS",
|
||||
"PRDY_CTRT",
|
||||
"WGHN_AVRG_STCK_PRC",
|
||||
"STCK_OPRC",
|
||||
"STCK_HGPR",
|
||||
"STCK_LWPR",
|
||||
"ASKP1",
|
||||
"BIDP1",
|
||||
"CNTG_VOL",
|
||||
"ACML_VOL",
|
||||
"ACML_TR_PBMN",
|
||||
"SELN_CNTG_CSNU",
|
||||
"SHNU_CNTG_CSNU",
|
||||
"NTBY_CNTG_CSNU",
|
||||
"CTTR",
|
||||
"SELN_CNTG_SMTN",
|
||||
"SHNU_CNTG_SMTN",
|
||||
"CNTG_CLS_CODE",
|
||||
"SHNU_RATE",
|
||||
"PRDY_VOL_VRSS_ACML_VOL_RATE",
|
||||
"OPRC_HOUR",
|
||||
"OPRC_VRSS_PRPR_SIGN",
|
||||
"OPRC_VRSS_PRPR",
|
||||
"HGPR_HOUR",
|
||||
"HGPR_VRSS_PRPR_SIGN",
|
||||
"HGPR_VRSS_PRPR",
|
||||
"LWPR_HOUR",
|
||||
"LWPR_VRSS_PRPR_SIGN",
|
||||
"LWPR_VRSS_PRPR",
|
||||
"BSOP_DATE",
|
||||
"NEW_MKOP_CLS_CODE",
|
||||
"TRHT_YN",
|
||||
"ASKP_RSQN1",
|
||||
"BIDP_RSQN1",
|
||||
"TOTAL_ASKP_RSQN",
|
||||
"TOTAL_BIDP_RSQN",
|
||||
"VOL_TNRT",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL_RATE",
|
||||
"HOUR_CLS_CODE",
|
||||
"MRKT_TRTM_CLS_CODE",
|
||||
"VI_STND_PRC",
|
||||
]
|
||||
|
||||
return msg, columns
|
||||
@@ -0,0 +1,127 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from exp_ccnl_total import exp_ccnl_total
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간예상체결(통합)
|
||||
##############################################################################################
|
||||
|
||||
# 컬럼명 매핑
|
||||
COLUMN_MAPPING = {
|
||||
"MKSC_SHRN_ISCD": "유가증권단축종목코드",
|
||||
"STCK_CNTG_HOUR": "주식체결시간",
|
||||
"STCK_PRPR": "주식현재가",
|
||||
"PRDY_VRSS_SIGN": "전일대비구분",
|
||||
"PRDY_VRSS": "전일대비",
|
||||
"PRDY_CTRT": "등락율",
|
||||
"WGHN_AVRG_STCK_PRC": "가중평균주식가격",
|
||||
"STCK_OPRC": "시가",
|
||||
"STCK_HGPR": "고가",
|
||||
"STCK_LWPR": "저가",
|
||||
"ASKP1": "매도호가",
|
||||
"BIDP1": "매수호가",
|
||||
"CNTG_VOL": "거래량",
|
||||
"ACML_VOL": "누적거래량",
|
||||
"ACML_TR_PBMN": "누적거래대금",
|
||||
"SELN_CNTG_CSNU": "매도체결건수",
|
||||
"SHNU_CNTG_CSNU": "매수체결건수",
|
||||
"NTBY_CNTG_CSNU": "순매수체결건수",
|
||||
"CTTR": "체결강도",
|
||||
"SELN_CNTG_SMTN": "총매도수량",
|
||||
"SHNU_CNTG_SMTN": "총매수수량",
|
||||
"CNTG_CLS_CODE": "체결구분",
|
||||
"SHNU_RATE": "매수비율",
|
||||
"PRDY_VOL_VRSS_ACML_VOL_RATE": "전일거래량대비등락율",
|
||||
"OPRC_HOUR": "시가시간",
|
||||
"OPRC_VRSS_PRPR_SIGN": "시가대비구분",
|
||||
"OPRC_VRSS_PRPR": "시가대비",
|
||||
"HGPR_HOUR": "최고가시간",
|
||||
"HGPR_VRSS_PRPR_SIGN": "고가대비구분",
|
||||
"HGPR_VRSS_PRPR": "고가대비",
|
||||
"LWPR_HOUR": "최저가시간",
|
||||
"LWPR_VRSS_PRPR_SIGN": "저가대비구분",
|
||||
"LWPR_VRSS_PRPR": "저가대비",
|
||||
"BSOP_DATE": "영업일자",
|
||||
"NEW_MKOP_CLS_CODE": "신장운영구분코드",
|
||||
"TRHT_YN": "거래정지여부",
|
||||
"ASKP_RSQN1": "매도호가잔량1",
|
||||
"BIDP_RSQN1": "매수호가잔량1",
|
||||
"TOTAL_ASKP_RSQN": "총매도호가잔량",
|
||||
"TOTAL_BIDP_RSQN": "총매수호가잔량",
|
||||
"VOL_TNRT": "거래량회전율",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL": "전일동시간누적거래량",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL_RATE": "전일동시간누적거래량비율",
|
||||
"HOUR_CLS_CODE": "시간구분코드",
|
||||
"MRKT_TRTM_CLS_CODE": "임의종료구분코드",
|
||||
"VI_STND_PRC": "VI 상태값"
|
||||
}
|
||||
|
||||
# 숫자형 컬럼 리스트
|
||||
NUMERIC_COLUMNS = [
|
||||
"STCK_PRPR", "PRDY_VRSS", "PRDY_CTRT", "WGHN_AVRG_STCK_PRC", "STCK_OPRC",
|
||||
"STCK_HGPR", "STCK_LWPR", "ASKP1", "BIDP1", "CNTG_VOL", "ACML_VOL",
|
||||
"ACML_TR_PBMN", "SELN_CNTG_CSNU", "SHNU_CNTG_CSNU", "NTBY_CNTG_CSNU",
|
||||
"CTTR", "SELN_CNTG_SMTN", "SHNU_CNTG_SMTN", "SHNU_RATE",
|
||||
"PRDY_VOL_VRSS_ACML_VOL_RATE", "OPRC_VRSS_PRPR", "HGPR_VRSS_PRPR",
|
||||
"LWPR_VRSS_PRPR", "ASKP_RSQN1", "BIDP_RSQN1", "TOTAL_ASKP_RSQN",
|
||||
"TOTAL_BIDP_RSQN", "VOL_TNRT", "PRDY_SMNS_HOUR_ACML_VOL",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL_RATE", "VI_STND_PRC"
|
||||
]
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내주식 실시간예상체결 (통합)
|
||||
|
||||
국내주식 실시간예상체결 (통합) API입니다.
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
ka.auth_ws()
|
||||
|
||||
# 인증(auth_ws()) 이후에 선언
|
||||
kws = ka.KISWebSocket(api_url="/tryitout")
|
||||
|
||||
# 조회
|
||||
kws.subscribe(request=exp_ccnl_total, data=["005930", "000660"])
|
||||
|
||||
# 결과 표시
|
||||
def on_result(ws, tr_id: str, result: pd.DataFrame, data_map: dict):
|
||||
try:
|
||||
# 컬럼명 매핑
|
||||
result.rename(columns=COLUMN_MAPPING, inplace=True)
|
||||
|
||||
# 숫자형 컬럼 변환
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce')
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
except Exception as e:
|
||||
logging.error(f"결과 처리 중 오류: {e}")
|
||||
logging.error(f"받은 데이터: {result}")
|
||||
|
||||
kws.start(on_result=on_result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,106 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내주식 실시간예상체결(통합)
|
||||
##############################################################################################
|
||||
|
||||
def exp_ccnl_total(
|
||||
tr_type: str,
|
||||
tr_key: str,
|
||||
) -> tuple[dict, list[str]]:
|
||||
"""
|
||||
국내주식 실시간예상체결 (통합)[H0UNANC0]
|
||||
국내주식 실시간예상체결 (통합) API입니다. 이 함수는 웹소켓을 통해 실시간 데이터를 구독하거나 구독 해제합니다.
|
||||
|
||||
Args:
|
||||
tr_type (str): [필수] 구독 등록("1") 또는 해제("0") 여부를 나타내는 값
|
||||
tr_key (str): [필수] 종목코드 (빈 문자열 불가)
|
||||
|
||||
Returns:
|
||||
message (dict): 실시간 데이터 메시지
|
||||
columns (list[str]): 데이터의 컬럼 정보
|
||||
|
||||
Example:
|
||||
>>> msg, columns = exp_ccnl_total("1", "005930")
|
||||
>>> print(msg, columns)
|
||||
|
||||
Note:
|
||||
웹소켓을 통해 실시간 데이터를 수신하며, 구독 등록 시 지속적으로 데이터가 업데이트됩니다.
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not tr_key:
|
||||
raise ValueError("tr_key는 필수 입력값입니다. 빈 문자열을 사용할 수 없습니다.")
|
||||
|
||||
tr_id = "H0UNANC0"
|
||||
|
||||
params = {
|
||||
"tr_key": tr_key,
|
||||
}
|
||||
|
||||
# 웹소켓을 통해 데이터를 가져옵니다.
|
||||
msg = ka.data_fetch(tr_id, tr_type, params)
|
||||
|
||||
# API 메타데이터에 기반한 정확한 컬럼 리스트
|
||||
columns = [
|
||||
"MKSC_SHRN_ISCD",
|
||||
"STCK_CNTG_HOUR",
|
||||
"STCK_PRPR",
|
||||
"PRDY_VRSS_SIGN",
|
||||
"PRDY_VRSS",
|
||||
"PRDY_CTRT",
|
||||
"WGHN_AVRG_STCK_PRC",
|
||||
"STCK_OPRC",
|
||||
"STCK_HGPR",
|
||||
"STCK_LWPR",
|
||||
"ASKP1",
|
||||
"BIDP1",
|
||||
"CNTG_VOL",
|
||||
"ACML_VOL",
|
||||
"ACML_TR_PBMN",
|
||||
"SELN_CNTG_CSNU",
|
||||
"SHNU_CNTG_CSNU",
|
||||
"NTBY_CNTG_CSNU",
|
||||
"CTTR",
|
||||
"SELN_CNTG_SMTN",
|
||||
"SHNU_CNTG_SMTN",
|
||||
"CNTG_CLS_CODE",
|
||||
"SHNU_RATE",
|
||||
"PRDY_VOL_VRSS_ACML_VOL_RATE",
|
||||
"OPRC_HOUR",
|
||||
"OPRC_VRSS_PRPR_SIGN",
|
||||
"OPRC_VRSS_PRPR",
|
||||
"HGPR_HOUR",
|
||||
"HGPR_VRSS_PRPR_SIGN",
|
||||
"HGPR_VRSS_PRPR",
|
||||
"LWPR_HOUR",
|
||||
"LWPR_VRSS_PRPR_SIGN",
|
||||
"LWPR_VRSS_PRPR",
|
||||
"BSOP_DATE",
|
||||
"NEW_MKOP_CLS_CODE",
|
||||
"TRHT_YN",
|
||||
"ASKP_RSQN1",
|
||||
"BIDP_RSQN1",
|
||||
"TOTAL_ASKP_RSQN",
|
||||
"TOTAL_BIDP_RSQN",
|
||||
"VOL_TNRT",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL",
|
||||
"PRDY_SMNS_HOUR_ACML_VOL_RATE",
|
||||
"HOUR_CLS_CODE",
|
||||
"MRKT_TRTM_CLS_CODE",
|
||||
"VI_STND_PRC",
|
||||
]
|
||||
|
||||
return msg, columns
|
||||
@@ -0,0 +1,83 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from exp_closing_price import exp_closing_price
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 기본시세 > 국내주식 장마감 예상체결가[국내주식-120]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'stck_shrn_iscd': '주식 단축 종목코드',
|
||||
'hts_kor_isnm': 'HTS 한글 종목명',
|
||||
'stck_prpr': '주식 현재가',
|
||||
'prdy_vrss': '전일 대비',
|
||||
'prdy_vrss_sign': '전일 대비 부호',
|
||||
'prdy_ctrt': '전일 대비율',
|
||||
'sdpr_vrss_prpr': '기준가 대비 현재가',
|
||||
'sdpr_vrss_prpr_rate': '기준가 대비 현재가 비율',
|
||||
'cntg_vol': '체결 거래량'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = ['전일 대비율', '기준가 대비 현재가 비율']
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내주식 장마감 예상체결가 조회 테스트 함수
|
||||
|
||||
이 함수는 국내주식 장마감 예상체결가 API를 호출하여 결과를 출력합니다.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
# case1 조회
|
||||
logging.info("=== case1 조회 ===")
|
||||
try:
|
||||
result = exp_closing_price(
|
||||
fid_cond_mrkt_div_code="J",
|
||||
fid_input_iscd="0001",
|
||||
fid_rank_sort_cls_code="0",
|
||||
fid_cond_scr_div_code="11173",
|
||||
fid_blng_cls_code="0"
|
||||
)
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
logging.info("사용 가능한 컬럼: %s", result.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 기본시세 > 국내주식 장마감 예상체결가[국내주식-120]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/exp-closing-price"
|
||||
|
||||
def exp_closing_price(
|
||||
fid_cond_mrkt_div_code: str, # [필수] 조건시장분류코드 (ex. J:주식)
|
||||
fid_input_iscd: str, # [필수] 입력종목코드 (ex. 0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200, 4001: KRX100)
|
||||
fid_rank_sort_cls_code: str, # [필수] 순위정렬구분코드 (ex. 0:전체, 1:상한가마감예상, 2:하한가마감예상, 3:직전대비상승률상위, 4:직전대비하락률상위)
|
||||
fid_cond_scr_div_code: str, # [필수] 조건화면분류코드 (ex. 11173)
|
||||
fid_blng_cls_code: str # [필수] 소속구분코드 (ex. 0:전체, 1:종가범위연장)
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
국내주식 장마감 예상체결가 API입니다.
|
||||
한국투자 HTS(eFriend Plus) > [0183] 장마감 예상체결가 화면의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.
|
||||
|
||||
Args:
|
||||
fid_cond_mrkt_div_code (str): [필수] 조건시장분류코드 (ex. J:주식)
|
||||
fid_input_iscd (str): [필수] 입력종목코드 (ex. 0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200, 4001: KRX100)
|
||||
fid_rank_sort_cls_code (str): [필수] 순위정렬구분코드 (ex. 0:전체, 1:상한가마감예상, 2:하한가마감예상, 3:직전대비상승률상위, 4:직전대비하락률상위)
|
||||
fid_cond_scr_div_code (str): [필수] 조건화면분류코드 (ex. 11173)
|
||||
fid_blng_cls_code (str): [필수] 소속구분코드 (ex. 0:전체, 1:종가범위연장)
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: 국내주식 장마감 예상체결가 데이터
|
||||
|
||||
Example:
|
||||
>>> df = exp_closing_price("J", "0001", "0", "11173", "0")
|
||||
>>> print(df)
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if fid_cond_mrkt_div_code == "":
|
||||
raise ValueError("fid_cond_mrkt_div_code is required (e.g. 'J')")
|
||||
|
||||
if fid_input_iscd == "":
|
||||
raise ValueError("fid_input_iscd is required (e.g. '0000', '0001', '1001', '2001', '4001')")
|
||||
|
||||
if fid_rank_sort_cls_code == "":
|
||||
raise ValueError("fid_rank_sort_cls_code is required (e.g. '0', '1', '2', '3', '4')")
|
||||
|
||||
if fid_cond_scr_div_code == "":
|
||||
raise ValueError("fid_cond_scr_div_code is required (e.g. '11173')")
|
||||
|
||||
if fid_blng_cls_code == "":
|
||||
raise ValueError("fid_blng_cls_code is required (e.g. '0', '1')")
|
||||
|
||||
tr_id = "FHKST117300C0"
|
||||
|
||||
params = {
|
||||
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code,
|
||||
"FID_INPUT_ISCD": fid_input_iscd,
|
||||
"FID_RANK_SORT_CLS_CODE": fid_rank_sort_cls_code,
|
||||
"FID_COND_SCR_DIV_CODE": fid_cond_scr_div_code,
|
||||
"FID_BLNG_CLS_CODE": fid_blng_cls_code
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, "", params)
|
||||
|
||||
if res.isOK():
|
||||
return pd.DataFrame(res.getBody().output)
|
||||
else:
|
||||
res.printError(url=API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,97 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from exp_index_trend import exp_index_trend
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 업종/기타 > 국내주식 예상체결지수 추이[국내주식-121]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'stck_cntg_hour': '주식 단축 종목코드',
|
||||
'bstp_nmix_prpr': 'HTS 한글 종목명',
|
||||
'prdy_vrss_sign': '주식 현재가',
|
||||
'bstp_nmix_prdy_vrss': '전일 대비',
|
||||
'prdy_ctrt': '전일 대비 부호',
|
||||
'acml_vol': '전일 대비율',
|
||||
'acml_tr_pbmn': '기준가 대비 현재가'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 업종/기타
|
||||
국내주식 예상체결지수 추이[국내주식-121]
|
||||
|
||||
국내주식 예상체결지수 추이 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_mkop_cls_code (str): 장운영 구분 코드 (1: 장시작전, 2: 장마감)
|
||||
- fid_input_hour_1 (str): 입력 시간1 (10(10초), 30(30초), 60(1분), 600(10분))
|
||||
- fid_input_iscd (str): 입력 종목코드 (0000:전체, 0001:코스피, 1001:코스닥, 2001:코스피200, 4001: KRX100)
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (시장구분코드 (주식 U))
|
||||
Returns:
|
||||
- DataFrame: 국내주식 예상체결지수 추이 결과
|
||||
|
||||
Example:
|
||||
>>> df = exp_index_trend(fid_mkop_cls_code="1", fid_input_hour_1="", fid_input_iscd="0001", fid_cond_mrkt_div_code="U")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
# API 호출
|
||||
result = exp_index_trend(
|
||||
fid_mkop_cls_code="1", # 장운영 구분 코드
|
||||
fid_input_hour_1="", # 입력 시간1
|
||||
fid_input_iscd="0001", # 입력 종목코드
|
||||
fid_cond_mrkt_div_code="U", # 조건 시장 분류 코드
|
||||
)
|
||||
|
||||
if result is None or result.empty:
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# 컬럼명 출력
|
||||
logger.info("사용 가능한 컬럼 목록:")
|
||||
logger.info(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
logger.info("=== 국내주식 예상체결지수 추이 결과 ===")
|
||||
logger.info("조회된 데이터 건수: %d", len(result))
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,124 @@
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 업종/기타 > 국내주식 예상체결지수 추이[국내주식-121]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/exp-index-trend"
|
||||
|
||||
|
||||
|
||||
def exp_index_trend(
|
||||
fid_mkop_cls_code: str, # 장운영 구분 코드
|
||||
fid_input_hour_1: str, # 입력 시간1
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
tr_cont: str = "", # 연속 거래 여부
|
||||
dataframe: Optional[pd.DataFrame] = None, # 누적 데이터프레임
|
||||
depth: int = 0, # 현재 재귀 깊이
|
||||
max_depth: int = 10 # 최대 재귀 깊이
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 업종/기타
|
||||
국내주식 예상체결지수 추이[국내주식-121]
|
||||
국내주식 예상체결지수 추이 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_mkop_cls_code (str): 1: 장시작전, 2: 장마감
|
||||
fid_input_hour_1 (str): 10(10초), 30(30초), 60(1분), 600(10분)
|
||||
fid_input_iscd (str): 0000:전체, 0001:코스피, 1001:코스닥, 2001:코스피200, 4001: KRX100
|
||||
fid_cond_mrkt_div_code (str): 시장구분코드 (주식 U)
|
||||
tr_cont (str): 연속 거래 여부
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: 국내주식 예상체결지수 추이 데이터
|
||||
|
||||
Example:
|
||||
>>> df = exp_index_trend('1', '10', '0000', 'U')
|
||||
>>> print(df)
|
||||
"""
|
||||
# 필수 파라미터 검증
|
||||
if not fid_mkop_cls_code:
|
||||
logger.error("fid_mkop_cls_code is required. (e.g. '1')")
|
||||
raise ValueError("fid_mkop_cls_code is required. (e.g. '1')")
|
||||
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '0000')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '0000')")
|
||||
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'U')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'U')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe if dataframe is not None else pd.DataFrame()
|
||||
|
||||
|
||||
tr_id = "FHPST01840000"
|
||||
|
||||
params = {
|
||||
"FID_MKOP_CLS_CODE": fid_mkop_cls_code,
|
||||
"FID_INPUT_HOUR_1": fid_input_hour_1,
|
||||
"FID_INPUT_ISCD": fid_input_iscd,
|
||||
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code,
|
||||
}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
output_data = res.getBody().output
|
||||
if not isinstance(output_data, list):
|
||||
output_data = [output_data]
|
||||
current_data = pd.DataFrame(output_data)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont == "M":
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return exp_index_trend(
|
||||
fid_mkop_cls_code,
|
||||
fid_input_hour_1,
|
||||
fid_input_iscd,
|
||||
fid_cond_mrkt_div_code,
|
||||
"N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,103 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from exp_price_trend import exp_price_trend
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 국내주식 예상체결가 추이[국내주식-118]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'rprs_mrkt_kor_name': '대표 시장 한글 명',
|
||||
'antc_cnpr': '예상 체결가',
|
||||
'antc_cntg_vrss_sign': '예상 체결 대비 부호',
|
||||
'antc_cntg_vrss': '예상 체결 대비',
|
||||
'antc_cntg_prdy_ctrt': '예상 체결 전일 대비율',
|
||||
'antc_vol': '예상 거래량',
|
||||
'antc_tr_pbmn': '예상 거래대금',
|
||||
'stck_bsop_date': '주식 영업 일자',
|
||||
'stck_cntg_hour': '주식 체결 시간',
|
||||
'stck_prpr': '주식 현재가',
|
||||
'prdy_vrss_sign': '전일 대비 부호',
|
||||
'prdy_vrss': '전일 대비',
|
||||
'prdy_ctrt': '전일 대비율',
|
||||
'acml_vol': '누적 거래량'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내주식 예상체결가 추이 조회 테스트 함수
|
||||
|
||||
이 함수는 국내주식 예상체결가 추이 API를 호출하여 결과를 출력합니다.
|
||||
테스트 데이터로 삼성전자(005930)를 사용합니다.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
# case1 테스트
|
||||
logging.info("=== Case1: 삼성전자 예상체결가 추이 조회 ===")
|
||||
try:
|
||||
output1, output2 = exp_price_trend(
|
||||
fid_cond_mrkt_div_code="J",
|
||||
fid_input_iscd="005930",
|
||||
fid_mkop_cls_code="0"
|
||||
)
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
# output1 처리
|
||||
logging.info("=== Output1 결과 ===")
|
||||
logging.info("사용 가능한 컬럼: %s", output1.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환
|
||||
output1 = output1.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in output1.columns:
|
||||
output1[col] = pd.to_numeric(output1[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(output1)
|
||||
|
||||
# output2 처리
|
||||
logging.info("=== Output2 결과 ===")
|
||||
logging.info("사용 가능한 컬럼: %s", output2.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환
|
||||
output2 = output2.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in output2.columns:
|
||||
output2[col] = pd.to_numeric(output2[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(output2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
from typing import Tuple
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 국내주식 예상체결가 추이[국내주식-118]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/exp-price-trend"
|
||||
|
||||
def exp_price_trend(
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드 (ex. J)
|
||||
fid_input_iscd: str, # 입력 종목코드 (ex. 123456)
|
||||
fid_mkop_cls_code: str # (ex. 0:전체, 4:체결량 0 제외)
|
||||
) -> Tuple[pd.DataFrame, pd.DataFrame]:
|
||||
"""
|
||||
국내주식 예상체결가 추이 API입니다.
|
||||
한국투자 HTS(eFriend Plus) > [0184] 예상체결지수 추이 화면의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.
|
||||
최대 30건 확인 가능하며, 다음 조회가 불가합니다.
|
||||
|
||||
Args:
|
||||
fid_cond_mrkt_div_code (str): [필수] 조건 시장 분류 코드 (ex. J)
|
||||
fid_input_iscd (str): [필수] 입력 종목코드 (ex. 123456)
|
||||
fid_mkop_cls_code (str): [필수] (ex. 0:전체, 4:체결량 0 제외)
|
||||
|
||||
Returns:
|
||||
Tuple[pd.DataFrame, pd.DataFrame]: (output1, output2) 데이터
|
||||
|
||||
Example:
|
||||
>>> output1, output2 = exp_price_trend("J", "005930", "0")
|
||||
>>> print(output1)
|
||||
>>> print(output2)
|
||||
"""
|
||||
|
||||
if not fid_cond_mrkt_div_code:
|
||||
raise ValueError("fid_cond_mrkt_div_code is required (e.g. 'J')")
|
||||
|
||||
if not fid_input_iscd:
|
||||
raise ValueError("fid_input_iscd is required (e.g. '123456')")
|
||||
|
||||
if not fid_mkop_cls_code:
|
||||
raise ValueError("fid_mkop_cls_code is required (e.g. '0')")
|
||||
|
||||
tr_id = "FHPST01810000"
|
||||
|
||||
params = {
|
||||
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code,
|
||||
"FID_INPUT_ISCD": fid_input_iscd,
|
||||
"FID_MKOP_CLS_CODE": fid_mkop_cls_code,
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, "", params)
|
||||
|
||||
if res.isOK():
|
||||
output1_data = pd.DataFrame([res.getBody().output1])
|
||||
output2_data = pd.DataFrame(res.getBody().output2)
|
||||
|
||||
logging.info("Data fetch complete.")
|
||||
return output1_data, output2_data
|
||||
else:
|
||||
res.printError(url=API_URL)
|
||||
return pd.DataFrame(), pd.DataFrame()
|
||||
@@ -0,0 +1,136 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from exp_total_index import exp_total_index
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 업종/기타 > 국내주식 예상체결 전체지수[국내주식-122]
|
||||
##############################################################################################
|
||||
|
||||
# 통합 컬럼 매핑 (모든 output에서 공통 사용)
|
||||
COLUMN_MAPPING = {
|
||||
'bstp_nmix_prpr': '업종 지수 현재가',
|
||||
'bstp_nmix_prdy_vrss': '업종 지수 전일 대비',
|
||||
'prdy_vrss_sign': '전일 대비 부호',
|
||||
'prdy_ctrt': '전일 대비율',
|
||||
'acml_vol': '누적 거래량',
|
||||
'ascn_issu_cnt': '상승 종목 수',
|
||||
'down_issu_cnt': '하락 종목 수',
|
||||
'stnr_issu_cnt': '보합 종목 수',
|
||||
'bstp_cls_code': '업종 구분 코드',
|
||||
'hts_kor_isnm': 'HTS 한글 종목명',
|
||||
'bstp_nmix_prpr': '업종 지수 현재가',
|
||||
'bstp_nmix_prdy_vrss': '업종 지수 전일 대비',
|
||||
'prdy_vrss_sign': '전일 대비 부호',
|
||||
'bstp_nmix_prdy_ctrt': '업종 지수 전일 대비율',
|
||||
'acml_vol': '누적 거래량',
|
||||
'nmix_sdpr': '지수 기준가',
|
||||
'ascn_issu_cnt': '상승 종목 수',
|
||||
'stnr_issu_cnt': '보합 종목 수',
|
||||
'down_issu_cnt': '하락 종목 수'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 업종/기타
|
||||
국내주식 예상체결 전체지수[국내주식-122]
|
||||
|
||||
국내주식 예상체결 전체지수 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_mrkt_cls_code (str): 시장 구분 코드 (0:전체 K:거래소 Q:코스닥)
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (시장구분코드 (업종 U))
|
||||
- fid_cond_scr_div_code (str): 조건 화면 분류 코드 (Unique key(11175))
|
||||
- fid_input_iscd (str): 입력 종목코드 (0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200, 4001: KRX100)
|
||||
- fid_mkop_cls_code (str): 장운영 구분 코드 (1:장시작전, 2:장마감)
|
||||
|
||||
Returns:
|
||||
- Tuple[DataFrame, ...]: 국내주식 예상체결 전체지수 결과
|
||||
|
||||
Example:
|
||||
>>> df1, df2 = exp_total_index(fid_mrkt_cls_code="0", fid_cond_mrkt_div_code="U", fid_cond_scr_div_code="11175", fid_input_iscd="0000", fid_mkop_cls_code="1")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
|
||||
# API 호출
|
||||
result1, result2 = exp_total_index(
|
||||
fid_mrkt_cls_code="0", # 시장 구분 코드
|
||||
fid_cond_mrkt_div_code="U", # 조건 시장 분류 코드
|
||||
fid_cond_scr_div_code="11175", # 조건 화면 분류 코드
|
||||
fid_input_iscd="0000", # 입력 종목코드
|
||||
fid_mkop_cls_code="1", # 장운영 구분 코드
|
||||
)
|
||||
|
||||
# 결과 확인
|
||||
results = [result1, result2]
|
||||
if all(result is None or result.empty for result in results):
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
|
||||
# output1 결과 처리
|
||||
logger.info("=== output1 조회 ===")
|
||||
if not result1.empty:
|
||||
logger.info("사용 가능한 컬럼: %s", result1.columns.tolist())
|
||||
|
||||
# 통합 컬럼명 한글 변환 (필요한 컬럼만 자동 매핑됨)
|
||||
result1 = result1.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result1.columns:
|
||||
result1[col] = pd.to_numeric(result1[col], errors='coerce').round(2)
|
||||
|
||||
logger.info("output1 결과:")
|
||||
print(result1)
|
||||
else:
|
||||
logger.info("output1 데이터가 없습니다.")
|
||||
|
||||
# output2 결과 처리
|
||||
logger.info("=== output2 조회 ===")
|
||||
if not result2.empty:
|
||||
logger.info("사용 가능한 컬럼: %s", result2.columns.tolist())
|
||||
|
||||
# 통합 컬럼명 한글 변환 (필요한 컬럼만 자동 매핑됨)
|
||||
result2 = result2.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result2.columns:
|
||||
result2[col] = pd.to_numeric(result2[col], errors='coerce').round(2)
|
||||
|
||||
logger.info("output2 결과:")
|
||||
print(result2)
|
||||
else:
|
||||
logger.info("output2 데이터가 없습니다.")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,158 @@
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional, Tuple
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 업종/기타 > 국내주식 예상체결 전체지수[국내주식-122]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/exp-total-index"
|
||||
|
||||
|
||||
def exp_total_index(
|
||||
fid_mrkt_cls_code: str, # 시장 구분 코드
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
fid_cond_scr_div_code: str, # 조건 화면 분류 코드
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
fid_mkop_cls_code: str, # 장운영 구분 코드
|
||||
dataframe1: Optional[pd.DataFrame] = None, # 누적 데이터프레임 (output1)
|
||||
dataframe2: Optional[pd.DataFrame] = None, # 누적 데이터프레임 (output2)
|
||||
tr_cont: str = "",
|
||||
depth: int = 0,
|
||||
max_depth: int = 10
|
||||
) -> Tuple[pd.DataFrame, pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 업종/기타
|
||||
국내주식 예상체결 전체지수[국내주식-122]
|
||||
국내주식 예상체결 전체지수 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_mrkt_cls_code (str): 0:전체 K:거래소 Q:코스닥
|
||||
fid_cond_mrkt_div_code (str): 시장구분코드 (업종 U)
|
||||
fid_cond_scr_div_code (str): Unique key(11175)
|
||||
fid_input_iscd (str): 0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200, 4001: KRX100
|
||||
fid_mkop_cls_code (str): 1:장시작전, 2:장마감
|
||||
dataframe1 (Optional[pd.DataFrame]): 누적 데이터프레임 (output1)
|
||||
dataframe2 (Optional[pd.DataFrame]): 누적 데이터프레임 (output2)
|
||||
tr_cont (str): 연속 거래 여부
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Tuple[pd.DataFrame, pd.DataFrame]: 국내주식 예상체결 전체지수 데이터
|
||||
|
||||
Example:
|
||||
>>> df1, df2 = exp_total_index(
|
||||
... fid_mrkt_cls_code="K",
|
||||
... fid_cond_mrkt_div_code="U",
|
||||
... fid_cond_scr_div_code="11175",
|
||||
... fid_input_iscd="1001",
|
||||
... fid_mkop_cls_code="1"
|
||||
... )
|
||||
>>> print(df1)
|
||||
>>> print(df2)
|
||||
"""
|
||||
# 로깅 설정
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not fid_mrkt_cls_code:
|
||||
logger.error("fid_mrkt_cls_code is required. (e.g. 'K')")
|
||||
raise ValueError("fid_mrkt_cls_code is required. (e.g. 'K')")
|
||||
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'U')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'U')")
|
||||
|
||||
if not fid_cond_scr_div_code:
|
||||
logger.error("fid_cond_scr_div_code is required. (e.g. '11175')")
|
||||
raise ValueError("fid_cond_scr_div_code is required. (e.g. '11175')")
|
||||
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '1001')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '1001')")
|
||||
|
||||
if not fid_mkop_cls_code:
|
||||
logger.error("fid_mkop_cls_code is required. (e.g. '1')")
|
||||
raise ValueError("fid_mkop_cls_code is required. (e.g. '1')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe1 if dataframe1 is not None else pd.DataFrame(), dataframe2 if dataframe2 is not None else pd.DataFrame()
|
||||
|
||||
|
||||
tr_id = "FHKUP11750000"
|
||||
|
||||
params = {
|
||||
"fid_mrkt_cls_code": fid_mrkt_cls_code,
|
||||
"fid_cond_mrkt_div_code": fid_cond_mrkt_div_code,
|
||||
"fid_cond_scr_div_code": fid_cond_scr_div_code,
|
||||
"fid_input_iscd": fid_input_iscd,
|
||||
"fid_mkop_cls_code": fid_mkop_cls_code,
|
||||
}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
# output1 처리
|
||||
if hasattr(res.getBody(), 'output1'):
|
||||
output_data = res.getBody().output1
|
||||
if output_data:
|
||||
current_data1 = pd.DataFrame(output_data if isinstance(output_data, list) else [output_data])
|
||||
dataframe1 = pd.concat([dataframe1, current_data1],
|
||||
ignore_index=True) if dataframe1 is not None else current_data1
|
||||
else:
|
||||
dataframe1 = pd.DataFrame() if dataframe1 is None else dataframe1
|
||||
else:
|
||||
dataframe1 = pd.DataFrame() if dataframe1 is None else dataframe1
|
||||
|
||||
# output2 처리
|
||||
if hasattr(res.getBody(), 'output2'):
|
||||
output_data = res.getBody().output2
|
||||
if output_data:
|
||||
current_data2 = pd.DataFrame(output_data if isinstance(output_data, list) else [output_data])
|
||||
dataframe2 = pd.concat([dataframe2, current_data2],
|
||||
ignore_index=True) if dataframe2 is not None else current_data2
|
||||
else:
|
||||
dataframe2 = pd.DataFrame() if dataframe2 is None else dataframe2
|
||||
else:
|
||||
dataframe2 = pd.DataFrame() if dataframe2 is None else dataframe2
|
||||
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont in ["M", "F"]:
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return exp_total_index(
|
||||
fid_mrkt_cls_code,
|
||||
fid_cond_mrkt_div_code,
|
||||
fid_cond_scr_div_code,
|
||||
fid_input_iscd,
|
||||
fid_mkop_cls_code,
|
||||
"N", dataframe1, dataframe2, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe1, dataframe2
|
||||
else:
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame(), pd.DataFrame()
|
||||
@@ -0,0 +1,117 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from exp_trans_updown import exp_trans_updown
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > 국내주식 예상체결 상승_하락상위[v1_국내주식-103]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'stck_shrn_iscd': '주식 단축 종목코드',
|
||||
'hts_kor_isnm': 'HTS 한글 종목명',
|
||||
'stck_prpr': '주식 현재가',
|
||||
'prdy_vrss': '전일 대비',
|
||||
'prdy_vrss_sign': '전일 대비 부호',
|
||||
'prdy_ctrt': '전일 대비율',
|
||||
'stck_sdpr': '주식 기준가',
|
||||
'seln_rsqn': '매도 잔량',
|
||||
'askp': '매도호가',
|
||||
'bidp': '매수호가',
|
||||
'shnu_rsqn': '매수2 잔량',
|
||||
'cntg_vol': '체결 거래량',
|
||||
'antc_tr_pbmn': '체결 거래대금',
|
||||
'total_askp_rsqn': '총 매도호가 잔량',
|
||||
'total_bidp_rsqn': '총 매수호가 잔량'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
국내주식 예상체결 상승_하락상위[v1_국내주식-103]
|
||||
|
||||
국내주식 예상체결 상승_하락상위 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_rank_sort_cls_code (str): 순위 정렬 구분 코드 (0:상승률1:상승폭2:보합3:하락율4:하락폭5:체결량6:거래대금)
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (시장구분코드 (주식 J))
|
||||
- fid_cond_scr_div_code (str): 조건 화면 분류 코드 (Unique key(20182))
|
||||
- fid_input_iscd (str): 입력 종목코드 (0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200, 4001: KRX100)
|
||||
- fid_div_cls_code (str): 분류 구분 코드 (0:전체 1:보통주 2:우선주)
|
||||
- fid_aply_rang_prc_1 (str): 적용 범위 가격1 (입력값 없을때 전체 (가격 ~))
|
||||
- fid_vol_cnt (str): 거래량 수 (입력값 없을때 전체 (거래량 ~))
|
||||
- fid_pbmn (str): 거래대금 (입력값 없을때 전체 (거래대금 ~) 천원단위)
|
||||
- fid_blng_cls_code (str): 소속 구분 코드 (0: 전체)
|
||||
- fid_mkop_cls_code (str): 장운영 구분 코드 (0:장전예상1:장마감예상)
|
||||
Returns:
|
||||
- DataFrame: 국내주식 예상체결 상승_하락상위 결과
|
||||
|
||||
Example:
|
||||
>>> df = exp_trans_updown(fid_rank_sort_cls_code="0", fid_cond_mrkt_div_code="J", fid_cond_scr_div_code="20182", fid_input_iscd="0000", fid_div_cls_code="0", fid_aply_rang_prc_1="", fid_vol_cnt="", fid_pbmn="", fid_blng_cls_code="0", fid_mkop_cls_code="0")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
# API 호출
|
||||
result = exp_trans_updown(
|
||||
fid_rank_sort_cls_code="0", # 순위 정렬 구분 코드
|
||||
fid_cond_mrkt_div_code="J", # 조건 시장 분류 코드
|
||||
fid_cond_scr_div_code="20182", # 조건 화면 분류 코드
|
||||
fid_input_iscd="0000", # 입력 종목코드
|
||||
fid_div_cls_code="0", # 분류 구분 코드
|
||||
fid_aply_rang_prc_1="", # 적용 범위 가격1
|
||||
fid_vol_cnt="", # 거래량 수
|
||||
fid_pbmn="", # 거래대금
|
||||
fid_blng_cls_code="0", # 소속 구분 코드
|
||||
fid_mkop_cls_code="0", # 장운영 구분 코드
|
||||
)
|
||||
|
||||
if result is None or result.empty:
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# 컬럼명 출력
|
||||
logger.info("사용 가능한 컬럼 목록:")
|
||||
logger.info(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
logger.info("=== 국내주식 예상체결 상승_하락상위 결과 ===")
|
||||
logger.info("조회된 데이터 건수: %d", len(result))
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,177 @@
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > 국내주식 예상체결 상승_하락상위[v1_국내주식-103]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/ranking/exp-trans-updown"
|
||||
|
||||
def exp_trans_updown(
|
||||
fid_rank_sort_cls_code: str, # 순위 정렬 구분 코드
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
fid_cond_scr_div_code: str, # 조건 화면 분류 코드
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
fid_div_cls_code: str, # 분류 구분 코드
|
||||
fid_aply_rang_prc_1: str, # 적용 범위 가격1
|
||||
fid_vol_cnt: str, # 거래량 수
|
||||
fid_pbmn: str, # 거래대금
|
||||
fid_blng_cls_code: str, # 소속 구분 코드
|
||||
fid_mkop_cls_code: str, # 장운영 구분 코드
|
||||
tr_cont: str = "",
|
||||
dataframe: Optional[pd.DataFrame] = None,
|
||||
depth: int = 0,
|
||||
max_depth: int = 10
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
국내주식 예상체결 상승_하락상위[v1_국내주식-103]
|
||||
국내주식 예상체결 상승_하락상위 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_rank_sort_cls_code (str): 0:상승률1:상승폭2:보합3:하락율4:하락폭5:체결량6:거래대금
|
||||
fid_cond_mrkt_div_code (str): 시장구분코드 (주식 J)
|
||||
fid_cond_scr_div_code (str): Unique key(20182)
|
||||
fid_input_iscd (str): 0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200, 4001: KRX100
|
||||
fid_div_cls_code (str): 0:전체 1:보통주 2:우선주
|
||||
fid_aply_rang_prc_1 (str): 입력값 없을때 전체 (가격 ~)
|
||||
fid_vol_cnt (str): 입력값 없을때 전체 (거래량 ~)
|
||||
fid_pbmn (str): 입력값 없을때 전체 (거래대금 ~) 천원단위
|
||||
fid_blng_cls_code (str): 0: 전체
|
||||
fid_mkop_cls_code (str): 0:장전예상1:장마감예상
|
||||
tr_cont (str): 연속 거래 여부
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: 국내주식 예상체결 상승_하락상위 데이터
|
||||
|
||||
Example:
|
||||
>>> df = exp_trans_updown(
|
||||
... fid_rank_sort_cls_code="0",
|
||||
... fid_cond_mrkt_div_code="J",
|
||||
... fid_cond_scr_div_code="20182",
|
||||
... fid_input_iscd="0000",
|
||||
... fid_div_cls_code="0",
|
||||
... fid_aply_rang_prc_1="",
|
||||
... fid_vol_cnt="",
|
||||
... fid_pbmn="",
|
||||
... fid_blng_cls_code="0",
|
||||
... fid_mkop_cls_code="0"
|
||||
... )
|
||||
>>> print(df)
|
||||
"""
|
||||
# 로깅 설정
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not fid_rank_sort_cls_code:
|
||||
logger.error("fid_rank_sort_cls_code is required. (e.g. '0')")
|
||||
raise ValueError("fid_rank_sort_cls_code is required. (e.g. '0')")
|
||||
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
|
||||
if not fid_cond_scr_div_code:
|
||||
logger.error("fid_cond_scr_div_code is required. (e.g. '20182')")
|
||||
raise ValueError("fid_cond_scr_div_code is required. (e.g. '20182')")
|
||||
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '0000')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '0000')")
|
||||
|
||||
if not fid_div_cls_code:
|
||||
logger.error("fid_div_cls_code is required. (e.g. '0')")
|
||||
raise ValueError("fid_div_cls_code is required. (e.g. '0')")
|
||||
|
||||
if not fid_blng_cls_code:
|
||||
logger.error("fid_blng_cls_code is required. (e.g. '0')")
|
||||
raise ValueError("fid_blng_cls_code is required. (e.g. '0')")
|
||||
|
||||
if not fid_mkop_cls_code:
|
||||
logger.error("fid_mkop_cls_code is required. (e.g. '0')")
|
||||
raise ValueError("fid_mkop_cls_code is required. (e.g. '0')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe if dataframe is not None else pd.DataFrame()
|
||||
|
||||
|
||||
tr_id = "FHPST01820000"
|
||||
|
||||
params = {
|
||||
"fid_rank_sort_cls_code": fid_rank_sort_cls_code,
|
||||
"fid_cond_mrkt_div_code": fid_cond_mrkt_div_code,
|
||||
"fid_cond_scr_div_code": fid_cond_scr_div_code,
|
||||
"fid_input_iscd": fid_input_iscd,
|
||||
"fid_div_cls_code": fid_div_cls_code,
|
||||
"fid_aply_rang_prc_1": fid_aply_rang_prc_1,
|
||||
"fid_vol_cnt": fid_vol_cnt,
|
||||
"fid_pbmn": fid_pbmn,
|
||||
"fid_blng_cls_code": fid_blng_cls_code,
|
||||
"fid_mkop_cls_code": fid_mkop_cls_code,
|
||||
}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
output_data = res.getBody().output
|
||||
if not isinstance(output_data, list):
|
||||
output_data = [output_data]
|
||||
current_data = pd.DataFrame(output_data)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont == "M":
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return exp_trans_updown(
|
||||
fid_rank_sort_cls_code,
|
||||
fid_cond_mrkt_div_code,
|
||||
fid_cond_scr_div_code,
|
||||
fid_input_iscd,
|
||||
fid_div_cls_code,
|
||||
fid_aply_rang_prc_1,
|
||||
fid_vol_cnt,
|
||||
fid_pbmn,
|
||||
fid_blng_cls_code,
|
||||
fid_mkop_cls_code,
|
||||
"N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,100 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from finance_balance_sheet import finance_balance_sheet
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 대차대조표 [v1_국내주식-078]
|
||||
##############################################################################################
|
||||
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'stac_yymm': '결산 년월',
|
||||
'cras': '유동자산',
|
||||
'fxas': '고정자산',
|
||||
'total_aset': '자산총계',
|
||||
'flow_lblt': '유동부채',
|
||||
'fix_lblt': '고정부채',
|
||||
'total_lblt': '부채총계',
|
||||
'cpfn': '자본금',
|
||||
'cfp_surp': '자본 잉여금',
|
||||
'prfi_surp': '이익 잉여금',
|
||||
'total_cptl': '자본총계'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 대차대조표[v1_국내주식-078]
|
||||
|
||||
국내주식 대차대조표 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_div_cls_code (str): 분류 구분 코드 (0: 년, 1: 분기)
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (J)
|
||||
- fid_input_iscd (str): 입력 종목코드 (000660 : 종목코드)
|
||||
Returns:
|
||||
- DataFrame: 국내주식 대차대조표 결과
|
||||
|
||||
Example:
|
||||
>>> df = finance_balance_sheet(fid_div_cls_code="0", fid_cond_mrkt_div_code="J", fid_input_iscd="000660")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
# API 호출
|
||||
result = finance_balance_sheet(
|
||||
fid_div_cls_code="0", # 분류 구분 코드
|
||||
fid_cond_mrkt_div_code="J", # 조건 시장 분류 코드
|
||||
fid_input_iscd="000660", # 입력 종목코드
|
||||
)
|
||||
|
||||
if result is None or result.empty:
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# 컬럼명 출력
|
||||
logger.info("사용 가능한 컬럼 목록:")
|
||||
logger.info(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
logger.info("=== 국내주식 대차대조표 결과 ===")
|
||||
logger.info("조회된 데이터 건수: %d", len(result))
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,122 @@
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 대차대조표 [v1_국내주식-078]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/finance/balance-sheet"
|
||||
|
||||
def finance_balance_sheet(
|
||||
fid_div_cls_code: str, # 분류 구분 코드
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
tr_cont: str = "", # 연속 거래 여부
|
||||
dataframe: Optional[pd.DataFrame] = None, # 누적 데이터프레임
|
||||
depth: int = 0, # 현재 재귀 깊이
|
||||
max_depth: int = 10 # 최대 재귀 깊이
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 대차대조표[v1_국내주식-078]
|
||||
국내주식 대차대조표 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_div_cls_code (str): 0: 년, 1: 분기
|
||||
fid_cond_mrkt_div_code (str): J
|
||||
fid_input_iscd (str): 000660 : 종목코드
|
||||
tr_cont (str): 연속 거래 여부
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: 국내주식 대차대조표 데이터
|
||||
|
||||
Example:
|
||||
>>> df = finance_balance_sheet("0", "J", "000660")
|
||||
>>> print(df)
|
||||
"""
|
||||
# 로깅 설정
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not fid_div_cls_code:
|
||||
logger.error("fid_div_cls_code is required. (e.g. '0')")
|
||||
raise ValueError("fid_div_cls_code is required. (e.g. '0')")
|
||||
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '000660')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '000660')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe if dataframe is not None else pd.DataFrame()
|
||||
|
||||
|
||||
tr_id = "FHKST66430100"
|
||||
|
||||
params = {
|
||||
"FID_DIV_CLS_CODE": fid_div_cls_code,
|
||||
"fid_cond_mrkt_div_code": fid_cond_mrkt_div_code,
|
||||
"fid_input_iscd": fid_input_iscd,
|
||||
}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
# 응답 데이터 처리
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
current_data = pd.DataFrame(res.getBody().output)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
# 데이터프레임 병합
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
# 연속 거래 여부 확인
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont == "M":
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return finance_balance_sheet(
|
||||
fid_div_cls_code,
|
||||
fid_cond_mrkt_div_code,
|
||||
fid_input_iscd,
|
||||
"N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
# API 에러 처리
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,98 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from finance_financial_ratio import finance_financial_ratio
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 재무비율 [v1_국내주식-080]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'stac_yymm': '결산 년월',
|
||||
'grs': '매출액 증가율',
|
||||
'bsop_prfi_inrt': '영업 이익 증가율',
|
||||
'ntin_inrt': '순이익 증가율',
|
||||
'roe_val': 'ROE 값',
|
||||
'eps': 'EPS',
|
||||
'sps': '주당매출액',
|
||||
'bps': 'BPS',
|
||||
'rsrv_rate': '유보 비율',
|
||||
'lblt_rate': '부채 비율'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 재무비율[v1_국내주식-080]
|
||||
|
||||
국내주식 재무비율 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_div_cls_code (str): 분류 구분 코드 (0: 년, 1: 분기)
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (J)
|
||||
- fid_input_iscd (str): 입력 종목코드 (000660 : 종목코드)
|
||||
Returns:
|
||||
- DataFrame: 국내주식 재무비율 결과
|
||||
|
||||
Example:
|
||||
>>> df = finance_financial_ratio(fid_div_cls_code="0", fid_cond_mrkt_div_code="J", fid_input_iscd="000660")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
# API 호출
|
||||
result = finance_financial_ratio(
|
||||
fid_div_cls_code="0", # 분류 구분 코드
|
||||
fid_cond_mrkt_div_code="J", # 조건 시장 분류 코드
|
||||
fid_input_iscd="000660", # 입력 종목코드
|
||||
)
|
||||
|
||||
if result is None or result.empty:
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# 컬럼명 출력
|
||||
logger.info("사용 가능한 컬럼 목록:")
|
||||
logger.info(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
logger.info("=== 국내주식 재무비율 결과 ===")
|
||||
logger.info("조회된 데이터 건수: %d", len(result))
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,122 @@
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 재무비율 [v1_국내주식-080]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/finance/financial-ratio"
|
||||
|
||||
def finance_financial_ratio(
|
||||
fid_div_cls_code: str, # 분류 구분 코드
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
tr_cont: str = "", # 연속 거래 여부
|
||||
dataframe: Optional[pd.DataFrame] = None, # 누적 데이터프레임
|
||||
depth: int = 0, # 현재 재귀 깊이
|
||||
max_depth: int = 10 # 최대 재귀 깊이
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 재무비율[v1_국내주식-080]
|
||||
국내주식 재무비율 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_div_cls_code (str): 0: 년, 1: 분기
|
||||
fid_cond_mrkt_div_code (str): J
|
||||
fid_input_iscd (str): 000660 : 종목코드
|
||||
tr_cont (str): 연속 거래 여부
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: 국내주식 재무비율 데이터
|
||||
|
||||
Example:
|
||||
>>> df = finance_financial_ratio("0", "J", "000660")
|
||||
>>> print(df)
|
||||
"""
|
||||
# 로깅 설정
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not fid_div_cls_code:
|
||||
logger.error("fid_div_cls_code is required. (e.g. '0')")
|
||||
raise ValueError("fid_div_cls_code is required. (e.g. '0')")
|
||||
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '000660')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '000660')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe if dataframe is not None else pd.DataFrame()
|
||||
|
||||
|
||||
tr_id = "FHKST66430300"
|
||||
|
||||
params = {
|
||||
"FID_DIV_CLS_CODE": fid_div_cls_code,
|
||||
"fid_cond_mrkt_div_code": fid_cond_mrkt_div_code,
|
||||
"fid_input_iscd": fid_input_iscd,
|
||||
}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
output_data = res.getBody().output
|
||||
if not isinstance(output_data, list):
|
||||
output_data = [output_data]
|
||||
current_data = pd.DataFrame(output_data)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont == "M":
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return finance_financial_ratio(
|
||||
fid_div_cls_code,
|
||||
fid_cond_mrkt_div_code,
|
||||
fid_input_iscd,
|
||||
"N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,93 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from finance_growth_ratio import finance_growth_ratio
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 성장성비율 [v1_국내주식-085]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'stac_yymm': '결산 년월',
|
||||
'grs': '매출액 증가율',
|
||||
'bsop_prfi_inrt': '영업 이익 증가율',
|
||||
'equt_inrt': '자기자본 증가율',
|
||||
'totl_aset_inrt': '총자산 증가율'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 성장성비율[v1_국내주식-085]
|
||||
|
||||
국내주식 성장성비율 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_input_iscd (str): 입력 종목코드 (ex : 000660)
|
||||
- fid_div_cls_code (str): 분류 구분 코드 (0: 년, 1: 분기)
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (시장구분코드 (주식 J))
|
||||
Returns:
|
||||
- DataFrame: 국내주식 성장성비율 결과
|
||||
|
||||
Example:
|
||||
>>> df = finance_growth_ratio(fid_input_iscd="000660", fid_div_cls_code="0", fid_cond_mrkt_div_code="J")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
# API 호출
|
||||
result = finance_growth_ratio(
|
||||
fid_input_iscd="000660", # 입력 종목코드
|
||||
fid_div_cls_code="0", # 분류 구분 코드
|
||||
fid_cond_mrkt_div_code="J", # 조건 시장 분류 코드
|
||||
)
|
||||
|
||||
if result is None or result.empty:
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# 컬럼명 출력
|
||||
logger.info("사용 가능한 컬럼 목록:")
|
||||
logger.info(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
logger.info("=== 국내주식 성장성비율 결과 ===")
|
||||
logger.info("조회된 데이터 건수: %d", len(result))
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,122 @@
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 성장성비율 [v1_국내주식-085]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/finance/growth-ratio"
|
||||
|
||||
def finance_growth_ratio(
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
fid_div_cls_code: str, # 분류 구분 코드
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
tr_cont: str = "", # 연속 거래 여부
|
||||
dataframe: Optional[pd.DataFrame] = None, # 누적 데이터프레임
|
||||
depth: int = 0, # 현재 재귀 깊이
|
||||
max_depth: int = 10 # 최대 재귀 깊이
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 성장성비율[v1_국내주식-085]
|
||||
국내주식 성장성비율 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_input_iscd (str): 입력 종목코드 (예: '000660')
|
||||
fid_div_cls_code (str): 분류 구분 코드 (0: 년, 1: 분기)
|
||||
fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (예: 'J')
|
||||
tr_cont (str): 연속 거래 여부 (기본값: "")
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: 국내주식 성장성비율 데이터
|
||||
|
||||
Example:
|
||||
>>> df = finance_growth_ratio('005930', '1', 'J')
|
||||
>>> print(df)
|
||||
"""
|
||||
# 로깅 설정
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '000660')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '000660')")
|
||||
|
||||
if not fid_div_cls_code:
|
||||
logger.error("fid_div_cls_code is required. (e.g. '0' or '1')")
|
||||
raise ValueError("fid_div_cls_code is required. (e.g. '0' or '1')")
|
||||
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe if dataframe is not None else pd.DataFrame()
|
||||
|
||||
# API URL 및 거래 ID 설정
|
||||
tr_id = "FHKST66430800"
|
||||
|
||||
# 요청 파라미터 설정
|
||||
params = {
|
||||
"fid_input_iscd": fid_input_iscd,
|
||||
"fid_div_cls_code": fid_div_cls_code,
|
||||
"fid_cond_mrkt_div_code": fid_cond_mrkt_div_code,
|
||||
}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
# API 응답 처리
|
||||
if res.isOK():
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
current_data = pd.DataFrame(res.getBody().output)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
# 데이터프레임 병합
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
# 연속 거래 여부 확인
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont == "M":
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return finance_growth_ratio(
|
||||
fid_input_iscd,
|
||||
fid_div_cls_code,
|
||||
fid_cond_mrkt_div_code,
|
||||
"N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,103 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from finance_income_statement import finance_income_statement
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 손익계산서 [v1_국내주식-079]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'stac_yymm': '결산 년월',
|
||||
'sale_account': '매출액',
|
||||
'sale_cost': '매출 원가',
|
||||
'sale_totl_prfi': '매출 총 이익',
|
||||
'depr_cost': '감가상각비',
|
||||
'sell_mang': '판매 및 관리비',
|
||||
'bsop_prti': '영업 이익',
|
||||
'bsop_non_ernn': '영업 외 수익',
|
||||
'bsop_non_expn': '영업 외 비용',
|
||||
'op_prfi': '경상 이익',
|
||||
'spec_prfi': '특별 이익',
|
||||
'spec_loss': '특별 손실',
|
||||
'thtr_ntin': '당기순이익'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 손익계산서[v1_국내주식-079]
|
||||
|
||||
국내주식 손익계산서 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_div_cls_code (str): 분류 구분 코드 (0: 년, 1: 분기 ※ 분기데이터는 연단위 누적합산)
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (J)
|
||||
- fid_input_iscd (str): 입력 종목코드 (000660 : 종목코드)
|
||||
Returns:
|
||||
- DataFrame: 국내주식 손익계산서 결과
|
||||
|
||||
Example:
|
||||
>>> df = finance_income_statement(fid_div_cls_code="0", fid_cond_mrkt_div_code="J", fid_input_iscd="000660")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
# API 호출
|
||||
result = finance_income_statement(
|
||||
fid_div_cls_code="0", # 분류 구분 코드
|
||||
fid_cond_mrkt_div_code="J", # 조건 시장 분류 코드
|
||||
fid_input_iscd="000660", # 입력 종목코드
|
||||
)
|
||||
|
||||
if result is None or result.empty:
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# 컬럼명 출력
|
||||
logger.info("사용 가능한 컬럼 목록:")
|
||||
logger.info(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
logger.info("=== 국내주식 손익계산서 결과 ===")
|
||||
logger.info("조회된 데이터 건수: %d", len(result))
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,119 @@
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 손익계산서 [v1_국내주식-079]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/finance/income-statement"
|
||||
|
||||
def finance_income_statement(
|
||||
fid_div_cls_code: str, # 분류 구분 코드
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
tr_cont: str = "", # 연속 거래 여부
|
||||
dataframe: Optional[pd.DataFrame] = None, # 누적 데이터프레임
|
||||
depth: int = 0, # 현재 재귀 깊이
|
||||
max_depth: int = 10 # 최대 재귀 깊이
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
국내주식 손익계산서 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_div_cls_code (str): 분류 구분 코드 (0: 년, 1: 분기)
|
||||
fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (예: 'J')
|
||||
fid_input_iscd (str): 입력 종목코드 (예: '000660')
|
||||
tr_cont (str): 연속 거래 여부 (기본값: "")
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: 국내주식 손익계산서 데이터
|
||||
|
||||
Example:
|
||||
>>> df = finance_income_statement('1', 'J', '005930')
|
||||
>>> print(df)
|
||||
"""
|
||||
# 필수 파라미터 검증
|
||||
if not fid_div_cls_code:
|
||||
logger.error("fid_div_cls_code is required. (e.g. '0' or '1')")
|
||||
raise ValueError("fid_div_cls_code is required. (e.g. '0' or '1')")
|
||||
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '000660')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '000660')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe if dataframe is not None else pd.DataFrame()
|
||||
|
||||
|
||||
tr_id = "FHKST66430200"
|
||||
|
||||
params = {
|
||||
"FID_DIV_CLS_CODE": fid_div_cls_code,
|
||||
"fid_cond_mrkt_div_code": fid_cond_mrkt_div_code,
|
||||
"fid_input_iscd": fid_input_iscd,
|
||||
}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
output_data = res.getBody().output
|
||||
if not isinstance(output_data, list):
|
||||
output_data = [output_data]
|
||||
current_data = pd.DataFrame(output_data)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
# 데이터프레임 병합
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
# 연속 거래 여부 확인
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont == "M":
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return finance_income_statement(
|
||||
fid_div_cls_code,
|
||||
fid_cond_mrkt_div_code,
|
||||
fid_input_iscd,
|
||||
"N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,93 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from finance_other_major_ratios import finance_other_major_ratios
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 기타주요비율[v1_국내주식-082]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'stac_yymm': '결산 년월',
|
||||
'payout_rate': '배당 성향',
|
||||
'eva': 'EVA',
|
||||
'ebitda': 'EBITDA',
|
||||
'ev_ebitda': 'EV_EBITDA'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 기타주요비율[v1_국내주식-082]
|
||||
|
||||
국내주식 기타주요비율 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_input_iscd (str): 입력 종목코드 (000660 : 종목코드)
|
||||
- fid_div_cls_code (str): 분류 구분 코드 (0: 년, 1: 분기)
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (J)
|
||||
Returns:
|
||||
- DataFrame: 국내주식 기타주요비율 결과
|
||||
|
||||
Example:
|
||||
>>> df = finance_other_major_ratios(fid_input_iscd="000660", fid_div_cls_code="0", fid_cond_mrkt_div_code="J")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
# API 호출
|
||||
result = finance_other_major_ratios(
|
||||
fid_input_iscd="000660", # 입력 종목코드
|
||||
fid_div_cls_code="0", # 분류 구분 코드
|
||||
fid_cond_mrkt_div_code="J", # 조건 시장 분류 코드
|
||||
)
|
||||
|
||||
if result is None or result.empty:
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# 컬럼명 출력
|
||||
logger.info("사용 가능한 컬럼 목록:")
|
||||
logger.info(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
logger.info("=== 국내주식 기타주요비율 결과 ===")
|
||||
logger.info("조회된 데이터 건수: %d", len(result))
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,116 @@
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 기타주요비율[v1_국내주식-082]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/finance/other-major-ratios"
|
||||
|
||||
def finance_other_major_ratios(
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
fid_div_cls_code: str, # 분류 구분 코드
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
tr_cont: str = "", # 연속 거래 여부
|
||||
dataframe: Optional[pd.DataFrame] = None, # 누적 데이터프레임
|
||||
depth: int = 0, # 현재 재귀 깊이
|
||||
max_depth: int = 10 # 최대 재귀 깊이
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 기타주요비율[v1_국내주식-082]
|
||||
국내주식 기타주요비율 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_input_iscd (str): 종목코드 (예: '000660')
|
||||
fid_div_cls_code (str): 분류 구분 코드 (예: '0' - 년, '1' - 분기)
|
||||
fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (예: 'J')
|
||||
tr_cont (str): 연속 거래 여부 (기본값: 공백)
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임 (기본값: None)
|
||||
depth (int): 현재 재귀 깊이 (기본값: 0)
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: 국내주식 기타주요비율 데이터
|
||||
|
||||
Example:
|
||||
>>> df = finance_other_major_ratios('005930', '1', 'J')
|
||||
>>> print(df)
|
||||
"""
|
||||
# 필수 파라미터 검증
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '000660')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '000660')")
|
||||
|
||||
if not fid_div_cls_code:
|
||||
logger.error("fid_div_cls_code is required. (e.g. '0' or '1')")
|
||||
raise ValueError("fid_div_cls_code is required. (e.g. '0' or '1')")
|
||||
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe if dataframe is not None else pd.DataFrame()
|
||||
|
||||
|
||||
tr_id = "FHKST66430500"
|
||||
|
||||
params = {
|
||||
"fid_input_iscd": fid_input_iscd,
|
||||
"fid_div_cls_code": fid_div_cls_code,
|
||||
"fid_cond_mrkt_div_code": fid_cond_mrkt_div_code,
|
||||
}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
current_data = pd.DataFrame(res.getBody().output)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont == "M":
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return finance_other_major_ratios(
|
||||
fid_input_iscd,
|
||||
fid_div_cls_code,
|
||||
fid_cond_mrkt_div_code,
|
||||
"N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,94 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from finance_profit_ratio import finance_profit_ratio
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 수익성비율[v1_국내주식-081]
|
||||
##############################################################################################
|
||||
|
||||
# 통합 컬럼 매핑
|
||||
COLUMN_MAPPING = {
|
||||
'stac_yymm': '결산 년월',
|
||||
'cptl_ntin_rate': '총자본 순이익율',
|
||||
'self_cptl_ntin_inrt': '자기자본 순이익율',
|
||||
'sale_ntin_rate': '매출액 순이익율',
|
||||
'sale_totl_rate': '매출액 총이익율'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 수익성비율[v1_국내주식-081]
|
||||
|
||||
국내주식 수익성비율 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_input_iscd (str): 입력 종목코드 (000660 : 종목코드)
|
||||
- fid_div_cls_code (str): 분류 구분 코드 (0: 년, 1: 분기)
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (J)
|
||||
Returns:
|
||||
- DataFrame: 국내주식 수익성비율 결과
|
||||
|
||||
Example:
|
||||
>>> df = finance_profit_ratio(fid_input_iscd="000660", fid_div_cls_code="0", fid_cond_mrkt_div_code="J")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
# API 호출
|
||||
result = finance_profit_ratio(
|
||||
fid_input_iscd="000660", # 입력 종목코드
|
||||
fid_div_cls_code="0", # 분류 구분 코드
|
||||
fid_cond_mrkt_div_code="J", # 조건 시장 분류 코드
|
||||
)
|
||||
|
||||
if result is None or result.empty:
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# 컬럼명 출력
|
||||
logger.info("사용 가능한 컬럼 목록:")
|
||||
logger.info(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
logger.info("=== 국내주식 수익성비율 결과 ===")
|
||||
logger.info("조회된 데이터 건수: %d", len(result))
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,128 @@
|
||||
# [국내주식] 종목정보 - 국내주식 수익성비율
|
||||
# Generated by KIS API Generator (Single API Mode)
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 수익성비율[v1_국내주식-081]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/finance/profit-ratio"
|
||||
|
||||
def finance_profit_ratio(
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
fid_div_cls_code: str, # 분류 구분 코드
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
tr_cont: str = "", # 연속 거래 여부
|
||||
dataframe: Optional[pd.DataFrame] = None, # 누적 데이터프레임
|
||||
depth: int = 0, # 현재 재귀 깊이
|
||||
max_depth: int = 10 # 최대 재귀 깊이
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 수익성비율[v1_국내주식-081]
|
||||
국내주식 수익성비율 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_input_iscd (str): 입력 종목코드 (예: '000660')
|
||||
fid_div_cls_code (str): 분류 구분 코드 (0: 년, 1: 분기)
|
||||
fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (예: 'J')
|
||||
tr_cont (str): 연속 거래 여부 (기본값: 공백)
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: 국내주식 수익성비율 데이터
|
||||
|
||||
Example:
|
||||
>>> df = finance_profit_ratio('005930', '1', 'J')
|
||||
>>> print(df)
|
||||
"""
|
||||
# 로깅 설정
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '000660')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '000660')")
|
||||
|
||||
if not fid_div_cls_code:
|
||||
logger.error("fid_div_cls_code is required. (e.g. '0')")
|
||||
raise ValueError("fid_div_cls_code is required. (e.g. '0')")
|
||||
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe if dataframe is not None else pd.DataFrame()
|
||||
|
||||
|
||||
tr_id = "FHKST66430400"
|
||||
|
||||
params = {
|
||||
"fid_input_iscd": fid_input_iscd,
|
||||
"FID_DIV_CLS_CODE": fid_div_cls_code,
|
||||
"fid_cond_mrkt_div_code": fid_cond_mrkt_div_code,
|
||||
}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
# 응답 데이터 처리
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
output_data = res.getBody().output
|
||||
if not isinstance(output_data, list):
|
||||
output_data = [output_data]
|
||||
current_data = pd.DataFrame(output_data)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
# 데이터프레임 병합
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
# 연속 거래 여부 확인
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont == "M":
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return finance_profit_ratio(
|
||||
fid_input_iscd,
|
||||
fid_div_cls_code,
|
||||
fid_cond_mrkt_div_code,
|
||||
"N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
# API 호출 실패 시 에러 로그
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,114 @@
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from finance_ratio import finance_ratio
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > 국내주식 재무비율 순위[v1_국내주식-092]
|
||||
##############################################################################################
|
||||
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'data_rank': '데이터 순위',
|
||||
'hts_kor_isnm': 'HTS 한글 종목명',
|
||||
'mksc_shrn_iscd': '유가증권 단축 종목코드',
|
||||
'stck_prpr': '주식 현재가',
|
||||
'prdy_vrss': '전일 대비',
|
||||
'prdy_vrss_sign': '전일 대비 부호',
|
||||
'prdy_ctrt': '전일 대비율',
|
||||
'acml_vol': '누적 거래량',
|
||||
'cptl_op_prfi': '총자본경상이익율',
|
||||
'cptl_ntin_rate': '총자본 순이익율',
|
||||
'sale_totl_rate': '매출액 총이익율',
|
||||
'sale_ntin_rate': '매출액 순이익율',
|
||||
'bis': '자기자본비율',
|
||||
'lblt_rate': '부채 비율',
|
||||
'bram_depn': '차입금 의존도',
|
||||
'rsrv_rate': '유보 비율',
|
||||
'grs': '매출액 증가율',
|
||||
'op_prfi_inrt': '경상 이익 증가율',
|
||||
'bsop_prfi_inrt': '영업 이익 증가율',
|
||||
'ntin_inrt': '순이익 증가율',
|
||||
'equt_inrt': '자기자본 증가율',
|
||||
'cptl_tnrt': '총자본회전율',
|
||||
'sale_bond_tnrt': '매출 채권 회전율',
|
||||
'totl_aset_inrt': '총자산 증가율',
|
||||
'stac_month': '결산 월',
|
||||
'stac_month_cls_code': '결산 월 구분 코드',
|
||||
'iqry_csnu': '조회 건수'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
국내주식 재무비율 순위[v1_국내주식-092]
|
||||
|
||||
국내주식 재무비율 순위 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_trgt_cls_code (str): 대상 구분 코드 (0 : 전체)
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (시장구분코드 (주식 J))
|
||||
- fid_cond_scr_div_code (str): 조건 화면 분류 코드 (Unique key( 20175 ))
|
||||
- fid_input_iscd (str): 입력 종목코드 (0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200)
|
||||
- fid_div_cls_code (str): 분류 구분 코드 (0 : 전체)
|
||||
- fid_input_price_1 (str): 입력 가격1 (입력값 없을때 전체 (가격 ~))
|
||||
- fid_input_price_2 (str): 입력 가격2 (입력값 없을때 전체 (~ 가격))
|
||||
- fid_vol_cnt (str): 거래량 수 (입력값 없을때 전체 (거래량 ~))
|
||||
- fid_input_option_1 (str): 입력 옵션1 (회계년도 입력 (ex 2023))
|
||||
- fid_input_option_2 (str): 입력 옵션2 (0: 1/4분기 , 1: 반기, 2: 3/4분기, 3: 결산)
|
||||
- fid_rank_sort_cls_code (str): 순위 정렬 구분 코드 (7: 수익성 분석, 11 : 안정성 분석, 15: 성장성 분석, 20: 활동성 분석)
|
||||
- fid_blng_cls_code (str): 소속 구분 코드 (0)
|
||||
- fid_trgt_exls_cls_code (str): 대상 제외 구분 코드 (0 : 전체)
|
||||
Returns:
|
||||
- DataFrame: 국내주식 재무비율 순위 결과
|
||||
|
||||
Example:
|
||||
>>> df = finance_ratio(fid_trgt_cls_code="0", fid_cond_mrkt_div_code="J", fid_cond_scr_div_code="20175", fid_input_iscd="0000", fid_div_cls_code="0", fid_input_price_1="", fid_input_price_2="", fid_vol_cnt="", fid_input_option_1="2023", fid_input_option_2="3", fid_rank_sort_cls_code="7", fid_blng_cls_code="0", fid_trgt_exls_cls_code="0")
|
||||
"""
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
# API 호출
|
||||
result = finance_ratio(
|
||||
fid_trgt_cls_code="0", # 대상 구분 코드,
|
||||
fid_cond_mrkt_div_code="J", # 조건 시장 분류 코드,
|
||||
fid_cond_scr_div_code="20175", # 조건 화면 분류 코드,
|
||||
fid_input_iscd="0000", # 입력 종목코드,
|
||||
fid_div_cls_code="0", # 분류 구분 코드,
|
||||
fid_input_price_1="", # 입력 가격1,
|
||||
fid_input_price_2="", # 입력 가격2,
|
||||
fid_vol_cnt="", # 거래량 수,
|
||||
fid_input_option_1="2023", # 입력 옵션1,
|
||||
fid_input_option_2="3", # 입력 옵션2,
|
||||
fid_rank_sort_cls_code="7", # 순위 정렬 구분 코드,
|
||||
fid_blng_cls_code="0", # 소속 구분 코드,
|
||||
fid_trgt_exls_cls_code="0", # 대상 제외 구분 코드
|
||||
)
|
||||
|
||||
# 컬럼명 출력
|
||||
print("\n=== 사용 가능한 컬럼 목록 ===")
|
||||
print(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
print("\n=== 국내주식 재무비율 순위 결과 ===")
|
||||
print(result)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,166 @@
|
||||
import logging
|
||||
import sys
|
||||
import time
|
||||
from typing import Optional
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > 국내주식 재무비율 순위[v1_국내주식-092]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/ranking/finance-ratio"
|
||||
|
||||
def finance_ratio(
|
||||
fid_trgt_cls_code: str, # 대상 구분 코드
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
fid_cond_scr_div_code: str, # 조건 화면 분류 코드
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
fid_div_cls_code: str, # 분류 구분 코드
|
||||
fid_input_price_1: str, # 입력 가격1
|
||||
fid_input_price_2: str, # 입력 가격2
|
||||
fid_vol_cnt: str, # 거래량 수
|
||||
fid_input_option_1: str, # 입력 옵션1
|
||||
fid_input_option_2: str, # 입력 옵션2
|
||||
fid_rank_sort_cls_code: str, # 순위 정렬 구분 코드
|
||||
fid_blng_cls_code: str, # 소속 구분 코드
|
||||
fid_trgt_exls_cls_code: str, # 대상 제외 구분 코드
|
||||
tr_cont: str = "", # 연속 거래 여부
|
||||
dataframe: Optional[pd.DataFrame] = None # 누적 데이터프레임
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
국내주식 재무비율 순위[v1_국내주식-092]
|
||||
국내주식 재무비율 순위 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_trgt_cls_code (str): 대상 구분 코드 (0 : 전체)
|
||||
fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (J:KRX, NX:NXT)
|
||||
fid_cond_scr_div_code (str): 조건 화면 분류 코드 (Unique key, 20175)
|
||||
fid_input_iscd (str): 입력 종목코드 (0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200)
|
||||
fid_div_cls_code (str): 분류 구분 코드 (0 : 전체)
|
||||
fid_input_price_1 (str): 입력 가격1 (입력값 없을때 전체, 가격 ~)
|
||||
fid_input_price_2 (str): 입력 가격2 (입력값 없을때 전체, ~ 가격)
|
||||
fid_vol_cnt (str): 거래량 수 (입력값 없을때 전체, 거래량 ~)
|
||||
fid_input_option_1 (str): 입력 옵션1 (회계년도 입력, ex 2023)
|
||||
fid_input_option_2 (str): 입력 옵션2 (0: 1/4분기, 1: 반기, 2: 3/4분기, 3: 결산)
|
||||
fid_rank_sort_cls_code (str): 순위 정렬 구분 코드 (7: 수익성 분석, 11: 안정성 분석, 15: 성장성 분석, 20: 활동성 분석)
|
||||
fid_blng_cls_code (str): 소속 구분 코드 (0)
|
||||
fid_trgt_exls_cls_code (str): 대상 제외 구분 코드 (0 : 전체)
|
||||
tr_cont (str): 연속 거래 여부 (공백 : 초기 조회, N : 다음 데이터 조회)
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: 국내주식 재무비율 순위 데이터
|
||||
|
||||
Example:
|
||||
>>> df = finance_ratio(
|
||||
... fid_trgt_cls_code="0",
|
||||
... fid_cond_mrkt_div_code="J",
|
||||
... fid_cond_scr_div_code="20175",
|
||||
... fid_input_iscd="0000",
|
||||
... fid_div_cls_code="0",
|
||||
... fid_input_price_1="",
|
||||
... fid_input_price_2="",
|
||||
... fid_vol_cnt="",
|
||||
... fid_input_option_1="2023",
|
||||
... fid_input_option_2="3",
|
||||
... fid_rank_sort_cls_code="7",
|
||||
... fid_blng_cls_code="0",
|
||||
... fid_trgt_exls_cls_code="0"
|
||||
... )
|
||||
>>> print(df)
|
||||
"""
|
||||
# 필수 파라미터 검증
|
||||
if fid_trgt_cls_code == "":
|
||||
raise ValueError("대상 구분 코드 확인요망!!!")
|
||||
if fid_cond_mrkt_div_code != "J":
|
||||
raise ValueError("조건 시장 분류 코드 확인요망!!!")
|
||||
if fid_cond_scr_div_code != "20175":
|
||||
raise ValueError("조건 화면 분류 코드 확인요망!!!")
|
||||
if fid_input_iscd not in ["0000", "0001", "1001", "2001"]:
|
||||
raise ValueError("입력 종목코드 확인요망!!!")
|
||||
if fid_div_cls_code != "0":
|
||||
raise ValueError("분류 구분 코드 확인요망!!!")
|
||||
if fid_input_option_2 not in ["0", "1", "2", "3"]:
|
||||
raise ValueError("입력 옵션2 확인요망!!!")
|
||||
if fid_rank_sort_cls_code not in ["7", "11", "15", "20"]:
|
||||
raise ValueError("순위 정렬 구분 코드 확인요망!!!")
|
||||
if fid_blng_cls_code != "0":
|
||||
raise ValueError("소속 구분 코드 확인요망!!!")
|
||||
if fid_trgt_exls_cls_code != "0":
|
||||
raise ValueError("대상 제외 구분 코드 확인요망!!!")
|
||||
|
||||
|
||||
tr_id = "FHPST01750000"
|
||||
|
||||
params = {
|
||||
"fid_trgt_cls_code": fid_trgt_cls_code,
|
||||
"fid_cond_mrkt_div_code": fid_cond_mrkt_div_code,
|
||||
"fid_cond_scr_div_code": fid_cond_scr_div_code,
|
||||
"fid_input_iscd": fid_input_iscd,
|
||||
"fid_div_cls_code": fid_div_cls_code,
|
||||
"fid_input_price_1": fid_input_price_1,
|
||||
"fid_input_price_2": fid_input_price_2,
|
||||
"fid_vol_cnt": fid_vol_cnt,
|
||||
"fid_input_option_1": fid_input_option_1,
|
||||
"fid_input_option_2": fid_input_option_2,
|
||||
"fid_rank_sort_cls_code": fid_rank_sort_cls_code,
|
||||
"fid_blng_cls_code": fid_blng_cls_code,
|
||||
"fid_trgt_exls_cls_code": fid_trgt_exls_cls_code,
|
||||
}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
# 응답 데이터 처리
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
current_data = pd.DataFrame(res.getBody().output)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
# 데이터프레임 병합
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
# 연속 거래 여부 확인
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont == "M":
|
||||
print("Call Next")
|
||||
ka.smart_sleep()
|
||||
return finance_ratio(
|
||||
fid_trgt_cls_code,
|
||||
fid_cond_mrkt_div_code,
|
||||
fid_cond_scr_div_code,
|
||||
fid_input_iscd,
|
||||
fid_div_cls_code,
|
||||
fid_input_price_1,
|
||||
fid_input_price_2,
|
||||
fid_vol_cnt,
|
||||
fid_input_option_1,
|
||||
fid_input_option_2,
|
||||
fid_rank_sort_cls_code,
|
||||
fid_blng_cls_code,
|
||||
fid_trgt_exls_cls_code,
|
||||
"N", dataframe
|
||||
)
|
||||
else:
|
||||
print("The End")
|
||||
return dataframe
|
||||
else:
|
||||
# 오류 처리
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,93 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from finance_stability_ratio import finance_stability_ratio
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 안정성비율 [v1_국내주식-083]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'stac_yymm': '결산 년월',
|
||||
'lblt_rate': '부채 비율',
|
||||
'bram_depn': '차입금 의존도',
|
||||
'crnt_rate': '유동 비율',
|
||||
'quck_rate': '당좌 비율'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 안정성비율[v1_국내주식-083]
|
||||
|
||||
국내주식 안정성비율 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_input_iscd (str): 입력 종목코드 (000660 : 종목코드)
|
||||
- fid_div_cls_code (str): 분류 구분 코드 (0: 년, 1: 분기)
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (J)
|
||||
Returns:
|
||||
- DataFrame: 국내주식 안정성비율 결과
|
||||
|
||||
Example:
|
||||
>>> df = finance_stability_ratio(fid_input_iscd="000660", fid_div_cls_code="0", fid_cond_mrkt_div_code="J")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
# API 호출
|
||||
result = finance_stability_ratio(
|
||||
fid_input_iscd="000660", # 입력 종목코드
|
||||
fid_div_cls_code="0", # 분류 구분 코드
|
||||
fid_cond_mrkt_div_code="J", # 조건 시장 분류 코드
|
||||
)
|
||||
|
||||
if result is None or result.empty:
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# 컬럼명 출력
|
||||
logger.info("사용 가능한 컬럼 목록:")
|
||||
logger.info(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
logger.info("=== 국내주식 안정성비율 결과 ===")
|
||||
logger.info("조회된 데이터 건수: %d", len(result))
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,118 @@
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 종목정보 > 국내주식 안정성비율[v1_국내주식-083]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/finance/stability-ratio"
|
||||
|
||||
def finance_stability_ratio(
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
fid_div_cls_code: str, # 분류 구분 코드
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
tr_cont: str = "", # 연속 거래 여부
|
||||
dataframe: Optional[pd.DataFrame] = None, # 누적 데이터프레임
|
||||
depth: int = 0, # 현재 재귀 깊이
|
||||
max_depth: int = 10 # 최대 재귀 깊이
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 종목정보
|
||||
국내주식 안정성비율[v1_국내주식-083]
|
||||
국내주식 안정성비율 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_input_iscd (str): 종목코드 (예: '000660')
|
||||
fid_div_cls_code (str): 분류 구분 코드 (예: '0' - 년, '1' - 분기)
|
||||
fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (예: 'J')
|
||||
tr_cont (str): 연속 거래 여부 (기본값: "")
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임 (기본값: None)
|
||||
depth (int): 현재 재귀 깊이 (기본값: 0)
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: 국내주식 안정성비율 데이터
|
||||
|
||||
Example:
|
||||
>>> df = finance_stability_ratio('005930', '1', 'J')
|
||||
>>> print(df)
|
||||
"""
|
||||
# 필수 파라미터 검증
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '000660')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '000660')")
|
||||
|
||||
if not fid_div_cls_code:
|
||||
logger.error("fid_div_cls_code is required. (e.g. '0' or '1')")
|
||||
raise ValueError("fid_div_cls_code is required. (e.g. '0' or '1')")
|
||||
|
||||
if not fid_cond_mrkt_div_code:
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe if dataframe is not None else pd.DataFrame()
|
||||
|
||||
|
||||
tr_id = "FHKST66430600"
|
||||
|
||||
params = {
|
||||
"fid_input_iscd": fid_input_iscd,
|
||||
"fid_div_cls_code": fid_div_cls_code,
|
||||
"fid_cond_mrkt_div_code": fid_cond_mrkt_div_code,
|
||||
}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
output_data = res.getBody().output
|
||||
if not isinstance(output_data, list):
|
||||
output_data = [output_data]
|
||||
current_data = pd.DataFrame(output_data)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont == "M":
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return finance_stability_ratio(
|
||||
fid_input_iscd,
|
||||
fid_div_cls_code,
|
||||
fid_cond_mrkt_div_code,
|
||||
"N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,115 @@
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from fluctuation import fluctuation
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > 등락률 순위[v1_국내주식-088]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
"stck_shrn_iscd": "주식 단축 종목코드",
|
||||
"data_rank": "데이터 순위",
|
||||
"hts_kor_isnm": "HTS 한글 종목명",
|
||||
"stck_prpr": "주식 현재가",
|
||||
"prdy_vrss": "전일 대비",
|
||||
"prdy_vrss_sign": "전일 대비 부호",
|
||||
"prdy_ctrt": "전일 대비율",
|
||||
"acml_vol": "누적 거래량",
|
||||
"stck_hgpr": "주식 최고가",
|
||||
"hgpr_hour": "최고가 시간",
|
||||
"acml_hgpr_date": "누적 최고가 일자",
|
||||
"stck_lwpr": "주식 최저가",
|
||||
"lwpr_hour": "최저가 시간",
|
||||
"acml_lwpr_date": "누적 최저가 일자",
|
||||
"lwpr_vrss_prpr_rate": "저가 대비 현재가 비율",
|
||||
"dsgt_date_clpr_vrss_prpr_rate": "영업 일수 대비 현재가 비율",
|
||||
"cnnt_ascn_dynu": "연속 상승 일수",
|
||||
"hgpr_vrss_prpr_rate": "고가 대비 현재가 비율",
|
||||
"cnnt_down_dynu": "연속 하락 일수",
|
||||
"oprc_vrss_prpr_sign": "시가 대비 부호",
|
||||
"oprc_vrss_prpr": "시가 대비",
|
||||
"oprc_vrss_prpr_rate": "시가 대비 현재가 비율",
|
||||
"prd_rsfl": "기간 등락",
|
||||
"prd_rsfl_rate": "기간 등락 비율"
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
등락률 순위[v1_국내주식-088]
|
||||
|
||||
국내주식 등락률 순위 조회 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (J: 주식, W: ELW, Q: ETF)
|
||||
- fid_cond_scr_div_code (str): 조건 화면 분류 코드 (20170: 등락률)
|
||||
- fid_input_iscd (str): 입력 종목코드 (0000: 전체)
|
||||
- fid_rank_sort_cls_code (str): 순위 정렬 구분 코드 (0000: 등락률순)
|
||||
- fid_input_cnt_1 (str): 입력 수1 (조회할 종목 수)
|
||||
- fid_prc_cls_code (str): 가격 구분 코드 (0: 전체)
|
||||
- fid_input_price_1 (str): 입력 가격1 (하한가)
|
||||
- fid_input_price_2 (str): 입력 가격2 (상한가)
|
||||
- fid_vol_cnt (str): 거래량 수 (최소 거래량)
|
||||
- fid_trgt_cls_code (str): 대상 구분 코드 (9자리, "1" or "0", 증거금30% 40% 50% 60% 100% 신용보증금30% 40% 50% 60%)
|
||||
- fid_trgt_exls_cls_code (str): 대상 제외 구분 코드 (10자리, "1" or "0", 투자위험/경고/주의 관리종목 정리매매 불성실공시 우선주 거래정지 ETF ETN 신용주문불가 SPAC)
|
||||
- fid_div_cls_code (str): 분류 구분 코드 (0: 전체)
|
||||
- fid_rsfl_rate1 (str): 등락 비율1 (하락률 하한)
|
||||
- fid_rsfl_rate2 (str): 등락 비율2 (상승률 상한)
|
||||
- tr_cont (str): 연속 거래 여부
|
||||
- dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
|
||||
Returns:
|
||||
- DataFrame: 국내주식 등락률 순위 조회 결과
|
||||
|
||||
Example:
|
||||
>>> df = fluctuation(fid_cond_mrkt_div_code="J", fid_cond_scr_div_code="20170", fid_input_iscd="0000", fid_rank_sort_cls_code="0", fid_input_cnt_1="0", fid_prc_cls_code="0", fid_input_price_1="", fid_input_price_2="", fid_vol_cnt="", fid_trgt_cls_code="0", fid_trgt_exls_cls_code="0", fid_div_cls_code="0", fid_rsfl_rate1="", fid_rsfl_rate2="")
|
||||
"""
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
# API 호출
|
||||
result = fluctuation(
|
||||
fid_cond_mrkt_div_code="J",
|
||||
fid_cond_scr_div_code="20170",
|
||||
fid_input_iscd="0000",
|
||||
fid_rank_sort_cls_code="0",
|
||||
fid_input_cnt_1="0",
|
||||
fid_prc_cls_code="0",
|
||||
fid_input_price_1="",
|
||||
fid_input_price_2="",
|
||||
fid_vol_cnt="",
|
||||
fid_trgt_cls_code="0",
|
||||
fid_trgt_exls_cls_code="0",
|
||||
fid_div_cls_code="0",
|
||||
fid_rsfl_rate1="",
|
||||
fid_rsfl_rate2="",
|
||||
)
|
||||
|
||||
# 컬럼명 출력
|
||||
print("\n=== 사용 가능한 컬럼 목록 ===")
|
||||
print(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
print("\n=== 국내주식 거래량순위 조회 결과 ===")
|
||||
print(result)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,126 @@
|
||||
import logging
|
||||
import sys
|
||||
import time
|
||||
from typing import Optional
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > 등락률 순위[v1_국내주식-088]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/ranking/fluctuation"
|
||||
|
||||
def fluctuation(
|
||||
fid_cond_mrkt_div_code: str, # 필수, 조건 시장 분류 코드
|
||||
fid_cond_scr_div_code: str, # 필수, 조건 화면 분류 코드
|
||||
fid_input_iscd: str, # 필수, 입력 종목코드
|
||||
fid_rank_sort_cls_code: str, # 필수, 순위 정렬 구분 코드
|
||||
fid_input_cnt_1: str, # 필수, 입력 수1
|
||||
fid_prc_cls_code: str, # 필수, 가격 구분 코드
|
||||
fid_input_price_1: str, # 필수, 입력 가격1
|
||||
fid_input_price_2: str, # 필수, 입력 가격2
|
||||
fid_vol_cnt: str, # 필수, 거래량 수
|
||||
fid_trgt_cls_code: str, # 필수, 대상 구분 코드
|
||||
fid_trgt_exls_cls_code: str, # 필수, 대상 제외 구분 코드
|
||||
fid_div_cls_code: str, # 필수, 분류 구분 코드
|
||||
fid_rsfl_rate1: str, # 필수, 등락 비율1
|
||||
fid_rsfl_rate2: str, # 필수, 등락 비율2
|
||||
tr_cont: str = "", # 선택, 연속 거래 여부
|
||||
dataframe: Optional[pd.DataFrame] = None # 선택, 누적 데이터프레임
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
등락률 순위[v1_국내주식-088]
|
||||
국내주식 등락률 순위 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_cond_mrkt_div_code (str): 조건 시장 분류 코드 (J:KRX, NX:NXT)
|
||||
fid_cond_scr_div_code (str): 조건 화면 분류 코드 (20170: 등락률)
|
||||
fid_input_iscd (str): 입력 종목코드 (0000: 전체)
|
||||
fid_rank_sort_cls_code (str): 순위 정렬 구분 코드 (0000: 등락률순)
|
||||
fid_input_cnt_1 (str): 입력 수1 (조회할 종목 수)
|
||||
fid_prc_cls_code (str): 가격 구분 코드 (0: 전체)
|
||||
fid_input_price_1 (str): 입력 가격1 (하한가)
|
||||
fid_input_price_2 (str): 입력 가격2 (상한가)
|
||||
fid_vol_cnt (str): 거래량 수 (최소 거래량)
|
||||
fid_trgt_cls_code (str): 대상 구분 코드 (9자리, "1" or "0", 증거금30% 40% 50% 60% 100% 신용보증금30% 40% 50% 60%)
|
||||
fid_trgt_exls_cls_code (str): 대상 제외 구분 코드 (10자리, "1" or "0", 투자위험/경고/주의 관리종목 정리매매 불성실공시 우선주 거래정지 ETF ETN 신용주문불가 SPAC)
|
||||
fid_div_cls_code (str): 분류 구분 코드 (0: 전체)
|
||||
fid_rsfl_rate1 (str): 등락 비율1 (하락률 하한)
|
||||
fid_rsfl_rate2 (str): 등락 비율2 (상승률 상한)
|
||||
tr_cont (str): 연속 거래 여부
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: API 응답 데이터
|
||||
|
||||
Example:
|
||||
>>> df = fluctuation(fid_rsfl_rate2="10", fid_cond_mrkt_div_code="J", fid_cond_scr_div_code="20170", fid_input_iscd="0000", fid_rank_sort_cls_code="0000", fid_input_cnt_1="10", fid_prc_cls_code="0", fid_input_price_1="0", fid_input_price_2="1000000", fid_vol_cnt="100000", fid_trgt_cls_code="0", fid_trgt_exls_cls_code="0", fid_div_cls_code="0", fid_rsfl_rate1="0")
|
||||
>>> print(df)
|
||||
"""
|
||||
if fid_cond_mrkt_div_code not in ["J", "W", "Q"]:
|
||||
raise ValueError("조건 시장 분류 코드 확인요망!!!")
|
||||
|
||||
if fid_cond_scr_div_code != "20170":
|
||||
raise ValueError("조건 화면 분류 코드 확인요망!!!")
|
||||
|
||||
|
||||
tr_id = "FHPST01700000" # 국내주식 등락률 순위
|
||||
|
||||
params = {
|
||||
"fid_rsfl_rate2": fid_rsfl_rate2,
|
||||
"fid_cond_mrkt_div_code": fid_cond_mrkt_div_code,
|
||||
"fid_cond_scr_div_code": fid_cond_scr_div_code,
|
||||
"fid_input_iscd": fid_input_iscd,
|
||||
"fid_rank_sort_cls_code": fid_rank_sort_cls_code,
|
||||
"fid_input_cnt_1": fid_input_cnt_1,
|
||||
"fid_prc_cls_code": fid_prc_cls_code,
|
||||
"fid_input_price_1": fid_input_price_1,
|
||||
"fid_input_price_2": fid_input_price_2,
|
||||
"fid_vol_cnt": fid_vol_cnt,
|
||||
"fid_trgt_cls_code": fid_trgt_cls_code,
|
||||
"fid_trgt_exls_cls_code": fid_trgt_exls_cls_code,
|
||||
"fid_div_cls_code": fid_div_cls_code,
|
||||
"fid_rsfl_rate1": fid_rsfl_rate1
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
if hasattr(res.getBody(), 'output'):
|
||||
current_data = pd.DataFrame(res.getBody().output)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont == "M": # 다음 페이지 존재
|
||||
print("Call Next")
|
||||
ka.smart_sleep() # 시스템 안정적 운영을 위한 지연
|
||||
return fluctuation(
|
||||
fid_rsfl_rate2, fid_cond_mrkt_div_code, fid_cond_scr_div_code,
|
||||
fid_input_iscd, fid_rank_sort_cls_code, fid_input_cnt_1,
|
||||
fid_prc_cls_code, fid_input_price_1, fid_input_price_2,
|
||||
fid_vol_cnt, fid_trgt_cls_code, fid_trgt_exls_cls_code,
|
||||
fid_div_cls_code, fid_rsfl_rate1, "N", dataframe
|
||||
)
|
||||
else:
|
||||
print("The End")
|
||||
return dataframe
|
||||
else:
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,100 @@
|
||||
"""
|
||||
Created on 20250129
|
||||
"""
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from foreign_institution_total import foreign_institution_total
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 국내기관_외국인 매매종목가집계[국내주식-037]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'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': '외국인 순매수 거래 대금',
|
||||
'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': '기타 법인 순매수 거래 대금'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내기관_외국인 매매종목가집계 조회 테스트 함수
|
||||
|
||||
이 함수는 국내기관_외국인 매매종목가집계 API를 호출하여 결과를 출력합니다.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
# case1 조회
|
||||
logging.info("=== case1 조회 ===")
|
||||
try:
|
||||
result = foreign_institution_total(
|
||||
fid_cond_mrkt_div_code="V",
|
||||
fid_cond_scr_div_code="16449",
|
||||
fid_input_iscd="0000",
|
||||
fid_div_cls_code="0",
|
||||
fid_rank_sort_cls_code="0",
|
||||
fid_etc_cls_code="0"
|
||||
)
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
logging.info("사용 가능한 컬럼: %s", result.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환 및 데이터 출력
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,94 @@
|
||||
"""
|
||||
Created on 20250129
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 국내기관_외국인 매매종목가집계[국내주식-037]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/foreign-institution-total"
|
||||
|
||||
def foreign_institution_total(
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드
|
||||
fid_cond_scr_div_code: str, # 조건화면분류코드
|
||||
fid_input_iscd: str, # 입력 종목코드
|
||||
fid_div_cls_code: str, # 분류구분코드
|
||||
fid_rank_sort_cls_code: str, # 순위정렬구분코드
|
||||
fid_etc_cls_code: str # 기타구분정렬
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
국내기관_외국인 매매종목가집계 API입니다.
|
||||
|
||||
HTS(efriend Plus) [0440] 외국인/기관 매매종목 가집계 화면을 API로 구현한 사항으로 화면을 함께 보시면 기능 이해가 쉽습니다.
|
||||
|
||||
증권사 직원이 장중에 집계/입력한 자료를 단순 누계한 수치로서,
|
||||
입력시간은 외국인 09:30, 11:20, 13:20, 14:30 / 기관종합 10:00, 11:20, 13:20, 14:30 이며,
|
||||
입력한 시간은 ±10분정도 차이가 발생할 수 있으며, 장운영 사정에 다라 변동될 수 있습니다.
|
||||
|
||||
Args:
|
||||
fid_cond_mrkt_div_code (str): [필수] 조건 시장 분류 코드 (ex. V)
|
||||
fid_cond_scr_div_code (str): [필수] 조건화면분류코드 (ex. 16449)
|
||||
fid_input_iscd (str): [필수] 입력 종목코드 (ex. 0000:전체,0001:코스피,1001:코스닥,...,FAQ 종목정보 다운로드(국내) - 업종코드 참조 )
|
||||
fid_div_cls_code (str): [필수] 분류구분코드 (ex. 0:수량정열, 1:금액정열)
|
||||
fid_rank_sort_cls_code (str): [필수] 순위정렬구분코드 (ex. 0:순매수상위,1:순매도상위)
|
||||
fid_etc_cls_code (str): [필수] 기타구분정렬 (ex. 0:전체,1:외국인,2:기관계,3:기타)
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: 국내기관_외국인 매매종목가집계 데이터
|
||||
|
||||
Example:
|
||||
>>> df = foreign_institution_total("V", "16449", "0000", "0", "0", "0")
|
||||
>>> print(df)
|
||||
"""
|
||||
|
||||
if fid_cond_mrkt_div_code == "":
|
||||
raise ValueError("fid_cond_mrkt_div_code is required (e.g. 'V')")
|
||||
|
||||
if fid_cond_scr_div_code == "":
|
||||
raise ValueError("fid_cond_scr_div_code is required (e.g. '16449')")
|
||||
|
||||
if fid_input_iscd == "":
|
||||
raise ValueError("fid_input_iscd is required (e.g. '0000:전체,0001:코스피,1001:코스닥,...,FAQ 종목정보 다운로드(국내) - 업종코드 참조 ')")
|
||||
|
||||
if fid_div_cls_code == "":
|
||||
raise ValueError("fid_div_cls_code is required (e.g. '0:수량정열, 1:금액정열')")
|
||||
|
||||
if fid_rank_sort_cls_code == "":
|
||||
raise ValueError("fid_rank_sort_cls_code is required (e.g. '0:순매수상위,1:순매도상위')")
|
||||
|
||||
if fid_etc_cls_code == "":
|
||||
raise ValueError("fid_etc_cls_code is required (e.g. '0:전체,1:외국인,2:기관계,3:기타')")
|
||||
|
||||
tr_id = "FHPTJ04400000" # 국내기관_외국인 매매종목가집계
|
||||
|
||||
params = {
|
||||
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code, # 조건 시장 분류 코드
|
||||
"FID_COND_SCR_DIV_CODE": fid_cond_scr_div_code, # 조건화면분류코드
|
||||
"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 = ka._url_fetch(API_URL, tr_id, "", params)
|
||||
|
||||
if res.isOK():
|
||||
current_data = pd.DataFrame(res.getBody().output)
|
||||
|
||||
logging.info("Data fetch complete.")
|
||||
return current_data
|
||||
else:
|
||||
res.printError(url=API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from frgnmem_pchs_trend import frgnmem_pchs_trend
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 종목별 외국계 순매수추이 [국내주식-164]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'bsop_hour': '영업시간',
|
||||
'stck_prpr': '주식현재가',
|
||||
'prdy_vrss': '전일대비',
|
||||
'prdy_vrss_sign': '전일대비부호',
|
||||
'prdy_ctrt': '전일대비율',
|
||||
'acml_vol': '누적거래량',
|
||||
'frgn_seln_vol': '외국인매도거래량',
|
||||
'frgn_shnu_vol': '외국인매수2거래량',
|
||||
'glob_ntby_qty': '외국계순매수수량',
|
||||
'frgn_ntby_qty_icdc': '외국인순매수수량증감'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
종목별 외국계 순매수추이 조회 테스트 함수
|
||||
|
||||
이 함수는 종목별 외국계 순매수추이 API를 호출하여 결과를 출력합니다.
|
||||
테스트 데이터로 삼성전자(005930)를 사용합니다.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
# case1 테스트
|
||||
logging.info("=== Case1: 삼성전자 외국계 순매수추이 조회 ===")
|
||||
try:
|
||||
result = frgnmem_pchs_trend(
|
||||
fid_cond_mrkt_div_code="J",
|
||||
fid_input_iscd="005930",
|
||||
fid_input_iscd_2="99999"
|
||||
)
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
logging.info("사용 가능한 컬럼: %s", result.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,71 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 종목별 외국계 순매수추이 [국내주식-164]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/frgnmem-pchs-trend"
|
||||
|
||||
def frgnmem_pchs_trend(
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드 (ex. J)
|
||||
fid_input_iscd: str, # 입력 종목코드 (ex. 123456)
|
||||
fid_input_iscd_2: str # 입력 종목코드 (ex. 99999)
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
종목별 외국계 순매수추이 API입니다.
|
||||
한국투자 HTS(eFriend Plus) > [0433] 종목별 외국계 순매수추이 화면의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.
|
||||
|
||||
Args:
|
||||
fid_cond_mrkt_div_code (str): [필수] 조건 시장 분류 코드 (ex. J)
|
||||
fid_input_iscd (str): [필수] 입력 종목코드 (ex. 123456)
|
||||
fid_input_iscd_2 (str): [필수] 입력 종목코드 (ex. 99999)
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: 종목별 외국계 순매수추이 데이터
|
||||
|
||||
Example:
|
||||
>>> df = frgnmem_pchs_trend("J", "005930", "99999")
|
||||
>>> print(df)
|
||||
"""
|
||||
|
||||
if not fid_cond_mrkt_div_code:
|
||||
raise ValueError("fid_cond_mrkt_div_code is required (e.g. 'J')")
|
||||
|
||||
if not fid_input_iscd:
|
||||
raise ValueError("fid_input_iscd is required (e.g. '123456')")
|
||||
|
||||
if not fid_input_iscd_2:
|
||||
raise ValueError("fid_input_iscd_2 is required (e.g. '99999')")
|
||||
|
||||
tr_id = "FHKST644400C0"
|
||||
|
||||
params = {
|
||||
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code,
|
||||
"FID_INPUT_ISCD": fid_input_iscd,
|
||||
"FID_INPUT_ISCD_2": fid_input_iscd_2,
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, "", params)
|
||||
|
||||
if res.isOK():
|
||||
output_data = pd.DataFrame(res.getBody().output)
|
||||
|
||||
logging.info("Data fetch complete.")
|
||||
return output_data
|
||||
else:
|
||||
res.printError(url=API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,84 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from frgnmem_trade_estimate import frgnmem_trade_estimate
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 외국계 매매종목 가집계 [국내주식-161]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'stck_shrn_iscd': '주식단축종목코드',
|
||||
'hts_kor_isnm': 'HTS한글종목명',
|
||||
'glob_ntsl_qty': '외국계순매도수량',
|
||||
'stck_prpr': '주식현재가',
|
||||
'prdy_vrss': '전일대비',
|
||||
'prdy_vrss_sign': '전일대비부호',
|
||||
'prdy_ctrt': '전일대비율',
|
||||
'acml_vol': '누적거래량',
|
||||
'glob_total_seln_qty': '외국계총매도수량',
|
||||
'glob_total_shnu_qty': '외국계총매수2수량'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
외국계 매매종목 가집계 조회 테스트 함수
|
||||
|
||||
이 함수는 외국계 매매종목 가집계 API를 호출하여 결과를 출력합니다.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
# case1 조회
|
||||
logging.info("=== case1 조회 ===")
|
||||
try:
|
||||
result = frgnmem_trade_estimate(
|
||||
fid_cond_mrkt_div_code="J",
|
||||
fid_cond_scr_div_code="16441",
|
||||
fid_input_iscd="0000",
|
||||
fid_rank_sort_cls_code="0",
|
||||
fid_rank_sort_cls_code_2="0"
|
||||
)
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
logging.info("사용 가능한 컬럼: %s", result.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환 및 데이터 출력
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 시세분석 > 외국계 매매종목 가집계 [국내주식-161]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/frgnmem-trade-estimate"
|
||||
|
||||
|
||||
def frgnmem_trade_estimate(
|
||||
fid_cond_mrkt_div_code: str,
|
||||
fid_cond_scr_div_code: str,
|
||||
fid_input_iscd: str,
|
||||
fid_rank_sort_cls_code: str,
|
||||
fid_rank_sort_cls_code_2: str
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
외국계 매매종목 가집계 API입니다.
|
||||
한국투자 HTS(eFriend Plus) > [0430] 외국계 매매종목 가집계 화면의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.
|
||||
|
||||
Args:
|
||||
fid_cond_mrkt_div_code (str): [필수] 조건시장분류코드 (ex. J)
|
||||
fid_cond_scr_div_code (str): [필수] 조건화면분류코드 (ex. 16441)
|
||||
fid_input_iscd (str): [필수] 입력종목코드 (ex. 0000:전체, 1001:코스피, 2001:코스닥)
|
||||
fid_rank_sort_cls_code (str): [필수] 순위정렬구분코드 (ex. 0:금액순, 1:수량순)
|
||||
fid_rank_sort_cls_code_2 (str): [필수] 순위정렬구분코드2 (ex. 0:매수순, 1:매도순)
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: 외국계 매매종목 가집계 데이터
|
||||
|
||||
Example:
|
||||
>>> df = frgnmem_trade_estimate("J", "16441", "0000", "0", "0")
|
||||
>>> print(df)
|
||||
"""
|
||||
|
||||
if fid_cond_mrkt_div_code == "":
|
||||
raise ValueError("fid_cond_mrkt_div_code is required (e.g. 'J')")
|
||||
|
||||
if fid_cond_scr_div_code == "":
|
||||
raise ValueError("fid_cond_scr_div_code is required (e.g. '16441')")
|
||||
|
||||
if fid_input_iscd == "":
|
||||
raise ValueError("fid_input_iscd is required (e.g. '0000')")
|
||||
|
||||
if fid_rank_sort_cls_code == "":
|
||||
raise ValueError("fid_rank_sort_cls_code is required (e.g. '0')")
|
||||
|
||||
if fid_rank_sort_cls_code_2 == "":
|
||||
raise ValueError("fid_rank_sort_cls_code_2 is required (e.g. '0')")
|
||||
|
||||
tr_id = "FHKST644100C0"
|
||||
|
||||
params = {
|
||||
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code,
|
||||
"FID_COND_SCR_DIV_CODE": fid_cond_scr_div_code,
|
||||
"FID_INPUT_ISCD": fid_input_iscd,
|
||||
"FID_RANK_SORT_CLS_CODE": fid_rank_sort_cls_code,
|
||||
"FID_RANK_SORT_CLS_CODE_2": fid_rank_sort_cls_code_2
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, "", params)
|
||||
|
||||
if res.isOK():
|
||||
current_data = pd.DataFrame(res.getBody().output)
|
||||
return current_data
|
||||
else:
|
||||
res.printError(url=API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,131 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-07-10
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from frgnmem_trade_trend import frgnmem_trade_trend
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 기본시세 > 회원사 실 시간 매매동향(틱)[국내주식-163]
|
||||
##############################################################################################
|
||||
|
||||
# 통합 컬럼 매핑
|
||||
COLUMN_MAPPING = {
|
||||
'total_seln_qty': '총매도수량',
|
||||
'total_shnu_qty': '총매수2수량',
|
||||
'bsop_hour': '영업시간',
|
||||
'hts_kor_isnm': 'HTS한글종목명',
|
||||
'stck_prpr': '주식현재가',
|
||||
'prdy_vrss': '전일대비',
|
||||
'prdy_vrss_sign': '전일대비부호',
|
||||
'cntg_vol': '체결거래량',
|
||||
'acml_ntby_qty': '누적순매수수량',
|
||||
'glob_ntby_qty': '외국계순매수수량',
|
||||
'frgn_ntby_qty_icdc': '외국인순매수수량증감'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 시세분석
|
||||
회원사 실 시간 매매동향(틱)[국내주식-163]
|
||||
|
||||
회원사 실 시간 매매동향(틱) 테스트 함수
|
||||
|
||||
Parameters:
|
||||
- fid_cond_scr_div_code (str): 화면분류코드 (20432(primary key))
|
||||
- fid_cond_mrkt_div_code (str): 조건시장구분코드 (J 고정입력)
|
||||
- fid_input_iscd (str): 종목코드 (ex. 005930(삼성전자) ※ FID_INPUT_ISCD(종목코드) 혹은 FID_MRKT_CLS_CODE(시장구분코드) 둘 중 하나만 입력)
|
||||
- fid_input_iscd_2 (str): 회원사코드 (ex. 99999(전체) ※ 회원사코드 (kis developers 포탈 사이트 포럼-> FAQ -> 종목정보 다운로드(국내) 참조))
|
||||
- fid_mrkt_cls_code (str): 시장구분코드 (A(전체),K(코스피), Q(코스닥), K2(코스피200), W(ELW) ※ FID_INPUT_ISCD(종목코드) 혹은 FID_MRKT_CLS_CODE(시장구분코드) 둘 중 하나만 입력)
|
||||
- fid_vol_cnt (str): 거래량 (거래량 ~)
|
||||
|
||||
Returns:
|
||||
- DataFrame: 회원사 실 시간 매매동향(틱) 결과
|
||||
|
||||
Example:
|
||||
>>> df1, df2 = frgnmem_trade_trend(fid_cond_mrkt_div_code="J", fid_cond_scr_div_code="20432", fid_input_iscd="005930", fid_input_iscd_2="99999", fid_mrkt_cls_code="A", fid_vol_cnt="1000")
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
|
||||
# API 호출
|
||||
result1, result2 = frgnmem_trade_trend(
|
||||
fid_cond_scr_div_code="20432", # 화면분류코드
|
||||
fid_cond_mrkt_div_code="J", # 조건시장구분코드
|
||||
fid_input_iscd="005930", # 종목코드
|
||||
fid_input_iscd_2="99999", # 회원사코드
|
||||
fid_mrkt_cls_code="A", # 시장구분코드
|
||||
fid_vol_cnt="", # 거래량
|
||||
)
|
||||
|
||||
# 결과 확인
|
||||
results = [result1, result2]
|
||||
if all(result is None or result.empty for result in results):
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# output1 결과 처리
|
||||
logger.info("=== output1 조회 ===")
|
||||
if not result1.empty:
|
||||
logger.info("사용 가능한 컬럼: %s", result1.columns.tolist())
|
||||
|
||||
# 통합 컬럼명 한글 변환 (필요한 컬럼만 자동 매핑됨)
|
||||
result1 = result1.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result1.columns:
|
||||
result1[col] = pd.to_numeric(result1[col], errors='coerce').round(2)
|
||||
|
||||
logger.info("output1 결과:")
|
||||
print(result1)
|
||||
else:
|
||||
logger.info("output1 데이터가 없습니다.")
|
||||
|
||||
# output2 결과 처리
|
||||
logger.info("=== output2 조회 ===")
|
||||
if not result2.empty:
|
||||
logger.info("사용 가능한 컬럼: %s", result2.columns.tolist())
|
||||
|
||||
# 통합 컬럼명 한글 변환 (필요한 컬럼만 자동 매핑됨)
|
||||
result2 = result2.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result2.columns:
|
||||
result2[col] = pd.to_numeric(result2[col], errors='coerce').round(2)
|
||||
|
||||
logger.info("output2 결과:")
|
||||
print(result2)
|
||||
else:
|
||||
logger.info("output2 데이터가 없습니다.")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,171 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-07-10
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional, Tuple
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 기본시세 > 회원사 실 시간 매매동향(틱)[국내주식-163]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/frgnmem-trade-trend"
|
||||
|
||||
def frgnmem_trade_trend(
|
||||
fid_cond_scr_div_code: str, # 화면분류코드
|
||||
fid_cond_mrkt_div_code: str, # 조건시장구분코드
|
||||
fid_input_iscd: str, # 종목코드
|
||||
fid_input_iscd_2: str, # 회원사코드
|
||||
fid_mrkt_cls_code: str, # 시장구분코드
|
||||
fid_vol_cnt: str, # 거래량
|
||||
dataframe1: Optional[pd.DataFrame] = None, # 누적 데이터프레임 (output1)
|
||||
dataframe2: Optional[pd.DataFrame] = None, # 누적 데이터프레임 (output2)
|
||||
tr_cont: str = "",
|
||||
depth: int = 0,
|
||||
max_depth: int = 10
|
||||
) -> Tuple[pd.DataFrame, pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 시세분석
|
||||
회원사 실 시간 매매동향(틱)[국내주식-163]
|
||||
회원사 실 시간 매매동향(틱) API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
fid_cond_scr_div_code (str): 20432(primary key)
|
||||
fid_cond_mrkt_div_code (str): J 고정입력
|
||||
fid_input_iscd (str): ex. 005930(삼성전자) ※ FID_INPUT_ISCD(종목코드) 혹은 FID_MRKT_CLS_CODE(시장구분코드) 둘 중 하나만 입력
|
||||
fid_input_iscd_2 (str): ex. 99999(전체) ※ 회원사코드 (kis developers 포탈 사이트 포럼-> FAQ -> 종목정보 다운로드(국내) 참조)
|
||||
fid_mrkt_cls_code (str): A(전체),K(코스피), Q(코스닥), K2(코스피200), W(ELW) ※ FID_INPUT_ISCD(종목코드) 혹은 FID_MRKT_CLS_CODE(시장구분코드) 둘 중 하나만 입력
|
||||
fid_vol_cnt (str): 거래량 ~
|
||||
dataframe1 (Optional[pd.DataFrame]): 누적 데이터프레임 (output1)
|
||||
dataframe2 (Optional[pd.DataFrame]): 누적 데이터프레임 (output2)
|
||||
tr_cont (str): 연속 거래 여부
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Tuple[pd.DataFrame, pd.DataFrame]: 회원사 실 시간 매매동향(틱) 데이터
|
||||
|
||||
Example:
|
||||
>>> df1, df2 = frgnmem_trade_trend(
|
||||
... fid_cond_scr_div_code="20432",
|
||||
... fid_cond_mrkt_div_code="J",
|
||||
... fid_input_iscd="005930",
|
||||
... fid_input_iscd_2="99999",
|
||||
... fid_mrkt_cls_code="A",
|
||||
... fid_vol_cnt="1000"
|
||||
... )
|
||||
>>> print(df1)
|
||||
>>> print(df2)
|
||||
"""
|
||||
# [필수 파라미터 검증]
|
||||
if not fid_cond_scr_div_code:
|
||||
logger.error("fid_cond_scr_div_code is required. (e.g. '20432')")
|
||||
raise ValueError("fid_cond_scr_div_code is required. (e.g. '20432')")
|
||||
if not fid_cond_mrkt_div_code or fid_cond_mrkt_div_code != "J":
|
||||
logger.error("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
raise ValueError("fid_cond_mrkt_div_code is required. (e.g. 'J')")
|
||||
if not fid_input_iscd:
|
||||
logger.error("fid_input_iscd is required. (e.g. '005930')")
|
||||
raise ValueError("fid_input_iscd is required. (e.g. '005930')")
|
||||
if not fid_input_iscd_2:
|
||||
logger.error("fid_input_iscd_2 is required. (e.g. '99999')")
|
||||
raise ValueError("fid_input_iscd_2 is required. (e.g. '99999')")
|
||||
if not fid_mrkt_cls_code:
|
||||
logger.error("fid_mrkt_cls_code is required. (e.g. 'A')")
|
||||
raise ValueError("fid_mrkt_cls_code is required. (e.g. 'A')")
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe1 if dataframe1 is not None else pd.DataFrame(), dataframe2 if dataframe2 is not None else pd.DataFrame()
|
||||
|
||||
tr_id = "FHPST04320000"
|
||||
|
||||
params = {
|
||||
"FID_COND_SCR_DIV_CODE": fid_cond_scr_div_code,
|
||||
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code,
|
||||
"FID_INPUT_ISCD": fid_input_iscd,
|
||||
"FID_INPUT_ISCD_2": fid_input_iscd_2,
|
||||
"FID_MRKT_CLS_CODE": fid_mrkt_cls_code,
|
||||
"FID_VOL_CNT": fid_vol_cnt,
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
# output1 처리
|
||||
if hasattr(res.getBody(), 'output1'):
|
||||
output_data = res.getBody().output1
|
||||
if output_data:
|
||||
# output1은 단일 객체, output2는 배열일 수 있음
|
||||
if isinstance(output_data, list):
|
||||
current_data1 = pd.DataFrame(output_data)
|
||||
else:
|
||||
# 단일 객체인 경우 리스트로 감싸서 DataFrame 생성
|
||||
current_data1 = pd.DataFrame([output_data])
|
||||
|
||||
if dataframe1 is not None:
|
||||
dataframe1 = pd.concat([dataframe1, current_data1], ignore_index=True)
|
||||
else:
|
||||
dataframe1 = current_data1
|
||||
else:
|
||||
if dataframe1 is None:
|
||||
dataframe1 = pd.DataFrame()
|
||||
else:
|
||||
if dataframe1 is None:
|
||||
dataframe1 = pd.DataFrame()
|
||||
# output2 처리
|
||||
if hasattr(res.getBody(), 'output2'):
|
||||
output_data = res.getBody().output2
|
||||
if output_data:
|
||||
# output1은 단일 객체, output2는 배열일 수 있음
|
||||
if isinstance(output_data, list):
|
||||
current_data2 = pd.DataFrame(output_data)
|
||||
else:
|
||||
# 단일 객체인 경우 리스트로 감싸서 DataFrame 생성
|
||||
current_data2 = pd.DataFrame([output_data])
|
||||
|
||||
if dataframe2 is not None:
|
||||
dataframe2 = pd.concat([dataframe2, current_data2], ignore_index=True)
|
||||
else:
|
||||
dataframe2 = current_data2
|
||||
else:
|
||||
if dataframe2 is None:
|
||||
dataframe2 = pd.DataFrame()
|
||||
else:
|
||||
if dataframe2 is None:
|
||||
dataframe2 = pd.DataFrame()
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
|
||||
if tr_cont in ["M", "F"]:
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return frgnmem_trade_trend(
|
||||
fid_cond_scr_div_code,
|
||||
fid_input_iscd,
|
||||
fid_input_iscd_2,
|
||||
fid_mrkt_cls_code,
|
||||
fid_vol_cnt,
|
||||
"N", dataframe1, dataframe2, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe1, dataframe2
|
||||
else:
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame(), pd.DataFrame()
|
||||
@@ -0,0 +1,87 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.']) # kis_auth 파일 경로 추가
|
||||
import kis_auth as ka
|
||||
from hts_top_view import hts_top_view
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > HTS조회상위20종목[국내주식-214]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'output1': '응답상세',
|
||||
'mrkt_div_cls_code': '시장구분',
|
||||
'mksc_shrn_iscd': '종목코드'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
def main():
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
HTS조회상위20종목[국내주식-214]
|
||||
|
||||
HTS조회상위20종목 테스트 함수
|
||||
|
||||
Parameters:
|
||||
|
||||
Returns:
|
||||
- DataFrame: HTS조회상위20종목 결과
|
||||
|
||||
Example:
|
||||
>>> df = hts_top_view()
|
||||
"""
|
||||
try:
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 토큰 발급
|
||||
logger.info("토큰 발급 중...")
|
||||
ka.auth()
|
||||
logger.info("토큰 발급 완료")
|
||||
|
||||
# API 호출
|
||||
logger.info("API 호출 시작: HTS조회상위20종목")
|
||||
result = hts_top_view( )
|
||||
|
||||
if result is None or result.empty:
|
||||
logger.warning("조회된 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# 컬럼명 출력
|
||||
logger.info("사용 가능한 컬럼 목록:")
|
||||
logger.info(result.columns.tolist())
|
||||
|
||||
# 한글 컬럼명으로 변환
|
||||
result = result.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce').round(2)
|
||||
|
||||
# 결과 출력
|
||||
logger.info("=== HTS조회상위20종목 결과 ===")
|
||||
logger.info("조회된 데이터 건수: %d", len(result))
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("에러 발생: %s", str(e))
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,98 @@
|
||||
"""
|
||||
Created on 2025-06-17
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 순위분석 > HTS조회상위20종목[국내주식-214]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/ranking/hts-top-view"
|
||||
|
||||
|
||||
def hts_top_view(
|
||||
tr_cont: str = "",
|
||||
dataframe: Optional[pd.DataFrame] = None,
|
||||
depth: int = 0,
|
||||
max_depth: int = 10
|
||||
) -> Optional[pd.DataFrame]:
|
||||
"""
|
||||
[국내주식] 순위분석
|
||||
HTS조회상위20종목[국내주식-214]
|
||||
HTS조회상위20종목 API를 호출하여 DataFrame으로 반환합니다.
|
||||
|
||||
Args:
|
||||
tr_cont (str): 연속 거래 여부 ("공백": 초기 조회, "N": 다음 데이터 조회)
|
||||
dataframe (Optional[pd.DataFrame]): 누적 데이터프레임
|
||||
depth (int): 현재 재귀 깊이
|
||||
max_depth (int): 최대 재귀 깊이 (기본값: 10)
|
||||
|
||||
Returns:
|
||||
Optional[pd.DataFrame]: HTS조회상위20종목 데이터
|
||||
|
||||
Example:
|
||||
>>> df = hts_top_view(tr_cont="", dataframe=None, depth=0, max_depth=10)
|
||||
>>> print(df)
|
||||
"""
|
||||
# 로깅 설정
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 최대 재귀 깊이 체크
|
||||
if depth >= max_depth:
|
||||
logger.warning("Maximum recursion depth (%d) reached. Stopping further requests.", max_depth)
|
||||
return dataframe if dataframe is not None else pd.DataFrame()
|
||||
|
||||
|
||||
tr_id = "HHMCM000100C0"
|
||||
|
||||
# Request Query Parameter가 없으므로 빈 딕셔너리로 유지
|
||||
params = {}
|
||||
|
||||
# API 호출
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
# 응답 데이터 처리
|
||||
if hasattr(res.getBody(), 'output1'):
|
||||
current_data = pd.DataFrame(res.getBody().output1)
|
||||
else:
|
||||
current_data = pd.DataFrame()
|
||||
|
||||
# 데이터프레임 병합
|
||||
if dataframe is not None:
|
||||
dataframe = pd.concat([dataframe, current_data], ignore_index=True)
|
||||
else:
|
||||
dataframe = current_data
|
||||
|
||||
# 다음 페이지 호출 여부 결정
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
if tr_cont == "M":
|
||||
logger.info("Calling next page...")
|
||||
ka.smart_sleep()
|
||||
return hts_top_view(
|
||||
"N", dataframe, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logger.info("Data fetch complete.")
|
||||
return dataframe
|
||||
else:
|
||||
# API 호출 실패 시 에러 로그 출력
|
||||
logger.error("API call failed: %s - %s", res.getErrorCode(), res.getErrorMessage())
|
||||
res.printError(API_URL)
|
||||
return pd.DataFrame()
|
||||
@@ -0,0 +1,124 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from index_ccnl import index_ccnl
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내지수 실시간체결 [실시간-026]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
"bstp_cls_code": "업종 구분 코드",
|
||||
"bsop_hour": "영업 시간",
|
||||
"prpr_nmix": "현재가 지수",
|
||||
"prdy_vrss_sign": "전일 대비 부호",
|
||||
"bstp_nmix_prdy_vrss": "업종 지수 전일 대비",
|
||||
"acml_vol": "누적 거래량",
|
||||
"acml_tr_pbmn": "누적 거래 대금",
|
||||
"pcas_vol": "건별 거래량",
|
||||
"pcas_tr_pbmn": "건별 거래 대금",
|
||||
"prdy_ctrt": "전일 대비율",
|
||||
"oprc_nmix": "시가 지수",
|
||||
"nmix_hgpr": "지수 최고가",
|
||||
"nmix_lwpr": "지수 최저가",
|
||||
"oprc_vrss_nmix_prpr": "시가 대비 지수 현재가",
|
||||
"oprc_vrss_nmix_sign": "시가 대비 지수 부호",
|
||||
"hgpr_vrss_nmix_prpr": "최고가 대비 지수 현재가",
|
||||
"hgpr_vrss_nmix_sign": "최고가 대비 지수 부호",
|
||||
"lwpr_vrss_nmix_prpr": "최저가 대비 지수 현재가",
|
||||
"lwpr_vrss_nmix_sign": "최저가 대비 지수 부호",
|
||||
"prdy_clpr_vrss_oprc_rate": "전일 종가 대비 시가2 비율",
|
||||
"prdy_clpr_vrss_hgpr_rate": "전일 종가 대비 최고가 비율",
|
||||
"prdy_clpr_vrss_lwpr_rate": "전일 종가 대비 최저가 비율",
|
||||
"uplm_issu_cnt": "상한 종목 수",
|
||||
"ascn_issu_cnt": "상승 종목 수",
|
||||
"stnr_issu_cnt": "보합 종목 수",
|
||||
"down_issu_cnt": "하락 종목 수",
|
||||
"lslm_issu_cnt": "하한 종목 수",
|
||||
"qtqt_ascn_issu_cnt": "기세 상승 종목수",
|
||||
"qtqt_down_issu_cnt": "기세 하락 종목수",
|
||||
"tick_vrss": "TICK대비"
|
||||
}
|
||||
NUMERIC_COLUMNS = [
|
||||
"현재가 지수", "업종 지수 전일 대비", "누적 거래량", "누적 거래 대금", "건별 거래량", "건별 거래 대금",
|
||||
"전일 대비율", "시가 지수", "지수 최고가", "지수 최저가", "시가 대비 지수 현재가",
|
||||
"최고가 대비 지수 현재가", "최저가 대비 지수 현재가", "전일 종가 대비 시가2 비율",
|
||||
"전일 종가 대비 최고가 비율", "전일 종가 대비 최저가 비율", "상한 종목 수", "상승 종목 수",
|
||||
"보합 종목 수", "하락 종목 수", "하한 종목 수", "기세 상승 종목수", "기세 하락 종목수", "TICK대비"
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내지수 실시간체결
|
||||
|
||||
[참고자료]
|
||||
종목코드 마스터파일 파이썬 정제코드는 한국투자증권 Github 참고 부탁드립니다.
|
||||
https://github.com/koreainvestment/open-trading-api/tree/main/stocks_info
|
||||
|
||||
[호출 데이터]
|
||||
헤더와 바디 값을 합쳐 JSON 형태로 전송합니다.
|
||||
|
||||
[응답 데이터]
|
||||
1. 정상 등록 여부 (JSON)
|
||||
- JSON["body"]["msg1"] - 정상 응답 시, SUBSCRIBE SUCCESS
|
||||
- JSON["body"]["output"]["iv"] - 실시간 결과 복호화에 필요한 AES256 IV (Initialize Vector)
|
||||
- JSON["body"]["output"]["key"] - 실시간 결과 복호화에 필요한 AES256 Key
|
||||
|
||||
2. 실시간 결과 응답 ( | 로 구분되는 값)
|
||||
ex) 0|H0STCNT0|004|005930^123929^73100^5^...
|
||||
- 암호화 유무 : 0 암호화 되지 않은 데이터 / 1 암호화된 데이터
|
||||
- TR_ID : 등록한 tr_id (ex. H0STCNT0)
|
||||
- 데이터 건수 : (ex. 001 인 경우 데이터 건수 1건, 004인 경우 데이터 건수 4건)
|
||||
- 응답 데이터 : 아래 response 데이터 참조 ( ^로 구분됨)
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
ka.auth_ws()
|
||||
|
||||
# 인증(auth_ws()) 이후에 선언
|
||||
kws = ka.KISWebSocket(api_url="/tryitout")
|
||||
|
||||
# 조회
|
||||
kws.subscribe(request=index_ccnl, data=["0001", "0128"])
|
||||
|
||||
# 결과 표시
|
||||
def on_result(ws, tr_id: str, result: pd.DataFrame, data_map: dict):
|
||||
try:
|
||||
# 컬럼 매핑
|
||||
result.rename(columns=COLUMN_MAPPING, inplace=True)
|
||||
|
||||
# 숫자형 컬럼 변환
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce')
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
except Exception as e:
|
||||
logging.error(f"결과 처리 중 오류: {e}")
|
||||
logging.error(f"받은 데이터: {result}")
|
||||
|
||||
kws.start(on_result=on_result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,73 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내지수 실시간체결 [실시간-026]
|
||||
##############################################################################################
|
||||
|
||||
def index_ccnl(
|
||||
tr_type: str,
|
||||
tr_key: str,
|
||||
) -> tuple[dict, list[str]]:
|
||||
"""
|
||||
국내지수 실시간체결[H0UPCNT0] 구독 함수
|
||||
|
||||
이 함수는 한국투자증권의 웹소켓 API를 통해 국내지수의 실시간 데이터를 구독합니다.
|
||||
실시간 데이터는 웹소켓을 통해 지속적으로 업데이트되며, 구독을 통해 실시간으로 데이터를 수신할 수 있습니다.
|
||||
|
||||
Args:
|
||||
tr_type (str): [필수] 구독 등록("1") 또는 해제("0") 여부를 나타내는 값
|
||||
tr_key (str): [필수] 종목코드 (빈 문자열 불가)
|
||||
|
||||
Returns:
|
||||
message (dict): 메시지 데이터
|
||||
columns (list[str]): 응답 데이터의 컬럼 정보
|
||||
|
||||
Raises:
|
||||
ValueError: tr_key가 빈 문자열인 경우 발생
|
||||
|
||||
Example:
|
||||
>>> msg, columns = subscribe_realtime_index("1", "005930")
|
||||
>>> print(msg, columns)
|
||||
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not tr_key:
|
||||
raise ValueError("tr_key는 필수 입력값입니다.")
|
||||
|
||||
tr_id = "H0UPCNT0"
|
||||
|
||||
params = {
|
||||
"tr_key": tr_key,
|
||||
}
|
||||
|
||||
# 데이터 구독 요청
|
||||
msg = ka.data_fetch(tr_id, tr_type, params)
|
||||
|
||||
# 응답 데이터 컬럼 정보
|
||||
columns = [
|
||||
"bstp_cls_code", "bsop_hour", "prpr_nmix", "prdy_vrss_sign",
|
||||
"bstp_nmix_prdy_vrss", "acml_vol", "acml_tr_pbmn", "pcas_vol",
|
||||
"pcas_tr_pbmn", "prdy_ctrt", "oprc_nmix", "nmix_hgpr", "nmix_lwpr",
|
||||
"oprc_vrss_nmix_prpr", "oprc_vrss_nmix_sign", "hgpr_vrss_nmix_prpr",
|
||||
"hgpr_vrss_nmix_sign", "lwpr_vrss_nmix_prpr", "lwpr_vrss_nmix_sign",
|
||||
"prdy_clpr_vrss_oprc_rate", "prdy_clpr_vrss_hgpr_rate",
|
||||
"prdy_clpr_vrss_lwpr_rate", "uplm_issu_cnt", "ascn_issu_cnt",
|
||||
"stnr_issu_cnt", "down_issu_cnt", "lslm_issu_cnt", "qtqt_ascn_issu_cnt",
|
||||
"qtqt_down_issu_cnt", "tick_vrss"
|
||||
]
|
||||
|
||||
return msg, columns
|
||||
@@ -0,0 +1,128 @@
|
||||
"""
|
||||
Created on 2025-07-08
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from index_exp_ccnl import index_exp_ccnl
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내지수 실시간예상체결 [실시간-027]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
"bstp_cls_code": "업종 구분 코드",
|
||||
"bsop_hour": "영업 시간",
|
||||
"prpr_nmix": "현재가 지수",
|
||||
"prdy_vrss_sign": "전일 대비 부호",
|
||||
"bstp_nmix_prdy_vrss": "업종 지수 전일 대비",
|
||||
"acml_vol": "누적 거래량",
|
||||
"acml_tr_pbmn": "누적 거래 대금",
|
||||
"pcas_vol": "건별 거래량",
|
||||
"pcas_tr_pbmn": "건별 거래 대금",
|
||||
"prdy_ctrt": "전일 대비율",
|
||||
"oprc_nmix": "시가 지수",
|
||||
"nmix_hgpr": "지수 최고가",
|
||||
"nmix_lwpr": "지수 최저가",
|
||||
"oprc_vrss_nmix_prpr": "시가 대비 지수 현재가",
|
||||
"oprc_vrss_nmix_sign": "시가 대비 지수 부호",
|
||||
"hgpr_vrss_nmix_prpr": "최고가 대비 지수 현재가",
|
||||
"hgpr_vrss_nmix_sign": "최고가 대비 지수 부호",
|
||||
"lwpr_vrss_nmix_prpr": "최저가 대비 지수 현재가",
|
||||
"lwpr_vrss_nmix_sign": "최저가 대비 지수 부호",
|
||||
"prdy_clpr_vrss_oprc_rate": "전일 종가 대비 시가2 비율",
|
||||
"prdy_clpr_vrss_hgpr_rate": "전일 종가 대비 최고가 비율",
|
||||
"prdy_clpr_vrss_lwpr_rate": "전일 종가 대비 최저가 비율",
|
||||
"uplm_issu_cnt": "상한 종목 수",
|
||||
"ascn_issu_cnt": "상승 종목 수",
|
||||
"stnr_issu_cnt": "보합 종목 수",
|
||||
"down_issu_cnt": "하락 종목 수",
|
||||
"lslm_issu_cnt": "하한 종목 수",
|
||||
"qtqt_ascn_issu_cnt": "기세 상승 종목수",
|
||||
"qtqt_down_issu_cnt": "기세 하락 종목수",
|
||||
"tick_vrss": "TICK대비"
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = [
|
||||
"현재가 지수", "업종 지수 전일 대비", "누적 거래량", "누적 거래 대금",
|
||||
"건별 거래량", "건별 거래 대금", "전일 대비율", "시가 지수",
|
||||
"지수 최고가", "지수 최저가", "시가 대비 지수 현재가",
|
||||
"최고가 대비 지수 현재가", "최저가 대비 지수 현재가",
|
||||
"전일 종가 대비 시가2 비율", "전일 종가 대비 최고가 비율",
|
||||
"전일 종가 대비 최저가 비율", "상한 종목 수", "상승 종목 수",
|
||||
"보합 종목 수", "하락 종목 수", "하한 종목 수",
|
||||
"기세 상승 종목수", "기세 하락 종목수", "TICK대비"
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내지수 실시간예상체결
|
||||
|
||||
[참고자료]
|
||||
종목코드 마스터파일 파이썬 정제코드는 한국투자증권 Github 참고 부탁드립니다.
|
||||
https://github.com/koreainvestment/open-trading-api/tree/main/stocks_info
|
||||
|
||||
[호출 데이터]
|
||||
헤더와 바디 값을 합쳐 JSON 형태로 전송합니다.
|
||||
|
||||
[응답 데이터]
|
||||
1. 정상 등록 여부 (JSON)
|
||||
- JSON["body"]["msg1"] - 정상 응답 시, SUBSCRIBE SUCCESS
|
||||
- JSON["body"]["output"]["iv"] - 실시간 결과 복호화에 필요한 AES256 IV (Initialize Vector)
|
||||
- JSON["body"]["output"]["key"] - 실시간 결과 복호화에 필요한 AES256 Key
|
||||
|
||||
2. 실시간 결과 응답 ( | 로 구분되는 값)
|
||||
ex) 0|H0STCNT0|004|005930^123929^73100^5^...
|
||||
- 암호화 유무 : 0 암호화 되지 않은 데이터 / 1 암호화된 데이터
|
||||
- TR_ID : 등록한 tr_id (ex. H0STCNT0)
|
||||
- 데이터 건수 : (ex. 001 인 경우 데이터 건수 1건, 004인 경우 데이터 건수 4건)
|
||||
- 응답 데이터 : 아래 response 데이터 참조 ( ^로 구분됨)
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
ka.auth_ws()
|
||||
|
||||
# 인증(auth_ws()) 이후에 선언
|
||||
kws = ka.KISWebSocket(api_url="/tryitout")
|
||||
|
||||
# 조회
|
||||
kws.subscribe(request=index_exp_ccnl, data=["0001"])
|
||||
|
||||
# 결과 표시
|
||||
def on_result(ws, tr_id: str, result: pd.DataFrame, data_map: dict):
|
||||
try:
|
||||
# 컬럼명 매핑
|
||||
result.rename(columns=COLUMN_MAPPING, inplace=True)
|
||||
|
||||
# 숫자형 컬럼 변환
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result.columns:
|
||||
result[col] = pd.to_numeric(result[col], errors='coerce')
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
except Exception as e:
|
||||
logging.error(f"결과 처리 중 오류: {e}")
|
||||
logging.error(f"받은 데이터: {result}")
|
||||
|
||||
kws.start(on_result=on_result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,72 @@
|
||||
"""
|
||||
Created on 2025-07-08
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내지수 실시간예상체결 [실시간-027]
|
||||
##############################################################################################
|
||||
|
||||
def index_exp_ccnl(
|
||||
tr_type: str,
|
||||
tr_key: str,
|
||||
) -> tuple[dict, list[str]]:
|
||||
"""
|
||||
국내지수 실시간예상체결[H0UPANC0] 구독 함수
|
||||
|
||||
이 함수는 한국투자증권 웹소켓 API를 통해 국내지수의 실시간 데이터를 구독합니다.
|
||||
실시간 데이터는 웹소켓을 통해 지속적으로 업데이트되며, 구독 등록/해제 여부와 종목코드를 통해 데이터를 필터링합니다.
|
||||
|
||||
Args:
|
||||
tr_type (str): [필수] 구독 등록("1") 또는 해제("0") 여부를 나타내는 문자열
|
||||
tr_key (str): [필수] 종목코드를 나타내는 문자열. 빈 문자열일 수 없습니다.
|
||||
|
||||
Returns:
|
||||
message (dict): 실시간 데이터 구독에 대한 응답 메시지
|
||||
columns (list[str]): 실시간 데이터의 컬럼 정보 리스트
|
||||
|
||||
Raises:
|
||||
ValueError: tr_key가 빈 문자열인 경우 발생
|
||||
|
||||
Example:
|
||||
>>> msg, columns = index_exp_ccnl("1", "005930")
|
||||
>>> print(msg, columns)
|
||||
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not tr_key:
|
||||
raise ValueError("tr_key is required and cannot be an empty string")
|
||||
|
||||
tr_id = "H0UPANC0"
|
||||
|
||||
params = {
|
||||
"tr_key": tr_key,
|
||||
}
|
||||
|
||||
# 데이터 구독 요청
|
||||
msg = ka.data_fetch(tr_id, tr_type, params)
|
||||
|
||||
# 응답 데이터 컬럼 정보
|
||||
columns = [
|
||||
"bstp_cls_code", "bsop_hour", "prpr_nmix", "prdy_vrss_sign",
|
||||
"bstp_nmix_prdy_vrss", "acml_vol", "acml_tr_pbmn", "pcas_vol",
|
||||
"pcas_tr_pbmn", "prdy_ctrt", "oprc_nmix", "nmix_hgpr", "nmix_lwpr",
|
||||
"oprc_vrss_nmix_prpr", "oprc_vrss_nmix_sign", "hgpr_vrss_nmix_prpr",
|
||||
"hgpr_vrss_nmix_sign", "lwpr_vrss_nmix_prpr", "lwpr_vrss_nmix_sign",
|
||||
"prdy_clpr_vrss_oprc_rate", "prdy_clpr_vrss_hgpr_rate",
|
||||
"prdy_clpr_vrss_lwpr_rate", "uplm_issu_cnt", "ascn_issu_cnt",
|
||||
"stnr_issu_cnt", "down_issu_cnt", "lslm_issu_cnt",
|
||||
"qtqt_ascn_issu_cnt", "qtqt_down_issu_cnt", "tick_vrss"
|
||||
]
|
||||
|
||||
return msg, columns
|
||||
@@ -0,0 +1,215 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from index_program_trade import index_program_trade
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내지수 실시간프로그램매매 [실시간-028]
|
||||
##############################################################################################
|
||||
|
||||
# 컬럼명 매핑
|
||||
COLUMN_MAPPING = {
|
||||
"bstp_cls_code": "업종 구분 코드",
|
||||
"bsop_hour": "영업 시간",
|
||||
"arbt_seln_entm_cnqn": "차익 매도 위탁 체결량",
|
||||
"arbt_seln_onsl_cnqn": "차익 매도 자기 체결량",
|
||||
"arbt_shnu_entm_cnqn": "차익 매수2 위탁 체결량",
|
||||
"arbt_shnu_onsl_cnqn": "차익 매수2 자기 체결량",
|
||||
"nabt_seln_entm_cnqn": "비차익 매도 위탁 체결량",
|
||||
"nabt_seln_onsl_cnqn": "비차익 매도 자기 체결량",
|
||||
"nabt_shnu_entm_cnqn": "비차익 매수2 위탁 체결량",
|
||||
"nabt_shnu_onsl_cnqn": "비차익 매수2 자기 체결량",
|
||||
"arbt_seln_entm_cntg_amt": "차익 매도 위탁 체결 금액",
|
||||
"arbt_seln_onsl_cntg_amt": "차익 매도 자기 체결 금액",
|
||||
"arbt_shnu_entm_cntg_amt": "차익 매수2 위탁 체결 금액",
|
||||
"arbt_shnu_onsl_cntg_amt": "차익 매수2 자기 체결 금액",
|
||||
"nabt_seln_entm_cntg_amt": "비차익 매도 위탁 체결 금액",
|
||||
"nabt_seln_onsl_cntg_amt": "비차익 매도 자기 체결 금액",
|
||||
"nabt_shnu_entm_cntg_amt": "비차익 매수2 위탁 체결 금액",
|
||||
"nabt_shnu_onsl_cntg_amt": "비차익 매수2 자기 체결 금액",
|
||||
"arbt_smtn_seln_vol": "차익 합계 매도 거래량",
|
||||
"arbt_smtm_seln_vol_rate": "차익 합계 매도 거래량 비율",
|
||||
"arbt_smtn_seln_tr_pbmn": "차익 합계 매도 거래 대금",
|
||||
"arbt_smtm_seln_tr_pbmn_rate": "차익 합계 매도 거래대금 비율",
|
||||
"arbt_smtn_shnu_vol": "차익 합계 매수2 거래량",
|
||||
"arbt_smtm_shnu_vol_rate": "차익 합계 매수 거래량 비율",
|
||||
"arbt_smtn_shnu_tr_pbmn": "차익 합계 매수2 거래 대금",
|
||||
"arbt_smtm_shnu_tr_pbmn_rate": "차익 합계 매수 거래대금 비율",
|
||||
"arbt_smtn_ntby_qty": "차익 합계 순매수 수량",
|
||||
"arbt_smtm_ntby_qty_rate": "차익 합계 순매수 수량 비율",
|
||||
"arbt_smtn_ntby_tr_pbmn": "차익 합계 순매수 거래 대금",
|
||||
"arbt_smtm_ntby_tr_pbmn_rate": "차익 합계 순매수 거래대금 비율",
|
||||
"nabt_smtn_seln_vol": "비차익 합계 매도 거래량",
|
||||
"nabt_smtm_seln_vol_rate": "비차익 합계 매도 거래량 비율",
|
||||
"nabt_smtn_seln_tr_pbmn": "비차익 합계 매도 거래 대금",
|
||||
"nabt_smtm_seln_tr_pbmn_rate": "비차익 합계 매도 거래대금 비율",
|
||||
"nabt_smtn_shnu_vol": "비차익 합계 매수2 거래량",
|
||||
"nabt_smtm_shnu_vol_rate": "비차익 합계 매수 거래량 비율",
|
||||
"nabt_smtn_shnu_tr_pbmn": "비차익 합계 매수2 거래 대금",
|
||||
"nabt_smtm_shnu_tr_pbmn_rate": "비차익 합계 매수 거래대금 비율",
|
||||
"nabt_smtn_ntby_qty": "비차익 합계 순매수 수량",
|
||||
"nabt_smtm_ntby_qty_rate": "비차익 합계 순매수 수량 비율",
|
||||
"nabt_smtn_ntby_tr_pbmn": "비차익 합계 순매수 거래 대금",
|
||||
"nabt_smtm_ntby_tr_pbmn_rate": "비차익 합계 순매수 거래대금 비율",
|
||||
"whol_entm_seln_vol": "전체 위탁 매도 거래량",
|
||||
"entm_seln_vol_rate": "위탁 매도 거래량 비율",
|
||||
"whol_entm_seln_tr_pbmn": "전체 위탁 매도 거래 대금",
|
||||
"entm_seln_tr_pbmn_rate": "위탁 매도 거래대금 비율",
|
||||
"whol_entm_shnu_vol": "전체 위탁 매수2 거래량",
|
||||
"entm_shnu_vol_rate": "위탁 매수 거래량 비율",
|
||||
"whol_entm_shnu_tr_pbmn": "전체 위탁 매수2 거래 대금",
|
||||
"entm_shnu_tr_pbmn_rate": "위탁 매수 거래대금 비율",
|
||||
"whol_entm_ntby_qt": "전체 위탁 순매수 수량",
|
||||
"entm_ntby_qty_rat": "위탁 순매수 수량 비율",
|
||||
"whol_entm_ntby_tr_pbmn": "전체 위탁 순매수 거래 대금",
|
||||
"entm_ntby_tr_pbmn_rate": "위탁 순매수 금액 비율",
|
||||
"whol_onsl_seln_vol": "전체 자기 매도 거래량",
|
||||
"onsl_seln_vol_rate": "자기 매도 거래량 비율",
|
||||
"whol_onsl_seln_tr_pbmn": "전체 자기 매도 거래 대금",
|
||||
"onsl_seln_tr_pbmn_rate": "자기 매도 거래대금 비율",
|
||||
"whol_onsl_shnu_vol": "전체 자기 매수2 거래량",
|
||||
"onsl_shnu_vol_rate": "자기 매수 거래량 비율",
|
||||
"whol_onsl_shnu_tr_pbmn": "전체 자기 매수2 거래 대금",
|
||||
"onsl_shnu_tr_pbmn_rate": "자기 매수 거래대금 비율",
|
||||
"whol_onsl_ntby_qty": "전체 자기 순매수 수량",
|
||||
"onsl_ntby_qty_rate": "자기 순매수량 비율",
|
||||
"whol_onsl_ntby_tr_pbmn": "전체 자기 순매수 거래 대금",
|
||||
"onsl_ntby_tr_pbmn_rate": "자기 순매수 대금 비율",
|
||||
"total_seln_qty": "총 매도 수량",
|
||||
"whol_seln_vol_rate": "전체 매도 거래량 비율",
|
||||
"total_seln_tr_pbmn": "총 매도 거래 대금",
|
||||
"whol_seln_tr_pbmn_rate": "전체 매도 거래대금 비율",
|
||||
"shnu_cntg_smtn": "총 매수 수량",
|
||||
"whol_shun_vol_rate": "전체 매수 거래량 비율",
|
||||
"total_shnu_tr_pbmn": "총 매수2 거래 대금",
|
||||
"whol_shun_tr_pbmn_rate": "전체 매수 거래대금 비율",
|
||||
"whol_ntby_qty": "전체 순매수 수량",
|
||||
"whol_smtm_ntby_qty_rate": "전체 합계 순매수 수량 비율",
|
||||
"whol_ntby_tr_pbmn": "전체 순매수 거래 대금",
|
||||
"whol_ntby_tr_pbmn_rate": "전체 순매수 거래대금 비율",
|
||||
"arbt_entm_ntby_qty": "차익 위탁 순매수 수량",
|
||||
"arbt_entm_ntby_tr_pbmn": "차익 위탁 순매수 거래 대금",
|
||||
"arbt_onsl_ntby_qty": "차익 자기 순매수 수량",
|
||||
"arbt_onsl_ntby_tr_pbmn": "차익 자기 순매수 거래 대금",
|
||||
"nabt_entm_ntby_qty": "비차익 위탁 순매수 수량",
|
||||
"nabt_entm_ntby_tr_pbmn": "비차익 위탁 순매수 거래 대금",
|
||||
"nabt_onsl_ntby_qty": "비차익 자기 순매수 수량",
|
||||
"nabt_onsl_ntby_tr_pbmn": "비차익 자기 순매수 거래 대금",
|
||||
"acml_vol": "누적 거래량",
|
||||
"acml_tr_pbmn": "누적 거래 대금"
|
||||
}
|
||||
|
||||
# 숫자형 컬럼 리스트
|
||||
NUMERIC_COLUMNS = [
|
||||
"arbt_seln_entm_cnqn", "arbt_seln_onsl_cnqn", "arbt_shnu_entm_cnqn", "arbt_shnu_onsl_cnqn",
|
||||
"nabt_seln_entm_cnqn", "nabt_seln_onsl_cnqn", "nabt_shnu_entm_cnqn", "nabt_shnu_onsl_cnqn",
|
||||
"arbt_seln_entm_cntg_amt", "arbt_seln_onsl_cntg_amt", "arbt_shnu_entm_cntg_amt", "arbt_shnu_onsl_cntg_amt",
|
||||
"nabt_seln_entm_cntg_amt", "nabt_seln_onsl_cntg_amt", "nabt_shnu_entm_cntg_amt", "nabt_shnu_onsl_cntg_amt",
|
||||
"arbt_smtn_seln_vol", "arbt_smtm_seln_vol_rate", "arbt_smtn_seln_tr_pbmn", "arbt_smtm_seln_tr_pbmn_rate",
|
||||
"arbt_smtn_shnu_vol", "arbt_smtm_shnu_vol_rate", "arbt_smtn_shnu_tr_pbmn", "arbt_smtm_shnu_tr_pbmn_rate",
|
||||
"arbt_smtn_ntby_qty", "arbt_smtm_ntby_qty_rate", "arbt_smtn_ntby_tr_pbmn", "arbt_smtm_ntby_tr_pbmn_rate",
|
||||
"nabt_smtn_seln_vol", "nabt_smtm_seln_vol_rate", "nabt_smtn_seln_tr_pbmn", "nabt_smtm_seln_tr_pbmn_rate",
|
||||
"nabt_smtn_shnu_vol", "nabt_smtm_shnu_vol_rate", "nabt_smtn_shnu_tr_pbmn", "nabt_smtm_shnu_tr_pbmn_rate",
|
||||
"nabt_smtn_ntby_qty", "nabt_smtm_ntby_qty_rate", "nabt_smtn_ntby_tr_pbmn", "nabt_smtm_ntby_tr_pbmn_rate",
|
||||
"whol_entm_seln_vol", "entm_seln_vol_rate", "whol_entm_seln_tr_pbmn", "entm_seln_tr_pbmn_rate",
|
||||
"whol_entm_shnu_vol", "entm_shnu_vol_rate", "whol_entm_shnu_tr_pbmn", "entm_shnu_tr_pbmn_rate",
|
||||
"whol_entm_ntby_qt", "entm_ntby_qty_rat", "whol_entm_ntby_tr_pbmn", "entm_ntby_tr_pbmn_rate",
|
||||
"whol_onsl_seln_vol", "onsl_seln_vol_rate", "whol_onsl_seln_tr_pbmn", "onsl_seln_tr_pbmn_rate",
|
||||
"whol_onsl_shnu_vol", "onsl_shnu_vol_rate", "whol_onsl_shnu_tr_pbmn", "onsl_shnu_tr_pbmn_rate",
|
||||
"whol_onsl_ntby_qty", "onsl_ntby_qty_rate", "whol_onsl_ntby_tr_pbmn", "onsl_ntby_tr_pbmn_rate",
|
||||
"total_seln_qty", "whol_seln_vol_rate", "total_seln_tr_pbmn", "whol_seln_tr_pbmn_rate",
|
||||
"shnu_cntg_smtn", "whol_shun_vol_rate", "total_shnu_tr_pbmn", "whol_shun_tr_pbmn_rate",
|
||||
"whol_ntby_qty", "whol_smtm_ntby_qty_rate", "whol_ntby_tr_pbmn", "whol_ntby_tr_pbmn_rate",
|
||||
"arbt_entm_ntby_qty", "arbt_entm_ntby_tr_pbmn", "arbt_onsl_ntby_qty", "arbt_onsl_ntby_tr_pbmn",
|
||||
"nabt_entm_ntby_qty", "nabt_entm_ntby_tr_pbmn", "nabt_onsl_ntby_qty", "nabt_onsl_ntby_tr_pbmn",
|
||||
"acml_vol", "acml_tr_pbmn"
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
국내지수 실시간프로그램매매
|
||||
|
||||
[참고자료]
|
||||
종목코드 마스터파일 파이썬 정제코드는 한국투자증권 Github 참고 부탁드립니다.
|
||||
https://github.com/koreainvestment/open-trading-api/tree/main/stocks_info
|
||||
|
||||
[호출 데이터]
|
||||
헤더와 바디 값을 합쳐 JSON 형태로 전송합니다.
|
||||
|
||||
[응답 데이터]
|
||||
1. 정상 등록 여부 (JSON)
|
||||
- JSON["body"]["msg1"] - 정상 응답 시, SUBSCRIBE SUCCESS
|
||||
- JSON["body"]["output"]["iv"] - 실시간 결과 복호화에 필요한 AES256 IV (Initialize Vector)
|
||||
- JSON["body"]["output"]["key"] - 실시간 결과 복호화에 필요한 AES256 Key
|
||||
|
||||
2. 실시간 결과 응답 ( | 로 구분되는 값)
|
||||
ex) 0|H0STCNT0|004|005930^123929^73100^5^...
|
||||
- 암호화 유무 : 0 암호화 되지 않은 데이터 / 1 암호화된 데이터
|
||||
- TR_ID : 등록한 tr_id (ex. H0STCNT0)
|
||||
- 데이터 건수 : (ex. 001 인 경우 데이터 건수 1건, 004인 경우 데이터 건수 4건)
|
||||
- 응답 데이터 : 아래 response 데이터 참조 ( ^로 구분됨)
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
ka.auth_ws()
|
||||
|
||||
# 인증(auth_ws()) 이후에 선언
|
||||
kws = ka.KISWebSocket(api_url="/tryitout")
|
||||
|
||||
# 조회
|
||||
kws.subscribe(request=index_program_trade, data=["0001", "0128"])
|
||||
|
||||
# 결과 표시
|
||||
def on_result(ws, tr_id: str, result: pd.DataFrame, data_map: dict):
|
||||
try:
|
||||
# 안전한 컬럼명 매핑 (존재하는 컬럼에 대해서만 한글명 적용)
|
||||
if not result.empty:
|
||||
# 컬럼명 매핑
|
||||
existing_columns = {col: COLUMN_MAPPING[col] for col in result.columns if col in COLUMN_MAPPING}
|
||||
if existing_columns:
|
||||
result = result.rename(columns=existing_columns)
|
||||
logging.info(f"컬럼명 매핑 완료: {len(existing_columns)}개 컬럼")
|
||||
|
||||
# 안전한 숫자형 컬럼 변환 (존재하는 컬럼에 대해서만 적용)
|
||||
NUMERIC_COLUMNS_to_convert = [col for col in NUMERIC_COLUMNS if col in result.columns]
|
||||
if NUMERIC_COLUMNS_to_convert:
|
||||
for col in NUMERIC_COLUMNS_to_convert:
|
||||
try:
|
||||
# 한글명으로 변환된 컬럼이 있는지 확인
|
||||
tarcol = COLUMN_MAPPING.get(col, col)
|
||||
if tarcol in result.columns:
|
||||
result[tarcol] = pd.to_numeric(result[tarcol], errors='coerce')
|
||||
except Exception as e:
|
||||
logging.warning(f"컬럼 '{col}' 숫자 변환 실패: {e}")
|
||||
logging.info(f"숫자형 변환 완료: {len(NUMERIC_COLUMNS_to_convert)}개 컬럼")
|
||||
|
||||
logging.info("결과:")
|
||||
print(result)
|
||||
except Exception as e:
|
||||
logging.error(f"결과 처리 중 오류: {e}")
|
||||
logging.error(f"받은 데이터: {result}")
|
||||
|
||||
kws.start(on_result=on_result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,95 @@
|
||||
"""
|
||||
Created on 2025-07-09
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 실시간시세 > 국내지수 실시간프로그램매매 [실시간-028]
|
||||
##############################################################################################
|
||||
|
||||
def index_program_trade(
|
||||
tr_type: str,
|
||||
tr_key: str,
|
||||
) -> tuple[dict, list[str]]:
|
||||
"""
|
||||
국내지수 실시간프로그램매매[H0UPPGM0] 구독 함수
|
||||
|
||||
이 함수는 한국투자증권의 웹소켓 API를 통해 국내지수의 실시간 프로그램 매매 데이터를 구독합니다.
|
||||
실시간 데이터를 구독하거나 구독 해제할 수 있습니다.
|
||||
|
||||
Args:
|
||||
tr_type (str): [필수] 구독 등록("1") 또는 해제("0") 여부를 나타내는 문자열
|
||||
tr_key (str): [필수] 종목코드를 나타내는 문자열. 빈 문자열일 수 없습니다.
|
||||
|
||||
Returns:
|
||||
message (dict): 웹소켓으로부터 수신된 메시지 데이터
|
||||
columns (list[str]): 응답 데이터의 컬럼 정보 리스트
|
||||
|
||||
Raises:
|
||||
ValueError: tr_key가 빈 문자열인 경우 발생
|
||||
|
||||
Example:
|
||||
>>> msg, columns = index_program_trade("1", "005930")
|
||||
>>> print(msg, columns)
|
||||
|
||||
참고자료:
|
||||
종목코드 마스터파일 파이썬 정제코드는 한국투자증권 Github 참고 부탁드립니다.
|
||||
https://github.com/koreainvestment/open-trading-api/tree/main/stocks_info
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if not tr_key:
|
||||
raise ValueError("tr_key is required and cannot be an empty string")
|
||||
|
||||
tr_id = "H0UPPGM0"
|
||||
|
||||
params = {
|
||||
"tr_key": tr_key,
|
||||
}
|
||||
|
||||
# 웹소켓을 통해 데이터 구독 요청
|
||||
msg = ka.data_fetch(tr_id, tr_type, params)
|
||||
|
||||
# 응답 데이터의 컬럼 정보
|
||||
columns = [
|
||||
"bstp_cls_code", "bsop_hour", "arbt_seln_entm_cnqn", "arbt_seln_onsl_cnqn",
|
||||
"arbt_shnu_entm_cnqn", "arbt_shnu_onsl_cnqn", "nabt_seln_entm_cnqn",
|
||||
"nabt_seln_onsl_cnqn", "nabt_shnu_entm_cnqn", "nabt_shnu_onsl_cnqn",
|
||||
"arbt_seln_entm_cntg_amt", "arbt_seln_onsl_cntg_amt", "arbt_shnu_entm_cntg_amt",
|
||||
"arbt_shnu_onsl_cntg_amt", "nabt_seln_entm_cntg_amt", "nabt_seln_onsl_cntg_amt",
|
||||
"nabt_shnu_entm_cntg_amt", "nabt_shnu_onsl_cntg_amt", "arbt_smtn_seln_vol",
|
||||
"arbt_smtm_seln_vol_rate", "arbt_smtn_seln_tr_pbmn", "arbt_smtm_seln_tr_pbmn_rate",
|
||||
"arbt_smtn_shnu_vol", "arbt_smtm_shnu_vol_rate", "arbt_smtn_shnu_tr_pbmn",
|
||||
"arbt_smtm_shnu_tr_pbmn_rate", "arbt_smtn_ntby_qty", "arbt_smtm_ntby_qty_rate",
|
||||
"arbt_smtn_ntby_tr_pbmn", "arbt_smtm_ntby_tr_pbmn_rate", "nabt_smtn_seln_vol",
|
||||
"nabt_smtm_seln_vol_rate", "nabt_smtn_seln_tr_pbmn", "nabt_smtm_seln_tr_pbmn_rate",
|
||||
"nabt_smtn_shnu_vol", "nabt_smtm_shnu_vol_rate", "nabt_smtn_shnu_tr_pbmn",
|
||||
"nabt_smtm_shnu_tr_pbmn_rate", "nabt_smtn_ntby_qty", "nabt_smtm_ntby_qty_rate",
|
||||
"nabt_smtn_ntby_tr_pbmn", "nabt_smtm_ntby_tr_pbmn_rate", "whol_entm_seln_vol",
|
||||
"entm_seln_vol_rate", "whol_entm_seln_tr_pbmn", "entm_seln_tr_pbmn_rate",
|
||||
"whol_entm_shnu_vol", "entm_shnu_vol_rate", "whol_entm_shnu_tr_pbmn",
|
||||
"entm_shnu_tr_pbmn_rate", "whol_entm_ntby_qt", "entm_ntby_qty_rat",
|
||||
"whol_entm_ntby_tr_pbmn", "entm_ntby_tr_pbmn_rate", "whol_onsl_seln_vol",
|
||||
"onsl_seln_vol_rate", "whol_onsl_seln_tr_pbmn", "onsl_seln_tr_pbmn_rate",
|
||||
"whol_onsl_shnu_vol", "onsl_shnu_vol_rate", "whol_onsl_shnu_tr_pbmn",
|
||||
"onsl_shnu_tr_pbmn_rate", "whol_onsl_ntby_qty", "onsl_ntby_qty_rate",
|
||||
"whol_onsl_ntby_tr_pbmn", "onsl_ntby_tr_pbmn_rate", "total_seln_qty",
|
||||
"whol_seln_vol_rate", "total_seln_tr_pbmn", "whol_seln_tr_pbmn_rate",
|
||||
"shnu_cntg_smtn", "whol_shun_vol_rate", "total_shnu_tr_pbmn",
|
||||
"whol_shun_tr_pbmn_rate", "whol_ntby_qty", "whol_smtm_ntby_qty_rate",
|
||||
"whol_ntby_tr_pbmn", "whol_ntby_tr_pbmn_rate", "arbt_entm_ntby_qty",
|
||||
"arbt_entm_ntby_tr_pbmn", "arbt_onsl_ntby_qty", "arbt_onsl_ntby_tr_pbmn",
|
||||
"nabt_entm_ntby_qty", "nabt_entm_ntby_tr_pbmn", "nabt_onsl_ntby_qty",
|
||||
"nabt_onsl_ntby_tr_pbmn", "acml_vol", "acml_tr_pbmn",
|
||||
]
|
||||
|
||||
return msg, columns
|
||||
@@ -0,0 +1,121 @@
|
||||
"""
|
||||
Created on 20250131
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from inquire_account_balance import inquire_account_balance
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 주문/계좌 > 투자계좌자산현황조회[v1_국내주식-048]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'pchs_amt': '매입금액',
|
||||
'evlu_amt': '평가금액',
|
||||
'evlu_pfls_amt': '평가손익금액',
|
||||
'crdt_lnd_amt': '신용대출금액',
|
||||
'real_nass_amt': '실제순자산금액',
|
||||
'whol_weit_rt': '전체비중율',
|
||||
'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': '기업신용공여대출금액'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = ['매입금액', '평가금액', '평가손익금액', '신용대출금액', '실제순자산금액', '전체비중율', '매입금액합계', '순자산총금액', '대출금액합계', '평가손익금액합계',
|
||||
'평가금액합계', '총자산금액', '총대출금액총융자대출금액', 'CMA자동대출금액', '총담보대출금액', '대주평가금액', '신용융자금액', 'OCL_APL대출금액',
|
||||
'질권설정금액', '외화평가총액', '총예수금액', 'CMA평가금액', '예수금액', '총대용금액', '당일미수금액', '해외주식평가금액1', '해외채권평가금액',
|
||||
'MMFCMA담보대출금액', '청약예수금액', '공모주청약자금대출사용금액', '기업신용공여대출금액']
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
투자계좌자산현황조회 테스트 함수
|
||||
|
||||
이 함수는 투자계좌자산현황조회 API를 호출하여 결과를 출력합니다.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
trenv = ka.getTREnv()
|
||||
|
||||
# case1 조회
|
||||
logging.info("=== case1 조회 ===")
|
||||
try:
|
||||
result1, result2 = inquire_account_balance(cano=trenv.my_acct, acnt_prdt_cd=trenv.my_prod)
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
# output1 처리
|
||||
logging.info("=== output1 결과 ===")
|
||||
logging.info("사용 가능한 컬럼: %s", result1.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환 및 데이터 출력
|
||||
result1 = result1.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result1.columns:
|
||||
result1[col] = pd.to_numeric(result1[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result1)
|
||||
|
||||
# output2 처리
|
||||
logging.info("=== output2 결과 ===")
|
||||
logging.info("사용 가능한 컬럼: %s", result2.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환 및 데이터 출력
|
||||
result2 = result2.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result2.columns:
|
||||
result2[col] = pd.to_numeric(result2[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,78 @@
|
||||
"""
|
||||
Created on 20250131
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
from typing import Tuple
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 주문/계좌 > 투자계좌자산현황조회[v1_국내주식-048]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/trading/inquire-account-balance"
|
||||
|
||||
def inquire_account_balance(
|
||||
cano: str, # [필수] 종합계좌번호 (ex. 12345678)
|
||||
acnt_prdt_cd: str, # [필수] 계좌상품코드 (ex. 19 or 21)
|
||||
inqr_dvsn_1: str = "", # 조회구분1
|
||||
bspr_bf_dt_aply_yn: str = "" # 기준가이전일자적용여부
|
||||
) -> Tuple[pd.DataFrame, pd.DataFrame]:
|
||||
"""
|
||||
투자계좌자산현황조회 API입니다.
|
||||
|
||||
output1은 한국투자 HTS(eFriend Plus) > [0891] 계좌 자산비중(결제기준) 화면 아래 테이블의 기능을 API로 개발한 사항으로, 해당 화면을 참고하시면 기능을 이해하기 쉽습니다.
|
||||
|
||||
Args:
|
||||
cano (str): [필수] 종합계좌번호 (ex. 12345678)
|
||||
acnt_prdt_cd (str): [필수] 계좌상품코드 (ex. 19 or 21)
|
||||
inqr_dvsn_1 (str): 조회구분1
|
||||
bspr_bf_dt_aply_yn (str): 기준가이전일자적용여부
|
||||
|
||||
Returns:
|
||||
Tuple[pd.DataFrame, pd.DataFrame]: (output1 데이터프레임, output2 데이터프레임)
|
||||
|
||||
Example:
|
||||
>>> df1, df2 = inquire_account_balance("12345678", "21")
|
||||
>>> print(df1)
|
||||
>>> print(df2)
|
||||
"""
|
||||
|
||||
if cano == "":
|
||||
raise ValueError("cano is required (e.g. '12345678')")
|
||||
|
||||
if acnt_prdt_cd == "":
|
||||
raise ValueError("acnt_prdt_cd is required (e.g. '19' or '21')")
|
||||
|
||||
tr_id = "CTRP6548R" # 투자계좌자산현황조회
|
||||
|
||||
params = {
|
||||
"CANO": cano, # 종합계좌번호
|
||||
"ACNT_PRDT_CD": acnt_prdt_cd, # 계좌상품코드
|
||||
"INQR_DVSN_1": inqr_dvsn_1, # 조회구분1
|
||||
"BSPR_BF_DT_APLY_YN": bspr_bf_dt_aply_yn # 기준가이전일자적용여부
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, "", params)
|
||||
|
||||
if res.isOK():
|
||||
# output1 - array 타입
|
||||
df1 = pd.DataFrame(res.getBody().output1)
|
||||
|
||||
# output2 - object 타입 (단일 객체를 DataFrame으로 변환)
|
||||
df2 = pd.DataFrame([res.getBody().output2])
|
||||
|
||||
logging.info("Data fetch complete.")
|
||||
return df1, df2
|
||||
else:
|
||||
res.printError(url=API_URL)
|
||||
return pd.DataFrame(), pd.DataFrame()
|
||||
@@ -0,0 +1,171 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from inquire_asking_price_exp_ccn import inquire_asking_price_exp_ccn
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 기본시세 > 주식현재가 호가/예상체결[v1_국내주식-011]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'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': '신 장운영 구분 코드',
|
||||
'antc_mkop_cls_code': '예상 장운영 구분 코드',
|
||||
'stck_prpr': '주식 현재가',
|
||||
'stck_oprc': '주식 시가2',
|
||||
'stck_hgpr': '주식 최고가',
|
||||
'stck_lwpr': '주식 최저가',
|
||||
'stck_sdpr': '주식 기준가',
|
||||
'antc_cnpr': '예상 체결가',
|
||||
'antc_cntg_vrss_sign': '예상 체결 대비 부호',
|
||||
'antc_cntg_vrss': '예상 체결 대비',
|
||||
'antc_cntg_prdy_ctrt': '예상 체결 전일 대비율',
|
||||
'antc_vol': '예상 거래량',
|
||||
'stck_shrn_iscd': '주식 단축 종목코드',
|
||||
'vi_cls_code': 'VI적용구분코드'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
주식현재가 호가/예상체결 조회 테스트 함수
|
||||
|
||||
이 함수는 주식현재가 호가/예상체결 API를 호출하여 결과를 출력합니다.
|
||||
테스트 데이터로 삼성전자(005930)를 사용합니다.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
# case1 조회
|
||||
logging.info("=== case1 조회 ===")
|
||||
try:
|
||||
result1, result2 = inquire_asking_price_exp_ccn(env_dv="real", fid_cond_mrkt_div_code="J",
|
||||
fid_input_iscd="005930")
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
# output1 (호가정보) 처리
|
||||
logging.info("=== output1 (호가정보) ===")
|
||||
logging.info("사용 가능한 컬럼: %s", result1.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환
|
||||
result1 = result1.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result1.columns:
|
||||
result1[col] = pd.to_numeric(result1[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result1)
|
||||
|
||||
# output2 (예상체결정보) 처리
|
||||
logging.info("=== output2 (예상체결정보) ===")
|
||||
logging.info("사용 가능한 컬럼: %s" % result2.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환
|
||||
result2 = result2.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result2.columns:
|
||||
result2[col] = pd.to_numeric(result2[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
import logging
|
||||
from typing import Tuple
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 기본시세 > 주식현재가 호가/예상체결[v1_국내주식-011]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/quotations/inquire-asking-price-exp-ccn"
|
||||
|
||||
def inquire_asking_price_exp_ccn(
|
||||
env_dv: str, # 실전모의구분 (real:실전, demo:모의)
|
||||
fid_cond_mrkt_div_code: str, # 조건 시장 분류 코드 (J:KRX, NX:NXT, UN:통합)
|
||||
fid_input_iscd: str # 입력 종목코드 (123456)
|
||||
) -> Tuple[pd.DataFrame, pd.DataFrame]:
|
||||
"""
|
||||
주식현재가 호가 예상체결 API입니다. 매수 매도 호가를 확인하실 수 있습니다. 실시간 데이터를 원하신다면 웹소켓 API를 활용하세요.
|
||||
|
||||
Args:
|
||||
env_dv (str): [필수] 실전모의구분 (ex. real:실전, demo:모의)
|
||||
fid_cond_mrkt_div_code (str): [필수] 조건 시장 분류 코드 (ex. J:KRX, NX:NXT, UN:통합)
|
||||
fid_input_iscd (str): [필수] 입력 종목코드 (ex. 123456)
|
||||
|
||||
Returns:
|
||||
Tuple[pd.DataFrame, pd.DataFrame]: (호가정보, 예상체결정보) 데이터
|
||||
|
||||
Example:
|
||||
>>> result1, result2 = inquire_asking_price_exp_ccn(env_dv="real", fid_cond_mrkt_div_code="J", fid_input_iscd="005930")
|
||||
>>> print(result1) # 호가정보
|
||||
>>> print(result2) # 예상체결정보
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if env_dv == "":
|
||||
raise ValueError("env_dv is required (e.g. 'real:실전, demo:모의')")
|
||||
|
||||
if fid_cond_mrkt_div_code == "":
|
||||
raise ValueError("fid_cond_mrkt_div_code is required (e.g. 'J:KRX, NX:NXT, UN:통합')")
|
||||
|
||||
if fid_input_iscd == "":
|
||||
raise ValueError("fid_input_iscd is required (e.g. '123456')")
|
||||
|
||||
# TR_ID 설정
|
||||
if env_dv == "real":
|
||||
tr_id = "FHKST01010200"
|
||||
elif env_dv == "demo":
|
||||
tr_id = "FHKST01010200"
|
||||
else:
|
||||
raise ValueError("env_dv can only be 'real' or 'demo'")
|
||||
|
||||
params = {
|
||||
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code, # 조건 시장 분류 코드
|
||||
"FID_INPUT_ISCD": fid_input_iscd # 입력 종목코드
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, "", params)
|
||||
|
||||
if res.isOK():
|
||||
# output1 (object) -> 호가정보
|
||||
output1_data = pd.DataFrame([res.getBody().output1])
|
||||
|
||||
# output2 (array) -> 예상체결정보
|
||||
output2_data = pd.DataFrame([res.getBody().output2])
|
||||
|
||||
return output1_data, output2_data
|
||||
else:
|
||||
res.printError(url=API_URL)
|
||||
return pd.DataFrame(), pd.DataFrame()
|
||||
@@ -0,0 +1,147 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
from inquire_balance import inquire_balance
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 주문/계좌 > 주식잔고조회[v1_국내주식-006]
|
||||
##############################################################################################
|
||||
|
||||
COLUMN_MAPPING = {
|
||||
'pdno': '상품번호',
|
||||
'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': '만기일자',
|
||||
'fltt_rt': '등락율',
|
||||
'bfdy_cprs_icdc': '전일대비증감',
|
||||
'item_mgna_rt_name': '종목증거금율명',
|
||||
'grta_rt_name': '보증금율명',
|
||||
'sbst_pric': '대용가격',
|
||||
'stck_loan_unpr': '주식대출단가',
|
||||
'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': '자산증감수익율'
|
||||
}
|
||||
|
||||
NUMERIC_COLUMNS = []
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
주식잔고조회 테스트 함수
|
||||
|
||||
이 함수는 주식잔고조회 API를 호출하여 결과를 출력합니다.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# pandas 출력 옵션 설정
|
||||
pd.set_option('display.max_columns', None) # 모든 컬럼 표시
|
||||
pd.set_option('display.width', None) # 출력 너비 제한 해제
|
||||
pd.set_option('display.max_rows', None) # 모든 행 표시
|
||||
|
||||
# 인증 토큰 발급
|
||||
ka.auth()
|
||||
|
||||
trenv = ka.getTREnv()
|
||||
|
||||
# case1 테스트
|
||||
logging.info("=== case1 테스트 ===")
|
||||
try:
|
||||
result1, result2 = inquire_balance(
|
||||
env_dv="real",
|
||||
cano=trenv.my_acct,
|
||||
acnt_prdt_cd=trenv.my_prod,
|
||||
afhr_flpr_yn="N",
|
||||
inqr_dvsn="01",
|
||||
unpr_dvsn="01",
|
||||
fund_sttl_icld_yn="N",
|
||||
fncg_amt_auto_rdpt_yn="N",
|
||||
prcs_dvsn="00"
|
||||
)
|
||||
except ValueError as e:
|
||||
logging.error("에러 발생: %s" % str(e))
|
||||
return
|
||||
|
||||
# output1 결과 처리
|
||||
logging.info("=== output1 결과 ===")
|
||||
logging.info("사용 가능한 컬럼: %s", result1.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환
|
||||
result1 = result1.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result1.columns:
|
||||
result1[col] = pd.to_numeric(result1[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result1)
|
||||
|
||||
# output2 결과 처리
|
||||
logging.info("=== output2 결과 ===")
|
||||
logging.info("사용 가능한 컬럼: %s", result2.columns.tolist())
|
||||
|
||||
# 컬럼명 한글 변환
|
||||
result2 = result2.rename(columns=COLUMN_MAPPING)
|
||||
|
||||
# 숫자형 컬럼 소수점 둘째자리까지 표시
|
||||
for col in NUMERIC_COLUMNS:
|
||||
if col in result2.columns:
|
||||
result2[col] = pd.to_numeric(result2[col], errors='coerce').round(2)
|
||||
|
||||
logging.info("결과:")
|
||||
print(result2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,170 @@
|
||||
"""
|
||||
Created on 20250601
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
import time
|
||||
from typing import Optional, Tuple
|
||||
import logging
|
||||
|
||||
import pandas as pd
|
||||
|
||||
sys.path.extend(['../..', '.'])
|
||||
import kis_auth as ka
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
##############################################################################################
|
||||
# [국내주식] 주문/계좌 > 주식잔고조회[v1_국내주식-006]
|
||||
##############################################################################################
|
||||
|
||||
# 상수 정의
|
||||
API_URL = "/uapi/domestic-stock/v1/trading/inquire-balance"
|
||||
|
||||
def inquire_balance(
|
||||
env_dv: str, # 실전모의구분
|
||||
cano: str, # 종합계좌번호
|
||||
acnt_prdt_cd: str, # 계좌상품코드
|
||||
afhr_flpr_yn: str, # 시간외단일가·거래소여부
|
||||
inqr_dvsn: str, # 조회구분
|
||||
unpr_dvsn: str, # 단가구분
|
||||
fund_sttl_icld_yn: str, # 펀드결제분포함여부
|
||||
fncg_amt_auto_rdpt_yn: str, # 융자금액자동상환여부
|
||||
prcs_dvsn: str, # 처리구분
|
||||
FK100: str = "", # 연속조회검색조건100
|
||||
NK100: str = "", # 연속조회키100
|
||||
tr_cont: str = "", # 연속거래여부
|
||||
dataframe1: Optional[pd.DataFrame] = None, # 누적 데이터프레임1
|
||||
dataframe2: Optional[pd.DataFrame] = None, # 누적 데이터프레임2
|
||||
depth: int = 0, # 내부 재귀깊이 (자동관리)
|
||||
max_depth: int = 10 # 최대 재귀 횟수 제한
|
||||
) -> Tuple[pd.DataFrame, pd.DataFrame]:
|
||||
"""
|
||||
주식 잔고조회 API입니다.
|
||||
실전계좌의 경우, 한 번의 호출에 최대 50건까지 확인 가능하며, 이후의 값은 연속조회를 통해 확인하실 수 있습니다.
|
||||
모의계좌의 경우, 한 번의 호출에 최대 20건까지 확인 가능하며, 이후의 값은 연속조회를 통해 확인하실 수 있습니다.
|
||||
|
||||
* 당일 전량매도한 잔고도 보유수량 0으로 보여질 수 있으나, 해당 보유수량 0인 잔고는 최종 D-2일 이후에는 잔고에서 사라집니다.
|
||||
|
||||
Args:
|
||||
env_dv (str): [필수] 실전모의구분 (ex. real:실전, demo:모의)
|
||||
cano (str): [필수] 종합계좌번호 (ex. 계좌번호 체계(8-2)의 앞 8자리)
|
||||
acnt_prdt_cd (str): [필수] 계좌상품코드 (ex. 계좌번호 체계(8-2)의 뒤 2자리)
|
||||
afhr_flpr_yn (str): [필수] 시간외단일가·거래소여부 (ex. N:기본값, Y:시간외단일가, X:NXT)
|
||||
inqr_dvsn (str): [필수] 조회구분 (ex. 01 – 대출일별 | 02 – 종목별)
|
||||
unpr_dvsn (str): [필수] 단가구분 (ex. 01)
|
||||
fund_sttl_icld_yn (str): [필수] 펀드결제분포함여부 (ex. N, Y)
|
||||
fncg_amt_auto_rdpt_yn (str): [필수] 융자금액자동상환여부 (ex. N)
|
||||
prcs_dvsn (str): [필수] 처리구분 (ex. 00: 전일매매포함, 01:전일매매미포함)
|
||||
FK100 (str): 연속조회검색조건100
|
||||
NK100 (str): 연속조회키100
|
||||
tr_cont (str): 연속거래여부
|
||||
dataframe1 (Optional[pd.DataFrame]): 누적 데이터프레임1
|
||||
dataframe2 (Optional[pd.DataFrame]): 누적 데이터프레임2
|
||||
depth (int): 내부 재귀깊이 (자동관리)
|
||||
max_depth (int): 최대 재귀 횟수 제한
|
||||
|
||||
Returns:
|
||||
Tuple[pd.DataFrame, pd.DataFrame]: 주식잔고조회 데이터 (output1, output2)
|
||||
|
||||
Example:
|
||||
>>> df1, df2 = inquire_balance(env_dv="real", cano=trenv.my_acct, acnt_prdt_cd=trenv.my_prod, afhr_flpr_yn="N", inqr_dvsn="01", unpr_dvsn="01", fund_sttl_icld_yn="N", fncg_amt_auto_rdpt_yn="N", prcs_dvsn="00")
|
||||
>>> print(df1)
|
||||
>>> print(df2)
|
||||
"""
|
||||
|
||||
# 필수 파라미터 검증
|
||||
if env_dv == "":
|
||||
raise ValueError("env_dv is required (e.g. 'real:실전, demo:모의')")
|
||||
|
||||
if cano == "":
|
||||
raise ValueError("cano is required (e.g. '계좌번호 체계(8-2)의 앞 8자리')")
|
||||
|
||||
if acnt_prdt_cd == "":
|
||||
raise ValueError("acnt_prdt_cd is required (e.g. '계좌번호 체계(8-2)의 뒤 2자리')")
|
||||
|
||||
if afhr_flpr_yn == "":
|
||||
raise ValueError("afhr_flpr_yn is required (e.g. 'N:기본값, Y:시간외단일가, X:NXT')")
|
||||
|
||||
if inqr_dvsn == "":
|
||||
raise ValueError("inqr_dvsn is required (e.g. '01 – 대출일별 | 02 – 종목별')")
|
||||
|
||||
if unpr_dvsn == "":
|
||||
raise ValueError("unpr_dvsn is required (e.g. '01')")
|
||||
|
||||
if fund_sttl_icld_yn == "":
|
||||
raise ValueError("fund_sttl_icld_yn is required (e.g. 'N, Y')")
|
||||
|
||||
if fncg_amt_auto_rdpt_yn == "":
|
||||
raise ValueError("fncg_amt_auto_rdpt_yn is required (e.g. 'N')")
|
||||
|
||||
if prcs_dvsn == "":
|
||||
raise ValueError("prcs_dvsn is required (e.g. '00: 전일매매포함, 01:전일매매미포함')")
|
||||
|
||||
if depth > max_depth:
|
||||
logging.warning("Max recursive depth reached.")
|
||||
if dataframe1 is None:
|
||||
dataframe1 = pd.DataFrame()
|
||||
if dataframe2 is None:
|
||||
dataframe2 = pd.DataFrame()
|
||||
return dataframe1, dataframe2
|
||||
|
||||
# tr_id 설정
|
||||
if env_dv == "real":
|
||||
tr_id = "TTTC8434R"
|
||||
elif env_dv == "demo":
|
||||
tr_id = "VTTC8434R"
|
||||
else:
|
||||
raise ValueError("env_dv is required (e.g. 'real' or 'demo')")
|
||||
|
||||
params = {
|
||||
"CANO": cano,
|
||||
"ACNT_PRDT_CD": acnt_prdt_cd,
|
||||
"AFHR_FLPR_YN": afhr_flpr_yn,
|
||||
"OFL_YN": "",
|
||||
"INQR_DVSN": inqr_dvsn,
|
||||
"UNPR_DVSN": unpr_dvsn,
|
||||
"FUND_STTL_ICLD_YN": fund_sttl_icld_yn,
|
||||
"FNCG_AMT_AUTO_RDPT_YN": fncg_amt_auto_rdpt_yn,
|
||||
"PRCS_DVSN": prcs_dvsn,
|
||||
"CTX_AREA_FK100": FK100,
|
||||
"CTX_AREA_NK100": NK100
|
||||
}
|
||||
|
||||
res = ka._url_fetch(API_URL, tr_id, tr_cont, params)
|
||||
|
||||
if res.isOK():
|
||||
# output1 처리
|
||||
current_data1 = pd.DataFrame(res.getBody().output1)
|
||||
if dataframe1 is not None:
|
||||
dataframe1 = pd.concat([dataframe1, current_data1], ignore_index=True)
|
||||
else:
|
||||
dataframe1 = current_data1
|
||||
|
||||
# output2 처리
|
||||
current_data2 = pd.DataFrame(res.getBody().output2)
|
||||
if dataframe2 is not None:
|
||||
dataframe2 = pd.concat([dataframe2, current_data2], ignore_index=True)
|
||||
else:
|
||||
dataframe2 = current_data2
|
||||
|
||||
tr_cont = res.getHeader().tr_cont
|
||||
FK100 = res.getBody().ctx_area_fk100
|
||||
NK100 = res.getBody().ctx_area_nk100
|
||||
|
||||
if tr_cont in ["M", "F"]: # 다음 페이지 존재
|
||||
logging.info("Call Next page...")
|
||||
ka.smart_sleep() # 시스템 안정적 운영을 위한 지연
|
||||
return inquire_balance(
|
||||
env_dv, cano, acnt_prdt_cd, afhr_flpr_yn, inqr_dvsn, unpr_dvsn,
|
||||
fund_sttl_icld_yn, fncg_amt_auto_rdpt_yn, prcs_dvsn, FK100, NK100,
|
||||
"N", dataframe1, dataframe2, depth + 1, max_depth
|
||||
)
|
||||
else:
|
||||
logging.info("Data fetch complete.")
|
||||
return dataframe1, dataframe2
|
||||
else:
|
||||
res.printError(url=API_URL)
|
||||
return pd.DataFrame(), pd.DataFrame()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user