AlgoLab Blog · KIS API 실무 · 2026

KIS 장마감 예상체결가 FHKST117300C0 — 함정 5가지

KIS API · 기본시세 2026-10-10 · 약 8분 읽기 · 알고랩 AlgoLab
한 줄 요약

한국투자증권 KIS API의 국내주식 장마감 예상체결가는 GET /uapi/domestic-stock/v1/quotations/exp-closing-price에 tr_id FHKST117300C0으로 호출하고, 필수 파라미터 5개 중 FID_COND_SCR_DIV_CODE=11173은 고정입니다. 종가 단일가 구간에 상한가·하한가로 마감할 것으로 예상되는 종목 목록을 한 번에 받는 용도인데, 응답 9필드에 '예상체결가'라는 이름의 필드가 없고(stck_prpr = 주식 현재가), 연속조회를 하지 않으며, 정렬 기준인 '직전 가격'이 응답에 없습니다. 공식 저장소 기준 모의투자 제공 칸은 비어 있어 실전 앱키 전용입니다.

목차

  1. 스펙 한 장
  2. 요청 파라미터 5개 — 출처마다 다른 설명
  3. 요청·응답 실물
  4. 함정 5가지
  5. 봇에서 쓰는 법 — 종가 주문 직전 점검
  6. 자주 묻는 질문

한 종목의 예상체결가는 허브 글 KIS API 호가 조회 FHKST01010200의 output2(antc_cnpr·antc_vol)로 받습니다. 이 글은 반대 방향 — "지금 종가 단일가에서 상한가·하한가로 끝날 것 같은 종목이 시장 전체에 뭐가 있나"를 받는 순위형 API 하나만 떼어 냅니다. 출처는 한국투자증권 공식 GitHub 저장소 koreainvestment/open-trading-api의 examples_llm/domestic_stock/exp_closing_price/(exp_closing_price.py·chk_exp_closing_price.py), examples_user/domestic_stock/domestic_stock_functions.py, MCP/KIS Code Assistant MCP/data.csv, legacy/README.md·legacy/postman/README.md, 실전계좌_POSTMAN_샘플코드_v2.6.json입니다(2026-10-10 zipball 기준).

1. 스펙 한 장

항목값
API명[국내주식] 기본시세 > 국내주식 장마감 예상체결가 [국내주식-120]
HTS 화면eFriend Plus [0183] 장마감 예상체결가
메서드 · URLGET /uapi/domestic-stock/v1/quotations/exp-closing-price
tr_idFHKST117300C0 (실전)
헤더authorization(Bearer access_token) · appkey · appsecret · tr_id · custtype=P
모의투자legacy/README.md 제공 칸 공란
실전투자legacy/postman/README.md ⭕ · Postman v2.6 "J_국내주식 장마감 예상체결가"
연속조회없음 — 공식 함수가 tr_cont 자리에 "" 고정, 재귀 호출 없음
응답output 배열 1개, 행당 9필드

같은 '예상체결' 계열 API가 저장소에 여럿 있어 헷갈리기 쉽습니다. 용도별로 나누면 이렇습니다.

용도APItr_id
종목 1개의 지금 예상체결가주식현재가 호가/예상체결 (output2)FHKST01010200
종목 1개의 예상체결가 시간대별 흐름국내주식 예상체결가 추이FHPST01810000
예상체결 기준 등락률 순위국내주식 예상체결 상승/하락상위FHPST01820000
장마감 상·하한가 예상 종목 목록국내주식 장마감 예상체결가FHKST117300C0
예상체결 실시간 푸시국내주식 실시간예상체결 (KRX/NXT/통합)H0STANC0 · H0NXANC0 · H0UNANC0

legacy/README.md에서 모의 칸에 ⭕가 있는 것은 호가/예상체결(FHKST01010200)뿐이고 나머지 예상체결 계열은 공란이니, 모의 서버 openapivts에서 개발하던 봇이라면 시세 조회만 실전 키로 돌리는 구성이 필요합니다. 막히는 목록은 KIS 모의투자 한계에 있습니다.

2. 요청 파라미터 5개 — 출처마다 다른 설명

공식 함수 exp_closing_price()는 다섯 개 모두 빈 문자열이면 호출 전에 ValueError로 멈춥니다. 설명은 출처마다 조금씩 다릅니다.

