AlgoLab Blog · 한국투자증권 KIS · 업종·지수 · 2026

코스피 지수 API — KIS 업종지수로 상승·하락 종목 수까지

KIS · 업종/지수 2026-09-12 · 약 7분 읽기 · 알고랩 AlgoLab
한 줄 요약 KIS API에서 코스피 지수는 종목 현재가 조회로 받는 게 아니라 업종 API로 받습니다. /uapi/domestic-stock/v1/quotations/inquire-index-pricetr_id FHPUP02100000, 파라미터는 FID_COND_MRKT_DIV_CODE=U(업종)와 FID_INPUT_ISCD코스피 0001 · 코스닥 1001 · 코스피200 2001 두 개뿐입니다. 응답에는 지수 값만 오는 게 아니라 상승·하락·상한·하한·보합 종목 수가 같이 들어 있어, 시장 내부 분포를 한 호출로 받을 수 있습니다.

이 글은 KIS API 현재가 조회(종목 하나의 시세·관리종목·VI)에서 지수 한 갈래만 떼어 낸 글입니다. 종목 시세는 그쪽에 있고, 여기서는 지수·업종 전용 엔드포인트만 다룹니다. 아래 스펙은 2026-09-12에 한국투자증권 공식 저장소 koreainvestment/open-trading-apimain 브랜치 예제 원문(inquire_index_price·inquire_index_daily_price· inquire_index_timeprice·inquire_index_tickprice·inquire_index_category_price· inquire_daily_indexchartprice)을 직접 받아 확인했습니다.

이 글에서 확인할 것

  1. 지수는 종목이 아니다 — 시장구분 U와 업종코드
  2. 업종·지수 API 6종과 tr_id
  3. 현재지수 응답 — 지수에 딸려 오는 시장 분포
  4. 일자별지수에 숨어 있는 d20_dsrt·invt_new_psdg
  5. 함정 — 공식 예제 주석의 K2 표기가 어긋나 있다
  6. 봇에 붙이기 — 시장 필터를 만드는 법과 한계

1. 지수는 종목이 아니다 — 시장구분 U와 업종코드

KIS API를 처음 붙일 때 흔한 막힘이 "코스피 지수 종목코드가 뭐냐"입니다. 답은 종목코드가 아니라 업종코드이고, 시장구분 자체가 다릅니다. 종목 시세는 FID_COND_MRKT_DIV_CODEJ(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엔드포인트
현재지수FHPUP02100000inquire-index-price
일자별지수 (D/W/M)FHPUP02120000inquire-index-daily-price
시간별지수 (분)FHPUP02110200inquire-index-timeprice
시간별지수 (틱)FHPUP02110100inquire-index-tickprice
구분별 전체시세FHPUP02140000inquire-index-category-price
기간별 지수 차트FHKUP03500100inquire-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,   # 상승 비율
    }
FHPUP02100000 U + 0001 · 1 호출 bstp_nmix_prpr · bstp_nmix_prdy_ctrt ascn / down / stnr / uplm / lslm _issu_cnt total_askp_rsqn · ntby_rsqn · 연중 최고저
지수 한 번 부르면 시장 분포와 잔량까지 같이 온다.

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_CODED(일별)·W(주별)·M(월별)입니다. 날짜는 YYYYMMDD 문자열입니다.

다만 계산식은 공개돼 있지 않습니다. 심리도와 이격도는 산출 방식이 여러 갈래라, 값을 그대로 전략에 넣기 전에 같은 기간 지수 시계열로 직접 재계산해 대조하십시오. pandas로 20일 이동평균을 구해 비율을 내면 몇 줄입니다. 숫자가 맞지 않는다면 정의가 다른 것이고, 정의를 모르는 지표를 조건에 넣는 것이 가장 위험합니다.

5. 함정 — 공식 예제 주석의 K2 표기가 어긋나 있다

FHPUP02140000(국내업종 구분별전체시세)는 파라미터가 다섯 개로 늘어납니다. FID_COND_SCR_DIV_CODE20214라는 고정값(Unique key)을 넣어야 하고, FID_MRKT_CLS_CODEFID_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_CODE0부터 하나씩 실제로 호출해 돌아오는 업종명으로 의미를 확인한 뒤 고정하십시오. 증권사 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. 확인한 것과 확인하지 않은 것

자주 묻는 질문

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) output2d20_dsrt(20일 이격도)와 invt_new_psdg(투자 신 심리도)가 있습니다. 계산식은 공개돼 있지 않으니 pandas로 재계산해 대조한 뒤 쓰십시오.

지수 분봉이나 기간별 차트도 받을 수 있나요?

분 단위는 FHPUP02110200, 틱은 FHPUP02110100, 일·주·월은 FHPUP02120000, 기간별 차트는 FHKUP03500100입니다. 종목 차트와 경로·필드가 다르므로 함수를 분리하십시오.

지수로 봇을 멈추게 하는 필터를 만들어도 되나요?

구현은 간단하지만 어떤 임계값이 좋은지는 이 글이 답할 수 없습니다. 필터는 표본 수를 줄여 검증을 어렵게 만들고, 여러 값을 돌려 최적값을 고르면 다중검정 함정에 들어갑니다. 과거 결과가 미래를 보장하지 않으며 투자 판단은 본인 책임입니다.

시장 상황에 반응하는 봇이 필요하다면

지수·업종 데이터 수집부터 진입 게이트 설계까지 맞춰 만들어 드립니다. 24시간 빠른 답변 가능합니다.

무료 상담 시작하기