initial commit

This commit is contained in:
2026-01-31 22:34:57 +09:00
commit f1301de543
875 changed files with 196598 additions and 0 deletions

View File

@@ -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()

View File

@@ -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()

View 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) [실시간-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

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View 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

View 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()

View File

@@ -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

View File

@@ -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()

View 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

View 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()

View 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

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View 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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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