파라미터함수 주석 · data.csvPostman v2.6
FID_COND_MRKT_DIV_CODE조건시장분류코드 (J:주식)시장 분류 코드 (J : 주식)
FID_INPUT_ISCD0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200, 4001: KRX100업종코드 '0000':전체, '0001':코스피, '1001':코스닥, '2001':코스피200, '4001':KRX100
FID_RANK_SORT_CLS_CODE0:전체, 1:상한가마감예상, 2:하한가마감예상, 3:직전대비상승률상위, 4:직전대비하락률상위같음
FID_COND_SCR_DIV_CODE조건화면분류코드 (ex. 11173)화면 분류 코드(11173 입력)
FID_BLNG_CLS_CODE소속구분코드 (ex. 0:전체, 1:종가범위연장)소속 구분 코드 (값 목록 없음)

0001을 '거래소'와 '코스피'로 다르게 적었지만 가리키는 시장은 같습니다(유가증권시장). 공매도 순위(FHPST04820000)에 있던 코스닥150 3003은 이 API 목록에는 없습니다. 같은 저장소의 examples_llm 판 함수 시그니처 주석은 FID_BLNG_CLS_CODE를 "소속구분코드"로만 적고, 값 목록은 독스트링에만 있습니다.

3. 요청·응답 실물

Postman 샘플의 원본 요청 줄입니다(저장소 원문 그대로).

{{PROD}}/uapi/domestic-stock/v1/quotations/exp-closing-price?fid_cond_mrkt_div_code=J&fid_cond_scr_div_code=11173&fid_input_iscd=0001&fid_blng_cls_code=0&fid_rank_sort_cls_code=0

응답 필드는 chk_exp_closing_price.py의 COLUMN_MAPPING이 전부입니다.

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 = ['전일 대비율', '기준가 대비 현재가 비율']

공식 함수(ka._url_fetch)를 거치지 않고 requests로 직접 부르면 이렇게 됩니다. 앱키·토큰은 환경변수에서 읽고 코드에 쓰지 않습니다(API 키 보안).

import os, requests, pandas as pd
from datetime import datetime
from zoneinfo import ZoneInfo

URL = "https://openapi.koreainvestment.com:9443/uapi/domestic-stock/v1/quotations/exp-closing-price"
headers = {
    "content-type": "application/json; charset=utf-8",
    "authorization": f"Bearer {os.environ['KIS_TOKEN']}",
    "appkey": os.environ["KIS_APPKEY"],
    "appsecret": os.environ["KIS_APPSECRET"],
    "tr_id": "FHKST117300C0",
    "custtype": "P",
}

def exp_closing(iscd="0000", sort="2"):          # 2 = 하한가마감예상
    params = {
        "FID_COND_MRKT_DIV_CODE": "J",
        "FID_INPUT_ISCD": iscd,
        "FID_RANK_SORT_CLS_CODE": sort,
        "FID_COND_SCR_DIV_CODE": "11173",         # 고정
        "FID_BLNG_CLS_CODE": "0",
    }
    r = requests.get(URL, headers=headers, params=params, timeout=5)
    body = r.json()
    if body.get("rt_cd") != "0":
        raise RuntimeError(f"{body.get('msg_cd')} {body.get('msg1')}")
    df = pd.DataFrame(body.get("output") or [])
    df["fetched_at"] = datetime.now(ZoneInfo("Asia/Seoul"))   # 응답에 시각 필드가 없다
    return df

rt_cd가 "0"이 아닐 때의 msg_cd 해석은 KIS API 에러코드를, 장 막판에 종목을 여럿 조회하다 EGW00201(초당 거래건수 초과)이 나면 EGW00201 해결을 보십시오.

4. 함정 5가지

① '예상체결가' 필드가 없다 — stck_prpr는 "주식 현재가"

API 이름은 "장마감 예상체결가"인데 응답 9필드 어디에도 antc_cnpr(예상 체결가)가 없습니다. 가격 필드는 stck_prpr 하나이고 공식 매핑은 '주식 현재가'입니다. 종가 단일가 구간에 이 값이 예상체결가를 담는지, 직전 체결가를 담는지는 저장소 어디에도 적혀 있지 않습니다. 봇이 이 값으로 가격 판단을 한다면 같은 시각에 같은 종목을 FHKST01010200으로 불러 output2.antc_cnpr와 대조하는 검증을 한 번은 돌려야 합니다.

