KIS 예상체결 상승률 FHPST01820000 함정 7가지
KIS 예상체결 상승/하락상위는 GET /uapi/domestic-stock/v1/ranking/exp-trans-updown, tr_id FHPST01820000입니다. 장 시작 전(FID_MKOP_CLS_CODE=0)이나 장 마감 직전(1)의 예상 상승률·하락률 상위 종목을 한 번에 받습니다. 다만 ① 응답에 '예상체결가'라는 이름의 필드가 없고(stck_prpr = 주식 현재가), ② 필터 파라미터 이름이 등락률 순위(FHPST01700000)와 다르며, ③ 관리종목·투자경고를 거르는 코드가 없고, ④ 모의투자 표시가 없습니다. 아래 7가지는 2026-10-13 받은 공식 저장소 koreainvestment/open-trading-api 원문 기준입니다.
목차
- 요청 원문 — URL·tr_id·파라미터 10개
- 함정 1 — 장전/장마감 코드가 형제 TR과 다르다
- 함정 2 — 필터 이름이 등락률 순위와 다르다
- 함정 3 — 관리종목·투자경고를 못 거른다
- 함정 4 — 응답에 예상체결가·순위 필드가 없다
- 함정 5 — 한글명이 이상한 필드 2개
- 함정 6 — 시장 코드는 J뿐, '0001'은 거래소
- 함정 7 — 모의투자 표시 없음·연속조회 10회
- 봇에서 쓰는 순서
이 글은 거래량·등락률 순위로 종목 스캐너 만들기(허브)에서 '예상체결' 순위 하나만 떼어 낸 편입니다. 장전 예상체결가를 종목 1개씩 보는 방법은 KIS 호가 조회 글, 한 종목의 예상체결가 흐름은 예상체결가 추이 FHPST01810000 글에 있습니다. 여기서는 시장 전체에서 예상 등락률 상위를 뽑는 TR만 다룹니다.
1. 요청 원문 — URL·tr_id·파라미터 10개
공식 Postman 컬렉션(실전계좌 v2.6)에 들어 있는 요청 그대로입니다. 헤더는 다른 시세 조회와 같고(authorization·appkey·appsecret·tr_id·custtype: P), 파라미터는 전부 쿼리스트링입니다.
GET {{PROD}}/uapi/domestic-stock/v1/ranking/exp-trans-updown
?fid_cond_mrkt_div_code=J
&fid_cond_scr_div_code=20182
&fid_input_iscd=0000
&fid_div_cls_code=0
&fid_aply_rang_prc_1=
&fid_vol_cnt=
&fid_pbmn=
&fid_blng_cls_code=0
&fid_mkop_cls_code=0
&fid_rank_sort_cls_code=0
tr_id: FHPST01820000 custtype: P
| 파라미터 | 공식 설명 원문 | 메모 |
|---|---|---|
fid_rank_sort_cls_code | 0:상승률 1:상승폭 2:보합 3:하락율 4:하락폭 5:체결량 6:거래대금 | '상승/하락상위'지만 체결량·거래대금 정렬도 됨 |
fid_cond_mrkt_div_code | 시장구분코드 (주식 J) | NX 표기 없음 |
fid_cond_scr_div_code | Unique key(20182) | 고정값 |
fid_input_iscd | 0000:전체, 0001:거래소, 1001:코스닥, 2001:코스피200, 4001: KRX100 | 함정 6 |
fid_div_cls_code | 0:전체 1:보통주 2:우선주 | 함정 3 |
fid_aply_rang_prc_1 | 입력값 없을때 전체 (가격 ~) | 하한만, 함정 2 |
fid_vol_cnt | 입력값 없을때 전체 (거래량 ~) | |
fid_pbmn | 입력값 없을때 전체 (거래대금 ~) 천원단위 | 천원 단위 |
fid_blng_cls_code | 0: 전체 | 다른 값 설명 없음 |
fid_mkop_cls_code | 0:장전예상1:장마감예상 | 함정 1 |
2. 함정 1 — 장전/장마감 코드가 형제 TR과 다르다
FID_MKOP_CLS_CODE라는 같은 이름이 예상체결 계열 TR마다 다른 값을 씁니다. 공식 함수 독스트링 원문을 나란히 놓으면 이렇습니다.
| TR | 이름 | FID_MKOP_CLS_CODE |
|---|---|---|
FHPST01820000 | 예상체결 상승/하락상위 | 0:장전예상 / 1:장마감예상 |
FHPST01840000 | 예상체결지수 추이 | 1:장시작전 / 2:장마감 |
FHPST01810000 | 예상체결가 추이 | 0:전체 / 4:체결량 0 제외 (장전·장마감 선택 아님) |
지수 추이 코드를 그대로 복사해 "1"을 넣으면, 장전 순위를 받으려던 봇이 장마감 예상 순위를 받습니다. 장 시작 전 08:50에 호출했다면 장마감 예상 데이터가 어떻게 나오는지는 명세에 없으니, 값을 확인하지 않은 채 갭 필터를 돌리게 됩니다. TR마다 코드표를 따로 상수로 두는 것이 안전합니다.
3. 함정 2 — 필터 이름이 등락률 순위와 다르다
같은 '순위분석' 묶음인데 가격·거래량 필터의 파라미터 이름이 TR마다 다릅니다.
| 필터 | 예상체결 상승/하락 FHPST01820000 | 등락률 순위 FHPST01700000 | 시간외 예상체결등락률 FHKST11860000 |
|---|---|---|---|
| 가격 | fid_aply_rang_prc_1 (하한만) | fid_input_price_1·_2 | fid_input_price_1·_2 |
| 거래량 | fid_vol_cnt | fid_vol_cnt | fid_input_vol_1 |
| 거래대금 | fid_pbmn (천원) | 없음 | 없음 |
| 등락률 범위 | 없음 | fid_rsfl_rate1·2 | 없음 |
| 화면 코드 | 20182 | 20170 | 11186 |
등락률 순위용으로 만든 params 딕셔너리에 tr_id만 바꿔 쓰면, fid_input_price_1은 이 TR이 모르는 키라 가격 필터가 조용히 빠집니다. 에러가 나지 않으니 "1,000원 이하 동전주 제외"가 적용됐다고 믿고 넘어가기 쉽습니다. 또 가격 상한 파라미터가 없으므로 "5,000~50,000원" 같은 범위는 받은 뒤 직접 잘라야 합니다.
4. 함정 3 — 관리종목·투자경고를 못 거른다
허브 글에서 다룬 등락률 순위 FHPST01700000은 fid_trgt_exls_cls_code 10자리(투자위험/경고/주의·관리종목·정리매매·불성실공시·우선주·거래정지·ETF·ETN·신용주문불가·SPAC)로 대상을 뺄 수 있습니다. 시간외 예상체결등락률 FHKST11860000도 fid_div_cls_code에 1:관리종목, 2:투자주의, 3:투자경고 같은 값을 둡니다.
반면 FHPST01820000의 fid_div_cls_code는 0 전체 / 1 보통주 / 2 우선주뿐입니다. 장전 예상 상승률 상위에는 거래가 얇은 관리종목·정리매매 종목이 섞이기 쉬운데, 요청 단계에서 뺄 방법이 없습니다. 받은 종목코드로 현재가 시세를 다시 조회해 mang_issu_cls_code·iscd_stat_cls_code로 거르는 단계가 필요합니다(mang_issu_cls_code 글). 종목 수만큼 호출이 늘어나니 초당 호출 제한(EGW00201)도 같이 계산해야 합니다(EGW00201 글).
5. 함정 4 — 응답에 예상체결가·순위 필드가 없다
공식 예제 chk_exp_trans_updown.py의 COLUMN_MAPPING 원문입니다(응답 output 배열의 필드 15개).
COLUMN_MAPPING = {
'stck_shrn_iscd': '주식 단축 종목코드',
'hts_kor_isnm': 'HTS 한글 종목명',
'stck_prpr': '주식 현재가',
'prdy_vrss': '전일 대비',
'prdy_vrss_sign': '전일 대비 부호',
'prdy_ctrt': '전일 대비율',
'stck_sdpr': '주식 기준가',
'seln_rsqn': '매도 잔량',
'askp': '매도호가',
'bidp': '매수호가',
'shnu_rsqn': '매수2 잔량',
'cntg_vol': '체결 거래량',
'antc_tr_pbmn': '체결 거래대금',
'total_askp_rsqn': '총 매도호가 잔량',
'total_bidp_rsqn': '총 매수호가 잔량'
}
NUMERIC_COLUMNS = []
두 가지가 빠져 있습니다. 첫째, '예상체결가'라는 이름의 필드가 없습니다. 장전 예상 순위에서 보고 싶은 값은 예상체결가인데, 명세상 이름은 stck_prpr '주식 현재가'입니다. 시간외 예상체결등락률 FHKST11860000은 ovtm_untp_antc_cnpr(시간외 단일가 예상 체결가)처럼 '예상'을 이름에 박아 두는 것과 대조됩니다. 장전에 stck_prpr가 예상체결가인지 전일 종가인지는 명세만으로 확정할 수 없으니, 첫 호출 때 stck_sdpr(기준가)·prdy_vrss와 같이 로그로 남겨 stck_sdpr + prdy_vrss == stck_prpr인지 확인하세요.
둘째, 순위 필드가 없습니다. FHKST11860000에는 data_rank(데이터 순위)가 있지만 이 TR에는 없어서, 순위는 응답 배열 순서로만 알 수 있습니다. 연속조회로 여러 페이지를 이어 붙이면 순서가 곧 순위라는 가정을 지켜야 합니다. 그리고 NUMERIC_COLUMNS = [] — 공식 예제조차 숫자 변환을 하지 않으니 모든 값이 문자열로 남습니다.
6. 함정 5 — 한글명이 이상한 필드 2개
shnu_rsqn= '매수2 잔량' — 짝인seln_rsqn은 '매도 잔량'인데 매수 쪽에만 '2'가 붙어 있습니다. 2차 호가 잔량인지 단순 오기인지 저장소 어디에도 설명이 없습니다. 이 값을 '최우선 매수 잔량'으로 단정해 매수세 판단에 쓰지 말고, 총잔량total_bidp_rsqn을 쓰는 편이 안전합니다.antc_tr_pbmn= '체결 거래대금' — 필드명 앞의antc는 다른 TR에서 '예상'(anticipated)으로 쓰이는 약어인데 한글명은 '체결'입니다. 단위도 적혀 있지 않습니다. 요청의fid_pbmn은 천원 단위라고 명시돼 있지만 응답 단위가 같은지는 알 수 없으니, 거래대금 필터는 요청 파라미터로 걸고 응답값으로 다시 비교하지 않는 편이 낫습니다.
7. 함정 6 — 시장 코드는 J뿐, '0001'은 거래소
fid_cond_mrkt_div_code 설명은 "주식 J" 하나입니다. 등락률 순위 FHPST01700000은 같은 파라미터에 J:KRX, NX:NXT를 적어 두었지만 이 TR에는 NX가 없습니다. NXT 프리마켓(08:00~08:50) 가격을 반영한 순위라고 가정하지 마세요(NXT·KRX 주문 라우팅 글).
fid_input_iscd의 0001은 이 TR에서 '거래소', 시간외 예상체결등락률에서는 '코스피'로 적혀 있습니다. 둘 다 유가증권시장을 가리키는 것으로 보이지만 표기가 달라, 코드표를 공유하는 상수에는 주석으로 TR별 원문을 남겨 두는 것이 좋습니다. 2001 코스피200, 4001 KRX100은 이 TR에만 적혀 있는 값입니다.
8. 함정 7 — 모의투자 표시 없음·연속조회 10회
공식 저장소 legacy/README.md의 API 목록에서 '국내주식 예상체결 상승/하락상위' 행의 모의투자 칸은 비어 있고, legacy/postman/README.md에는 실전 ⭕만 있습니다. 모의투자에서 안 되는 것들과 같은 부류로 보고, 실전 App Key로만 개발·검증한다고 계획해야 합니다.
연속조회는 응답 헤더 tr_cont가 "M"이면 다음 요청에 tr_cont: N을 붙여 이어 받는 구조이고, 공식 함수는 max_depth=10에서 멈추며 페이지 사이에 ka.smart_sleep()을 둡니다. 한 페이지 건수는 명세에 없습니다. 장전 08:50~09:00은 다른 봇도 몰리는 시간이니 페이지 수를 상한으로 두고, 필요한 상위 N개만 받으면 멈추세요.
9. 봇에서 쓰는 순서
아래는 공식 예제와 같은 URL·헤더·파라미터로 구성한 호출 함수입니다. 키는 환경변수에서 읽고, 코드에 넣지 않습니다.
import os, requests
BASE = "https://openapi.koreainvestment.com:9443" # 실전 (모의투자 표시 없음)
MKOP = {"premarket": "0", "closing": "1"} # 이 TR 전용 — FHPST01840000과 다름
def exp_updown(token, sort="0", mkop="premarket", market="0000", min_price="", max_pages=3):
headers = {"authorization": f"Bearer {token}",
"appkey": os.environ["KIS_APPKEY"], "appsecret": os.environ["KIS_APPSECRET"],
"tr_id": "FHPST01820000", "custtype": "P"}
params = {"fid_rank_sort_cls_code": sort, "fid_cond_mrkt_div_code": "J",
"fid_cond_scr_div_code": "20182", "fid_input_iscd": market,
"fid_div_cls_code": "1", # 보통주만 — 관리종목은 못 거른다
"fid_aply_rang_prc_1": min_price, # fid_input_price_1 아님
"fid_vol_cnt": "", "fid_pbmn": "", "fid_blng_cls_code": "0",
"fid_mkop_cls_code": MKOP[mkop]}
rows, tr_cont = [], ""
for _ in range(max_pages):
headers["tr_cont"] = tr_cont
r = requests.get(f"{BASE}/uapi/domestic-stock/v1/ranking/exp-trans-updown",
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")}')
rows += body.get("output", [])
if r.headers.get("tr_cont") != "M": # 공식 예제와 같은 판정
break
tr_cont = "N"
for i, row in enumerate(rows, 1):
row["rank"] = i # 순위 필드가 없어 배열 순서로 매김
return rows
쓰임새는 두 가지가 현실적입니다. ① 갭 필터 — 하락률 상위(sort="3")에 보유 종목이 있으면 시가 진입을 보류. ② 감시 목록 — 상승률 상위 중 보통주·관리종목 아님·최소 가격 이상만 남겨 09:00 이후 실시간 체결(H0STCNT0)을 구독. 장 마감 쪽은 15:20~15:30 종가 단일가 동안 mkop="closing"으로 예상 종가 상·하위를 보는 용도이며, 종목 1개의 장마감 예상체결가는 FHKST117300C0 글이 더 직접적입니다.
확인하지 못한 것: 실계좌로 장전 응답을 받아 위 필드 값을 대조하지는 않았습니다(이 글은 공식 저장소 2026-10-13 main의 예제·Postman·README 원문 대조). 한 페이지 건수, stck_prpr의 장전 의미, antc_tr_pbmn 단위는 KIS Developers 포털의 최신 명세로 다시 확인하세요. 예상 순위는 과거 데이터일 뿐 미래 가격을 말해 주지 않습니다.
자주 묻는 질문
FHPST01820000은 모의투자에서도 호출되나요?
공식 저장소 legacy/README.md의 API 목록에서 이 TR의 모의투자 칸은 비어 있고, Postman 안내(legacy/postman/README.md)에는 실전만 표시돼 있습니다. 모의투자 계정으로 개발할 때는 이 순위를 받을 수 없다고 보고 설계하는 편이 안전합니다.
장전 예상과 장마감 예상은 어떻게 구분하나요?
FID_MKOP_CLS_CODE에 0을 넣으면 장전예상, 1을 넣으면 장마감예상입니다. 같은 예상체결 계열인 예상체결지수 추이(FHPST01840000)는 1이 장시작전, 2가 장마감이라 값이 다르므로 코드를 복사해 쓸 때 주의해야 합니다.
관리종목·투자경고 종목을 순위에서 뺄 수 있나요?
이 TR의 분류 구분 코드(FID_DIV_CLS_CODE)는 0 전체, 1 보통주, 2 우선주뿐이라 종목 상태로 거를 수 없습니다. 등락률 순위(FHPST01700000)의 10자리 대상 제외 코드 같은 파라미터가 없으므로, 받은 뒤 현재가 시세의 mang_issu_cls_code 등으로 따로 걸러야 합니다.
장전 예상 상승률 1위 종목을 시가에 사면 되나요?
그렇게 단정할 수 없습니다. 예상체결가는 장 시작 전 호가가 바뀌면 계속 움직이고, 순위는 '그 순간의 예상'일 뿐입니다. 이 데이터는 매수 신호가 아니라 갭이 큰 종목을 미리 걸러 내거나 감시 목록을 만드는 용도로 쓰고, 전략 성과는 별도 백테스트로 확인해야 합니다.