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