def cross_check(code, df):
    r = requests.get(
        "https://openapi.koreainvestment.com:9443/uapi/domestic-stock/v1/quotations/inquire-asking-price-exp-ccn",
        headers={**headers, "tr_id": "FHKST01010200"},
        params={"FID_COND_MRKT_DIV_CODE": "J", "FID_INPUT_ISCD": code}, timeout=5).json()
    antc = r["output2"]["antc_cnpr"]
    prpr = df.loc[df["stck_shrn_iscd"] == code, "stck_prpr"].iloc[0]
    return {"code": code, "exp_closing.stck_prpr": prpr, "orderbook.antc_cnpr": antc}

② 연속조회를 하지 않는다 — 받은 게 전부라는 보장이 없다

같은 저장소의 순위 API(FHPST04820000 등)는 응답 헤더 tr_cont가 M/F면 N으로 다시 부르는 재귀(max_depth 기본 10)가 들어 있습니다. exp_closing_price()는 ka._url_fetch(API_URL, tr_id, "", params) 한 번으로 끝납니다. 몇 행까지 주는지 명세에 없으므로, 응답 헤더의 tr_cont를 직접 로그로 남겨 뒤에 더 있는지 확인하십시오. 연속조회 처리 패턴은 KIS 잔고 연속조회와 같습니다.

③ 정렬 기준 '직전'이 응답에 없다

FID_RANK_SORT_CLS_CODE의 3(직전대비상승률상위)·4(직전대비하락률상위)는 '직전' 가격 대비 등락률로 줄을 세우는데, 응답에는 prdy_*(전일 대비)와 sdpr_*(기준가 대비)만 있고 직전 가격·직전 대비율 필드가 없습니다. 받은 표를 봇이 같은 기준으로 다시 정렬하거나 검증할 방법이 없다는 뜻입니다. 정렬 순서에 의존하는 로직(예: "상위 5개만")을 쓴다면 prdy_ctrt처럼 응답에 있는 열로 직접 다시 정렬하고, 그 기준을 명세서에 적어 두는 편이 재현 가능합니다.

④ 전일 대비와 기준가 대비가 다른 날이 있다

응답에 prdy_vrss(전일 대비)와 sdpr_vrss_prpr(기준가 대비 현재가)가 따로 있습니다. 평소에는 기준가가 전일 종가와 같지만, 권리락·배당락·액면분할처럼 기준가가 조정되는 날에는 둘이 갈라집니다. 상한가·하한가 판정은 가격제한폭이 걸리는 기준가 쪽으로 해야 하는데, prdy_ctrt만 보고 "+29%니 상한가 근접"이라고 판단하면 기준가 조정일에 틀립니다. 두 열이 다르면 로그에 경고를 남기는 한 줄을 넣어 두십시오. 기준가·상하한가 필드는 현재가 API FHKST01010100에서 종목별로 확인할 수 있습니다.

⑤ 시장코드는 J뿐, 시간대 해석은 직접 해야 한다

허브의 FHKST01010200은 FID_COND_MRKT_DIV_CODE에 J(KRX)·NX(NXT)·UN(통합)을 받지만, 이 API의 공식 설명은 J:주식 하나입니다. 종가 단일가는 KRX 정규장 막판(통상 15:20~15:30) 구간이고, 응답에는 조회 시각도 장운영 구분 코드도 없습니다. 그래서 위 코드처럼 fetched_at을 직접 붙여야 나중에 "15:22에 본 목록"인지 "15:31에 본 목록"인지 구분됩니다. 종가 단일가 밖에서 이 API가 무엇을 돌려주는지는 저장소에 적혀 있지 않습니다. FID_BLNG_CLS_CODE=1(종가범위연장)도 의미 설명이 독스트링 한 줄뿐이라, 쓰려면 HTS [0183] 화면과 대조해 확인한 뒤 쓰십시오. KRX·NXT 시간대 차이는 NXT·KRX 주문 라우팅에 정리했습니다.

정규장 접속매매 KRX 종가 단일가 15:2015:30 FHKST117300C0 호출 + fetched_at 기록 하한가마감예상이면 종가 매수 보류
그림 — 종가 단일가 구간(KRX 공지 기준 확인)에서 목록을 받아 종가 주문 직전 점검에 쓰는 흐름. 응답에 시각 필드가 없어 조회 시각을 직접 남긴다.

