[2026-05-19] KIS API TR_ID 수정 — 외국인/기관 수급·업종 지수 API 교체

- get_foreign_institution_rank: FHKST04430000(없는 서비스) → FHPTJ04400000(foreign-institution-total)
- get_sector_trend: FHKST03010100(일봉 오용) → FHPUP02100000(inquire-index-price) 15개 업종 다중 호출
- 두 함수 모두 실거래 API 테스트 통과 확인

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-19 08:59:35 +09:00
parent 92fec17e0e
commit 60eda5a5ee
+65 -40
View File
@@ -413,61 +413,86 @@ class KISClient:
return result
async def get_foreign_institution_rank(self, top_n: int = 30) -> Dict:
"""외국인/기관 순매수 상위 (AI 판단용)"""
"""외국인/기관 순매수 상위 (AI 판단용) — FHPTJ04400000"""
data = await self._request(
method = "GET",
path = "/uapi/domestic-stock/v1/quotations/inquire-investor",
tr_id = "FHKST04430000",
path = "/uapi/domestic-stock/v1/quotations/foreign-institution-total",
tr_id = "FHPTJ04400000",
params = {
"FID_COND_MRKT_DIV_CODE": "J",
"FID_INPUT_ISCD" : "0000",
"FID_INPUT_DATE_1" : "",
"FID_INPUT_DATE_2" : "",
"FID_PERIOD_DIV_CODE" : "D",
"FID_COND_MRKT_DIV_CODE" : "J",
"FID_COND_SCR_DIV_CODE" : "20171",
"FID_INPUT_ISCD" : "0000",
"FID_DIV_CLS_CODE" : "0",
"FID_BLNG_CLS_CODE" : "0",
"FID_TRGT_CLS_CODE" : "111111111",
"FID_TRGT_EXLS_CLS_CODE" : "000000",
"FID_INPUT_PRICE_1" : "",
"FID_INPUT_PRICE_2" : "",
"FID_VOL_CNT" : "",
"FID_INPUT_DATE_1" : "",
"FID_RANK_SORT_CLS_CODE" : "1", # 순매수량 기준 정렬
"FID_ETC_CLS_CODE" : "0",
}
)
foreign = []
institution = []
for row in data.get("output", [])[:top_n]:
entry = {
"ticker": row.get("mksc_shrn_iscd", ""),
"name" : row.get("hts_kor_isnm", ""),
"amount": int(row.get("frgn_ntby_qty", "0")),
}
foreign.append(entry)
entry2 = {
"ticker": row.get("mksc_shrn_iscd", ""),
"name" : row.get("hts_kor_isnm", ""),
"amount": int(row.get("orgn_ntby_qty", "0")),
}
institution.append(entry2)
for row in data.get("output", []):
ticker = row.get("mksc_shrn_iscd", "")
name = row.get("hts_kor_isnm", "")
try:
frgn_qty = int(row.get("frgn_ntby_qty") or 0)
except (ValueError, TypeError):
frgn_qty = 0
try:
orgn_qty = int(row.get("orgn_ntby_qty") or 0)
except (ValueError, TypeError):
orgn_qty = 0
foreign.append({"ticker": ticker, "name": name, "amount": frgn_qty})
institution.append({"ticker": ticker, "name": name, "amount": orgn_qty})
return {
"foreign" : sorted(foreign, key=lambda x: x["amount"], reverse=True)[:top_n],
"institution": sorted(institution, key=lambda x: x["amount"], reverse=True)[:top_n],
}
# 업종코드 → 업종명 (KOSPI 주요 업종)
_SECTOR_CODES = [
("0001", "KOSPI"),
("0028", "반도체"),
("0150", "2차전지"),
("0018", "전기전자"),
("0011", "의약품"),
("0010", "화학"),
("0016", "철강금속"),
("0017", "기계"),
("0006", "건설업"),
("0027", "금융업"),
("0026", "통신업"),
("0020", "운수창고"),
("0021", "유통업"),
("0009", "음식료품"),
("0024", "전기가스업"),
]
async def get_sector_trend(self) -> list:
"""업종별 등락률 (AI 판단용)"""
data = await self._request(
method = "GET",
path = "/uapi/domestic-stock/v1/quotations/inquire-daily-itemchartprice",
tr_id = "FHKST03010100",
params = {
"FID_COND_MRKT_DIV_CODE": "U", # 업종
"FID_INPUT_ISCD" : "0001",
"FID_INPUT_DATE_1" : "",
"FID_INPUT_DATE_2" : "",
"FID_PERIOD_DIV_CODE" : "D",
"FID_ORG_ADJ_PRC" : "0",
}
)
"""업종별 등락률 (AI 판단용) — FHPUP02100000 다중 호출"""
result = []
for row in data.get("output1", []):
result.append({
"sector" : row.get("hts_kor_isnm", ""),
"change_pct": float(row.get("prdy_ctrt", "0")),
})
for code, name in self._SECTOR_CODES:
try:
data = await self._request(
method = "GET",
path = "/uapi/domestic-stock/v1/quotations/inquire-index-price",
tr_id = "FHPUP02100000",
params = {
"FID_COND_MRKT_DIV_CODE": "U",
"FID_INPUT_ISCD" : code,
}
)
o = data.get("output", {})
change_pct = float(o.get("bstp_nmix_prdy_ctrt") or 0)
result.append({"sector": name, "change_pct": change_pct})
except Exception as e:
logger.warning(f"업종 지수 조회 실패 [{name}/{code}]: {e}")
return result