AlgoLab Blog · 한국투자증권 시세 · 2026

mang_issu_cls_code — 봇에서 관리종목 거르기

KIS · 유니버스 필터 2026-09-23 · 약 7분 읽기 · 알고랩 AlgoLab
한 줄 요약

관리종목·투자경고를 거르려고 새 API 를 찾을 필요가 없습니다. 한국투자증권 KIS API 의 주식현재가 시세(inquire-price, tr_id: FHKST01010100) 응답에 mang_issu_cls_code(관리종목여부)·mrkt_warn_cls_code(시장경고코드)·invt_caful_yn(투자유의여부)·sltr_yn(정리매매여부)·short_over_yn(단기과열여부)·temp_stop_yn(임시 정지 여부)가 이미 같이 옵니다. 문제는 종목당 1콜이라는 것 — 2,900종목을 이걸로 훑으면 EGW00201 에 걸립니다. 그래서 전 종목은 kospi_code.mst·kosdaq_code.mst 마스터파일로 한 번에 거르고, 주문 직전에만 현재가로 재확인하는 2단 구조를 씁니다. 함정은 두 경로의 필드명이 다르다는 것입니다 — 마스터파일 쪽은 mang_issu_yn·mrkt_alrm_cls_code 이고, 시장경고 값은 00 해당없음 · 01 투자주의 · 02 투자경고 · 03 투자위험 입니다.

이 글은 KIS 주식현재가 시세 FHKST01010100 글에서 위험 플래그 한 갈래만 떼어 낸 글입니다. 현재가 응답 전체 필드와 호가·체결 구조는 그쪽을 보시고, 여기서는 “이 종목을 사도 되는가” 만 다룹니다.

목차

  1. 왜 이걸 안 거르면 백테스트가 무너지나
  2. 경로 두 개 — 종목당 1콜 vs 전 종목 한 번에
  3. REST 경로: 현재가 응답의 플래그 8개
  4. 마스터파일 경로: 전 종목을 한 번에
  5. 함정 — 같은 뜻, 다른 이름
  6. 봇에 붙이는 2단 구조
  7. 남는 한계

1. 왜 이걸 안 거르면 백테스트가 무너지나

주문이 거부되는 것은 아닙니다. 체결되는 방식이 달라집니다. 한국거래소는 코스닥 관리종목의 매매방식을 연속적 경쟁매매에서 30분 단위의 주기적 단일가매매로 바꿔 운영하고 있고, 정리매매 종목은 가격제한폭 확대 적용의 예외로 분류돼 있습니다. 지정가를 냈는데 즉시 체결되지 않고 다음 단일가 시점까지 기다리게 되는 상태가 됩니다.

이게 왜 문제냐면, 백테스트는 거의 예외 없이 “분봉 종가에 체결된다” 를 가정하기 때문입니다. 실제로는 30분 뒤 단일가에 체결되고, 그 사이 호가가 크게 벌어져 있습니다. 전략이 틀린 것이 아니라 체결 가정이 틀린 것인데, 결과는 “백테스트는 좋았는데 실전은 다르다” 로 나타납니다. 백테스트와 실전이 갈리는 지점에서 다룬 괴리의 흔한 원인 하나가 정확히 이것입니다.

제도는 바뀝니다. 관리종목 지정 사유, 단일가 주기, 정리매매 기간과 가격제한폭 예외 범위는 시장(유가증권·코스닥)별로 다르고 개정됩니다. 위 내용은 발행 시점 기준이며, 한국거래소 공식 규정에서 현재 내용을 확인하십시오. 이 글이 다루는 것은 제도 해설이 아니라 봇이 그 상태를 어떤 필드로 읽는가 입니다.

2. 경로 두 개 — 종목당 1콜 vs 전 종목 한 번에

한국투자증권 KIS API 로 “이 종목이 관리종목인가” 를 아는 길은 두 개고, 쓰임새가 완전히 다릅니다.

구분REST 현재가종목 마스터파일
무엇inquire-price
tr_id: FHKST01010100
kospi_code.mst
kosdaq_code.mst
단위종목 1개 = 1콜파일 1개 = 전 종목
최신성실시간(현재가와 동시)배포 시점(하루 단위)
호출 한도계정 한도 소모 · EGW00201 위험API 한도와 무관
쓸 자리주문 직전 재확인유니버스 구성 · 백테스트

대부분의 사고는 이 둘을 바꿔 쓰는 데서 납니다. 유니버스 2,900종목을 현재가로 훑으면 시세 조회와 주문이 써야 할 초당 한도까지 같이 태우고, 반대로 마스터파일만 믿으면 장중에 새로 걸린 임시 정지를 놓칩니다.

kospi_code.mst 하루 1회 · 전 종목 유니버스 확정 관리·경고·정리매매 제외 신호 계산 30~50종목으로 축소 inquire-price 재확인 temp_stop_yn · mrkt_warn_cls_code 주문 전송 통과한 종목만
하루 1회 마스터파일 + 주문 직전 1콜 — 한도를 태우지 않고 장중 변화를 잡는 2단 구조