5. 봇에서 쓰는 법 — 종가 주문 직전 점검

이 API는 "무엇을 살까"가 아니라 "이미 정한 종가 주문을 그대로 내도 되나"를 점검하는 데 맞습니다. 예를 들어 종가에 매수하는 리밸런싱·종가 진입 전략이라면, 주문 직전에 하한가마감예상(sort="2") 목록을 받아 대상 종목이 있으면 주문을 보류하고 사람에게 알립니다.

targets = {"005930", "000660"}                     # 오늘 종가 매수 예정 종목
low = exp_closing(iscd="0000", sort="2")           # 하한가마감예상
hit = targets & set(low["stck_shrn_iscd"])
for code in hit:
    row = low[low["stck_shrn_iscd"] == code].iloc[0]
    if row["prdy_vrss"] != row["sdpr_vrss_prpr"]:   # ④ 기준가 조정일 경고
        log.warning("%s 기준가≠전일종가", code)
    notify(f"{code} 하한가 마감 예상 — 종가 매수 보류 ({row['fetched_at']:%H:%M:%S})")
orders = [c for c in targets if c not in hit]

알림은 텔레그램 봇 모니터링 구조를 그대로 쓰면 됩니다. 장 막판에는 주문·취소·잔고 조회가 몰리므로 이 조회는 1회로 끝내고, 종목별 확인이 필요할 때만 ①의 cross_check를 붙입니다.

장마감 예상 목록은 그 순간의 예상일 뿐이며 실제 종가와 다를 수 있습니다. 상한가·하한가 마감 예상 종목이 이후 어떻게 움직일지는 이 API가 알려 주지 않으므로 매매 신호가 아니라 점검용 필터로 쓰십시오. 종가 단일가 시간·가격제한폭 등 시장 제도는 한국거래소 공지를, API 명세는 KIS Developers 공식 문서를 확인하십시오(2026-10-10 공식 저장소 기준).

6. 자주 묻는 질문

KIS 장마감 예상체결가 API의 tr_id와 URL은 무엇인가요?

tr_id는 FHKST117300C0이고 GET /uapi/domestic-stock/v1/quotations/exp-closing-price 로 호출합니다. FID_COND_MRKT_DIV_CODE=J, FID_COND_SCR_DIV_CODE=11173(고정), FID_INPUT_ISCD(0000 전체·0001 코스피·1001 코스닥·2001 코스피200·4001 KRX100), FID_RANK_SORT_CLS_CODE(0~4), FID_BLNG_CLS_CODE 다섯 개가 모두 필수입니다. 공식 저장소 기준 모의투자 제공 칸은 비어 있습니다.

응답의 stck_prpr가 예상체결가인가요?

공식 COLUMN_MAPPING은 stck_prpr를 '주식 현재가'로만 적고 있고, 응답에 antc_cnpr(예상 체결가) 필드는 없습니다. 종목별 예상체결가가 필요하면 주식현재가 호가/예상체결(FHKST01010200)의 output2.antc_cnpr를 쓰고, 두 값을 같은 시각에 한 번 대조해 보는 것이 안전합니다.

상한가마감예상 목록이 전부 다 오나요?

보장되지 않습니다. 공식 함수는 tr_cont를 빈 값으로 고정해 한 번만 호출하고 연속조회 재귀가 없습니다. 응답 헤더의 tr_cont 값을 로그로 남겨 뒤에 데이터가 더 있는지 확인하고, 필요하면 N으로 다시 호출하는 처리를 직접 넣어야 합니다.

하한가 마감 예상 종목은 다음 날 반등하나요?

그렇게 단정할 수 없습니다. 이 API는 종가 단일가 구간의 예상 상황을 보여 줄 뿐 이후 가격 방향을 알려 주지 않습니다. 자동매매에서는 매수·매도 신호보다 종가 주문 직전에 보류하거나 사람에게 알리는 점검 필터로 쓰는 것이 일반적입니다.

종가 주문까지 점검하는 봇, 만들어 드립니다

전략과 종목 조건만 알려 주시면 됩니다. 24시간 빠른 답변 가능합니다.

무료 상담 시작하기