코스피 지수 API — KIS 업종지수로 상승·하락 종목 수까지
/uapi/domestic-stock/v1/quotations/inquire-index-price에
tr_id FHPUP02100000,
파라미터는 FID_COND_MRKT_DIV_CODE=U(업종)와
FID_INPUT_ISCD에 코스피 0001 · 코스닥 1001 · 코스피200 2001 두 개뿐입니다.
응답에는 지수 값만 오는 게 아니라 상승·하락·상한·하한·보합 종목 수가 같이 들어 있어,
시장 내부 분포를 한 호출로 받을 수 있습니다.
이 글은 KIS API 현재가 조회(종목 하나의 시세·관리종목·VI)에서
지수 한 갈래만 떼어 낸 글입니다.
종목 시세는 그쪽에 있고, 여기서는 지수·업종 전용 엔드포인트만 다룹니다.
아래 스펙은 2026-09-12에 한국투자증권 공식 저장소 koreainvestment/open-trading-api의
main 브랜치 예제 원문(inquire_index_price·inquire_index_daily_price·
inquire_index_timeprice·inquire_index_tickprice·inquire_index_category_price·
inquire_daily_indexchartprice)을 직접 받아 확인했습니다.
이 글에서 확인할 것
- 지수는 종목이 아니다 — 시장구분
U와 업종코드 - 업종·지수 API 6종과
tr_id - 현재지수 응답 — 지수에 딸려 오는 시장 분포
- 일자별지수에 숨어 있는
d20_dsrt·invt_new_psdg - 함정 — 공식 예제 주석의
K2표기가 어긋나 있다 - 봇에 붙이기 — 시장 필터를 만드는 법과 한계
1. 지수는 종목이 아니다 — 시장구분 U와 업종코드
KIS API를 처음 붙일 때 흔한 막힘이 "코스피 지수 종목코드가 뭐냐"입니다.
답은 종목코드가 아니라 업종코드이고, 시장구분 자체가 다릅니다.
종목 시세는 FID_COND_MRKT_DIV_CODE에 J(KRX)를 넣지만,
지수는 U(업종)를 넣습니다.
# 공식 예제 원문 — inquire_index_price.py
API_URL = "/uapi/domestic-stock/v1/quotations/inquire-index-price"
tr_id = "FHPUP02100000"
params = {
"FID_COND_MRKT_DIV_CODE": fid_cond_mrkt_div_code, # 업종(U)
"FID_INPUT_ISCD": fid_input_iscd, # 0001 / 1001 / 2001 ...
}
# Example: df = inquire_index_price("U", "0001") # 코스피
예제 docstring이 명시한 업종코드는 세 개입니다.
| 업종코드 | 무엇 |
|---|---|
0001 | 코스피 (KOSPI) |
1001 | 코스닥 (KOSDAQ) |
2001 | 코스피200 |
나머지 업종(전기전자·의약품·금융업 등)은 예제에 값이 적혀 있지 않고, "포탈 (FAQ : 종목정보 다운로드(국내) - 업종코드 참조)" 라고만 안내합니다. 즉 전체 업종코드표는 KIS Developers 포털의 다운로드 자료에 있습니다 — 종목마스터 파일을 파싱하는 방식과 같은 계열의 자료입니다. 이 글에서는 확인하지 못한 업종코드를 추측해 적지 않았습니다.
2. 업종·지수 API 6종과 tr_id
지수 계열은 용도별로 엔드포인트가 쪼개져 있습니다. 경로도 tr_id도 종목 쪽과 전부 다릅니다.
| 용도 | tr_id | 엔드포인트 |
|---|---|---|
| 현재지수 | FHPUP02100000 | inquire-index-price |
| 일자별지수 (D/W/M) | FHPUP02120000 | inquire-index-daily-price |
| 시간별지수 (분) | FHPUP02110200 | inquire-index-timeprice |
| 시간별지수 (틱) | FHPUP02110100 | inquire-index-tickprice |
| 구분별 전체시세 | FHPUP02140000 | inquire-index-category-price |
| 기간별 지수 차트 | FHKUP03500100 | inquire-daily-indexchartprice |
종목 차트 함수를 재사용하지 마십시오.
종목의 기간별 시세는 FHKST03010100, 지수의 기간별 차트는 FHKUP03500100으로
tr_id가 아예 다릅니다.
응답 필드명도 종목은 stck_prpr·stck_bsop_date 계열이고
지수는 bstp_nmix_prpr·bstp_nmix_oprc 계열이라 겹치지 않습니다.
같은 파서에 밀어 넣으면 KeyError가 아니라 조용한 None이 나기 쉽습니다.
3. 현재지수 응답 — 지수에 딸려 오는 시장 분포
FHPUP02100000의 응답은 생각보다 두껍습니다.
공식 예제 chk_inquire_index_price.py의 컬럼 매핑에 36개 필드가 나열돼 있는데,
이 중 눈여겨볼 것은 지수 값이 아니라 종목 수 5개입니다.
| 필드 | 의미 | 봇에서 쓰는 법 |
|---|---|---|
bstp_nmix_prpr | 업종 지수 현재가 | 지수 값 자체 |
bstp_nmix_prdy_ctrt | 전일 대비율 | 당일 등락률 |
ascn_issu_cnt | 상승 종목 수 | 상승/하락 비율로 시장 내부 분포 판단 |
down_issu_cnt | 하락 종목 수 | |
stnr_issu_cnt | 보합 종목 수 | |
uplm_issu_cnt | 상한 종목 수 | |
lslm_issu_cnt | 하한 종목 수 | |
dryy_bstp_nmix_hgpr / _lwpr | 연중 최고·최저 지수 | + 해당 일자 필드도 같이 옴 |
total_askp_rsqn / total_bidp_rsqn | 총 매도·매수호가 잔량 | ntby_rsqn(순매수 잔량)도 포함 |
acml_vol / prdy_vol | 당일·전일 거래량 | 거래대금은 acml_tr_pbmn |
이게 왜 유용하냐면 — 지수가 +0.3%인 날에도 하락 종목이 상승 종목보다 훨씬 많은 경우가 있습니다. 지수 등락률만 보면 알 수 없는 분포를, 따로 집계 API를 부르지 않고 같은 응답에서 바로 얻습니다. 호출 예산을 아끼는 설계 관점에서 의미가 큽니다.
import requests
def index_snapshot(iscd="0001"):
"""코스피(0001) / 코스닥(1001) / 코스피200(2001)"""
r = requests.get(
BASE + "/uapi/domestic-stock/v1/quotations/inquire-index-price",
headers={**auth_headers, "tr_id": "FHPUP02100000"},
params={"FID_COND_MRKT_DIV_CODE": "U", "FID_INPUT_ISCD": iscd},
timeout=5)
o = r.json()["output"]
up, down = int(o["ascn_issu_cnt"]), int(o["down_issu_cnt"])
return {
"index": float(o["bstp_nmix_prpr"]),
"chg_pct": float(o["bstp_nmix_prdy_ctrt"]),
"up": up, "down": down,
"breadth": up / (up + down) if up + down else None, # 상승 비율
}
4. 일자별지수에 숨어 있는 d20_dsrt · invt_new_psdg
FHPUP02120000(국내업종 일자별지수)은 출력이 두 덩어리입니다.
output1은 현재지수와 비슷한 요약이고, output2가 일자별 시계열인데
여기 계산된 지표 두 개가 섞여 있습니다.
# 공식 예제 chk_inquire_index_daily_price.py 의 COLUMN_MAPPING 발췌
'stck_bsop_date': '주식 영업 일자',
'bstp_nmix_prpr': '업종 지수 현재가',
'acml_vol_rlim' : '누적 거래량 비중',
'invt_new_psdg' : '투자 신 심리도', # ← KIS가 계산해서 준다
'd20_dsrt' : '20일 이격도', # ← 20일 이동평균 대비 위치
호출은 inquire_index_daily_price('D', 'U', '0001', '20240223') 형태이고,
첫 인자 FID_PERIOD_DIV_CODE가 D(일별)·W(주별)·M(월별)입니다.
날짜는 YYYYMMDD 문자열입니다.
다만 계산식은 공개돼 있지 않습니다.
심리도와 이격도는 산출 방식이 여러 갈래라, 값을 그대로 전략에 넣기 전에
같은 기간 지수 시계열로 직접 재계산해 대조하십시오.
pandas로 20일 이동평균을 구해 비율을 내면 몇 줄입니다.
숫자가 맞지 않는다면 정의가 다른 것이고, 정의를 모르는 지표를 조건에 넣는 것이 가장 위험합니다.
5. 함정 — 공식 예제 주석의 K2 표기가 어긋나 있다
FHPUP02140000(국내업종 구분별전체시세)는 파라미터가 다섯 개로 늘어납니다.
FID_COND_SCR_DIV_CODE에 20214라는 고정값(Unique key)을 넣어야 하고,
FID_MRKT_CLS_CODE와 FID_BLNG_CLS_CODE가 추가됩니다.
# 공식 예제 inquire_index_category_price.py docstring 발췌
fid_mrkt_cls_code : 시장구분코드(K:거래소, Q:코스닥, K2:코스피200)
fid_blng_cls_code : 시장구분코드(K:거래소) 0:전업종, 1:기타구분, 2:자본금구분 3:상업별구분
시장구분코드(Q:코스닥) 0:전업종, 1:기타구분, 2:벤처구분 3:일반구분
시장구분코드(K2:코스닥) 0:전업종 ← 같은 문서 안에서 K2 설명이 어긋난다
같은 docstring 안에서 K2가 위에서는 코스피200, 아래에서는 코스닥으로 적혀 있습니다.
위 줄이 맞고 아래가 오기로 보이지만, 이 글에서 어느 쪽이 맞다고 단정하지 않습니다.
교훈은 분명합니다 — 코드표를 주석에서 복사해 상수로 박지 말고,
FID_BLNG_CLS_CODE를 0부터 하나씩 실제로 호출해
돌아오는 업종명으로 의미를 확인한 뒤 고정하십시오.
증권사 API 문서의 코드표는 에러코드 정리에서 다룬 것과 같은 이유로
원문끼리도 어긋나는 일이 있습니다.
6. 봇에 붙이기 — 시장 필터를 만드는 법과 한계
실무에서 지수 API를 붙이는 자리는 보통 신규 진입 게이트입니다. "지수가 이 조건일 때는 새로 사지 않는다" 같은 규칙을 봇 앞단에 두는 형태입니다. 구현은 짧습니다.
def entry_allowed():
ks = index_snapshot("0001") # 코스피
kq = index_snapshot("1001") # 코스닥
# 규칙은 '예시'다 — 임계값은 각자 검증해서 정할 것
if ks["chg_pct"] <= -2.0: # 지수 급락 구간
return False, "kospi_drop"
if ks["breadth"] is not None and ks["breadth"] < 0.30:
return False, "breadth_weak" # 상승 종목이 30% 미만
if kq["chg_pct"] <= -2.5:
return False, "kosdaq_drop"
return True, "ok"
# 호출 비용: 하루 종일 30초 주기로 돌려도 지수 2종 × 2 = 초당 0.07 호출
여기서 반드시 짚어야 할 것. 위 임계값 -2.0·0.30은
코드 모양을 보여 주려고 넣은 예시 숫자이고,
이 글은 어떤 임계값이 수익을 올린다고 주장하지 않습니다.
시장 필터는 거래 표본 수를 줄이기 때문에
백테스트 결과의 유의성을 오히려 떨어뜨릴 수 있고,
여러 임계값을 돌려 가장 좋은 것을 고르는 순간
다중검정 함정에 그대로 들어갑니다.
과거 데이터에서 맞았다는 사실이 미래를 보장하지 않습니다.
투자 판단과 그 결과는 이용자 본인의 책임입니다.
7. 확인한 것과 확인하지 않은 것
- 확인함 — 6개 엔드포인트 경로와
tr_id, 파라미터 이름, 업종코드0001/1001/2001, 응답 필드명(현재지수 36개·일자별output2포함),FID_PERIOD_DIV_CODE의D/W/M. 모두 2026-09-12 공식 저장소main브랜치 원문. - 확인 안 함 — 전체 업종코드표(포털 다운로드 자료),
invt_new_psdg·d20_dsrt의 계산식,FHPUP02140000의K2의미, 지수 API의 모의투자 지원 범위.inquire_daily_indexchartprice예제는env_dv가real·demo모두 같은tr_idFHKUP03500100을 쓰고 그 외 값은ValueError를 냅니다. - 초당 호출 허용 건수는 이 글에서 수치로 단정하지 않았습니다. KIS Developers 공식 문서의 현재 값을 쓰십시오.
자주 묻는 질문
KIS API로 코스피 지수를 어떻게 조회하나요?
inquire-index-price(tr_id FHPUP02100000)에
FID_COND_MRKT_DIV_CODE=U, FID_INPUT_ISCD=0001을 넣습니다.
코스닥은 1001, 코스피200은 2001입니다.
지수 응답에 상승·하락 종목 수가 들어 있나요?
들어 있습니다. ascn_issu_cnt·down_issu_cnt·stnr_issu_cnt·
uplm_issu_cnt·lslm_issu_cnt 다섯 개가 같은 응답에 옵니다.
KIS가 이격도나 심리도를 계산해서 주나요?
일자별지수(FHPUP02120000) output2에 d20_dsrt(20일 이격도)와
invt_new_psdg(투자 신 심리도)가 있습니다. 계산식은 공개돼 있지 않으니
pandas로 재계산해 대조한 뒤 쓰십시오.
지수 분봉이나 기간별 차트도 받을 수 있나요?
분 단위는 FHPUP02110200, 틱은 FHPUP02110100,
일·주·월은 FHPUP02120000, 기간별 차트는 FHKUP03500100입니다.
종목 차트와 경로·필드가 다르므로 함수를 분리하십시오.
지수로 봇을 멈추게 하는 필터를 만들어도 되나요?
구현은 간단하지만 어떤 임계값이 좋은지는 이 글이 답할 수 없습니다. 필터는 표본 수를 줄여 검증을 어렵게 만들고, 여러 값을 돌려 최적값을 고르면 다중검정 함정에 들어갑니다. 과거 결과가 미래를 보장하지 않으며 투자 판단은 본인 책임입니다.