3. REST 경로: 현재가 응답의 플래그 8개

한국투자증권 공식 저장소 koreainvestment/open-trading-api 의 예제 chk_inquire_price.py 와 MCP 용 data.csv 컬럼 매핑에 적힌 이름 그대로입니다.

필드공식 설명봇에서의 판단
mang_issu_cls_code관리종목여부해당이면 무조건 제외
mrkt_warn_cls_code시장경고코드00 외에는 제외(아래 값표)
invt_caful_yn투자유의여부코스닥 환기종목 계열 — 제외 권장
sltr_yn정리매매여부무조건 제외 — 상장폐지 절차
short_over_yn단기과열여부단일가 전환 가능 — 체결 가정 검토
temp_stop_yn임시 정지 여부주문 보류 — 장중에 바뀜
ssts_yn공매도가능여부숏 전략일 때만 의미
iscd_stat_cls_code종목 상태 구분 코드보통주·우선주·ETF 등 구분

시장경고 코드 값

값의 뜻은 공식 저장소의 구조체 헤더 종목마스터정보(코스피).h 주석에 그대로 적혀 있습니다.

/* 종목마스터정보(코스피).h — 한국투자증권 공식 저장소 발췌 */
char    short_over_cls_code[1];      /* 단기과열종목구분코드 0:해당없음 */
char    trht_yn[1];                  /* 거래정지 여부 */
char    sltr_yn[1];                  /* 정리매매 여부 */
char    mang_issu_yn[1];             /* 관리 종목 여부 */
char    mrkt_alrm_cls_code[2];       /* 시장 경고 구분 코드 (00:해당없음 01:투자주의 */
                                     /* 02:투자경고 03:투자위험 */
char    mrkt_alrm_risk_adnt_yn[1];   /* 시장 경고위험 예고 여부 */
char    insn_pbnt_yn[1];             /* 불성실 공시 여부 */
char    byps_lstn_yn[1];             /* 우회 상장 여부 */
char    ssts_hot_yn[1];              /* 공매도과열종목여부 */
char    stange_runup_yn[1];          /* 이상급등종목여부 */

실제 응답에서 꺼내기

import requests

BASE = "https://openapi.koreainvestment.com:9443"

def price_flags(token, appkey, appsecret, code):
    r = requests.get(
        f"{BASE}/uapi/domestic-stock/v1/quotations/inquire-price",
        headers={
            "authorization": f"Bearer {token}",
            "appkey": appkey,
            "appsecret": appsecret,
            "tr_id": "FHKST01010100",   # 모의투자는 별도 확인
            "custtype": "P",
        },
        params={"FID_COND_MRKT_DIV_CODE": "J", "FID_INPUT_ISCD": code},
        timeout=5,
    )
    o = r.json()["output"]
    return {
        "price":      int(o["stck_prpr"]),
        "managed":    o["mang_issu_cls_code"],   # 관리종목여부
        "warn":       o["mrkt_warn_cls_code"],   # 00/01/02/03
        "caution":    o["invt_caful_yn"],        # 투자유의여부
        "liquidation":o["sltr_yn"],              # 정리매매여부
        "overheat":   o["short_over_yn"],        # 단기과열여부
        "halted":     o["temp_stop_yn"],         # 임시 정지 여부
    }

def tradable(f, allow_caution=False):
    if f["halted"] == "Y":           return False, "임시 정지"
    if f["liquidation"] == "Y":      return False, "정리매매"
    if f["managed"] not in ("", "N", "0"): return False, "관리종목"
    if f["warn"] != "00":
        if not (allow_caution and f["warn"] == "01"):
            return False, f"시장경고 {f['warn']}"
    if f["overheat"] == "Y":         return False, "단기과열"
    return True, "ok"

값의 표기는 방어적으로 읽으십시오. 여부 계열 필드는 환경과 시장 구분에 따라 Y/N 으로 오기도 하고 0/1 또는 빈 문자열로 오기도 합니다. == "Y" 하나로만 판정하면 표기가 다른 순간 필터가 조용히 통과시킵니다. 위 코드처럼 “정상값 집합에 없으면 거른다” 쪽으로 쓰고, 처음 붙일 때 실제 응답을 종목 몇 개로 찍어 확인하십시오. 응답 원문 확인 습관은 KIS API 에러코드 정리에서 다룬 것과 같은 이유입니다.

4. 마스터파일 경로: 전 종목을 한 번에

한국투자증권은 종목 마스터파일을 공개 URL 로 배포합니다. 공식 저장소의 kis_kospi_code_mst.py 가 내려받기와 파싱을 그대로 보여 줍니다.

https://new.real.download.dws.co.kr/common/master/kospi_code.mst.zip
https://new.real.download.dws.co.kr/common/master/kosdaq_code.mst.zip

파일은 cp949 인코딩의 고정폭 구조고, 뒤쪽 228바이트가 속성 영역입니다. 파싱 자체는 kospi_code.mst 파싱 — cp949·228자 고정폭에 코드 전문이 있으니 여기서는 반복하지 않고, 파싱 결과에서 어떤 컬럼을 보는지 만 봅니다. 공식 파서가 붙이는 컬럼 이름은 한글입니다.

# kis_kospi_code_mst.py 의 part2_columns 중 위험 플래그 구간
'기준가', '매매수량단위', '시간외수량단위',
'거래정지', '정리매매', '관리종목', '시장경고', '경고예고',
'불성실공시', '우회상장', '락구분', '액면변경', '증자구분', '증거금비율',
...
'우선주', '공매도과열', '이상급등', 'KRX300', 'KOSPI', ...
import pandas as pd

def build_universe(df):
    """마스터파일 DataFrame -> 거래 가능 유니버스"""
    ok = df[
        (df['거래정지']   != 'Y') &
        (df['정리매매']   != 'Y') &
        (df['관리종목']   != 'Y') &
        (df['시장경고'].astype(str).str.zfill(2) == '00') &
        (df['경고예고']   != 'Y') &
        (df['불성실공시'] != 'Y') &
        (df['단기과열']   != 'Y') &
        (df['공매도과열'] != 'Y') &
        (df['이상급등']   != 'Y') &
        (df['SPAC']       != 'Y')      # 코스닥은 '기업인수목적회사여부'
    ].copy()
    return ok[['단축코드', '한글명', '시가총액']]

# 하루 한 번만 돌린다. 장중에 다시 내려받지 않는다.
kospi = get_kospi_master_dataframe(BASE_DIR)
universe = build_universe(kospi)
print(len(kospi), "->", len(universe))

코스피와 코스닥은 컬럼 이름이 다릅니다. 공식 파서 기준으로 코스피는 SPAC·단기과열 인데, 코스닥은 기업인수목적회사여부·단기과열종목구분코드 이고 코스닥에만 (코스닥)투자주의환기종목여부 가 있습니다. 두 시장을 pd.concat 으로 합치기 전에 컬럼명을 통일하지 않으면, 합친 뒤 NaN!= 'Y' 를 통과해 필터가 절반만 작동합니다.

5. 함정 — 같은 뜻, 다른 이름

이 글에서 가장 많이 실수가 나는 지점입니다. REST 응답과 마스터파일 구조체는 같은 개념에 다른 필드명을 씁니다.

개념REST inquire-price마스터파일 구조체
관리종목mang_issu_cls_codemang_issu_yn여부
시장경고mrkt_warn_cls_codemrkt_alrm_cls_code00~03
경고 예고없음mrkt_alrm_risk_adnt_yn여부
거래정지temp_stop_yn(임시 정지)trht_yn(거래정지)여부
정리매매sltr_ynsltr_yn여부
단기과열short_over_ynshort_over_cls_code여부 / 코드
공매도과열없음ssts_hot_yn여부
이상급등없음stange_runup_yn여부

정리하면 세 가지입니다.

6. 봇에 붙이는 2단 구조

정리하면 이렇게 됩니다.

  1. 장 시작 전 1회kospi_code.mst·kosdaq_code.mst 를 받아 유니버스를 만든다. 2,900종목이 보통 수백 종목 단위로 줄어든다.
  2. 장중 — 신호 계산은 이 유니버스 안에서만 한다. 관리종목·정리매매는 여기서 이미 없다.
  3. 주문 직전 1콜 — 실제로 낼 종목에만 inquire-price 를 부르고 temp_stop_yn·mrkt_warn_cls_code 를 재확인한다. 어차피 현재가가 필요하므로 추가 호출이 아니다.

3번이 핵심입니다. 어차피 지정가를 정하려면 현재가를 불러야 하고, 그 응답에 위험 플래그가 같이 들어 있으므로 필터 비용이 사실상 0 입니다. 이 구조면 유니버스 스캔이 계정 초당 한도를 잡아먹지 않아 EGW00201 위험도 없습니다 — 호출 한도 설계는 API 호출 제한 설계에 정리해 두었습니다.

백테스트에도 같은 필터를 거십시오. 실전 봇에만 필터를 걸고 백테스트는 전 종목으로 돌리면, 백테스트가 실전에서는 애초에 사지 않았을 종목의 수익을 포함하게 됩니다. 이건 생존편향과 방향만 반대인 같은 종류의 오염입니다. 과거 시점의 관리종목 지정 이력은 마스터파일 하루치로는 알 수 없으므로, 마스터파일을 매일 저장해 쌓아 두는 것이 사실상 유일한 방법입니다.

7. 남는 한계

유니버스 필터부터 막히셨다면

전략은 정해졌는데 “뭘 빼야 하는지” 에서 멈추는 경우가 많습니다. 24시간 빠른 답변 가능합니다.

자동매매 제작 상담하기

알고랩(퀀트웍스)은 투자자문업·투자일임업을 영위하지 않으며, 본 글은 특정 종목의 매매를 권유하지 않습니다. 소프트웨어 제작·기술 정보 제공 목적의 글이며, 투자 판단과 그 결과에 대한 책임은 투자자 본인에게 있습니다. API 스펙·거래소 제도는 발행 시점 기준이며 변경될 수 있으므로 한국투자증권 KIS Developers 및 한국거래소 공식 자료를 확인하십시오.