AlgoLab Blog · 키움증권 REST API · 계좌 · 2026

키움 증거금율 API kt00011 — 증거금율이 3개로 온다

키움 · 계좌/증거금 2026-09-13 · 약 7분 읽기 · 알고랩 AlgoLab
한 줄 요약 "이 종목의 증거금율이 몇 %냐"에 답하는 것은 키움 REST API의 kt00011 증거금율별주문가능수량조회요청입니다. POST /api/dostk/acnt에 헤더 api-id: kt00011, 바디 stk_cd 하나면 됩니다. 다만 율이 하나로 오지 않습니다stk_profa_rt(종목증거금율)·profa_rt(계좌증거금율)·aplc_rt(적용증거금율) 세 개가 따로 오고, 주문에 실제로 쓰이는 것은 aplc_rt입니다. 그리고 이 세 필드는 % 기호가 붙은 문자열이라 float()에 그대로 넣으면 터집니다.

키움 주문가능금액 — kt00001 vs kt00010에서 답하지 못하고 남겨 둔 질문이 하나 있었습니다. "증거금율을 API로 알 수 있나요?" 그 두 TR은 증거금율 20%면 얼마, 40%면 얼마 하는 구간별 금액은 주는데, 이 종목이 몇 %짜리인지는 알려 주지 않습니다. 그래서 그 글의 코드는 율을 모르면 가장 보수적인 100% 기준으로 떨어지게 짜여 있었습니다.

빈칸을 채우는 것이 kt00011입니다. 이 글은 그 한 가지만 다룹니다. 기준은 키움증권 공식 저장소의 단일 명세 파일 kiwoom/_data/kiwoom_api_spec.json 원문(request.body·response.body 전수)입니다.

목차

  1. kt00011 호출 — 파라미터가 두 개뿐이다
  2. 함정 ① 증거금율이 3개로 온다
  3. 함정 ② 율에 % 기호가 붙어 있다
  4. 함정 ③ kt00012는 칸 수가 다르다
  5. kt00013 증거금세부내역 — 요청 바디가 없다
  6. 실전 코드 — 안전 수량 결정기
  7. 자주 묻는 질문

1. kt00011 호출 — 파라미터가 두 개뿐이다

요청 바디는 두 개입니다. 이웃 TR과 비교하면 차이가 바로 보입니다.

TR요청 바디필수
kt00011 증거금율별주문가능수량stk_cd(종목번호) · uv(매수가격)stk_cdY, uvN
kt00012 신용보증금율별주문가능수량stk_cd · uv동일
kt00010 주문인출가능금액stk_cd · trde_tp · uv · io_amt · trde_qty · exp_buy_unpstk_cd·trde_tp·uv 전부 Y
kt00013 증거금세부내역없음계좌 단위

uv가 선택값이라는 게 실무에서 큽니다. kt00010은 매수가격이 필수라 가격 없이는 물어볼 수 없는 구조였습니다. 시장가로 사는 봇은 최우선 매도호가를 임의로 넣어야 했죠. kt00011uv를 비워도 호출이 되므로 "이 종목 증거금율이 몇 %냐"만 먼저 물어볼 수 있습니다. 다만 가격을 비우면 응답의 수량 칸이 어떤 기준으로 채워지는지는 명세에 적혀 있지 않으니, 수량이 필요하면 uv를 넣으십시오.

import requests

def margin_rate(base_url, token, stk_cd, price=None):
    """kt00011 증거금율별주문가능수량조회요청"""
    body = {"stk_cd": stk_cd}
    if price is not None:
        body["uv"] = str(int(price))        # 선택 — 수량이 필요할 때만
    res = requests.post(
        f"{base_url}/api/dostk/acnt",
        headers={
            "Content-Type": "application/json;charset=UTF-8",
            "authorization": f"Bearer {token}",
            "api-id": "kt00011",            # ← 키움은 tr_id 가 아니라 api-id 헤더
        },
        json=body, timeout=5,
    )
    res.raise_for_status()
    return res.json()

2. 함정 ① 증거금율이 3개로 온다

응답 response.body 36개 항목 중 맨 앞 세 줄이 이 TR의 존재 이유입니다.

필드한글명무엇인가
stk_profa_rt종목증거금율종목에 증권사가 매긴 율
profa_rt계좌증거금율계좌에 걸린 율
aplc_rt적용증거금율실제로 적용되는 값 — 봇이 읽어야 할 것

종목 율만 읽으면 틀립니다. 종목 쪽과 계좌 쪽에 서로 다른 율이 걸려 있을 수 있고, 그때 주문 심사에 쓰이는 것은 aplc_rt입니다. 이름이 가장 짧고 평범해서 stk_profa_rt(종목)를 "이 종목의 증거금율"로 착각하기 딱 좋습니다. 세 값이 항상 같다고 가정하지 말고 aplc_rt를 기준으로 쓰십시오.

kt00011 응답 구조 — 율 3개 + 구간 7칸 stk_profa_rt 종목증거금율 profa_rt 계좌증거금율 aplc_rt 적용 ← 이것 profa_20… profa_30… profa_40… profa_50… profa_60… profa_100… 각 칸마다 ord_alow_amt · ord_alowq · pred_reu_amt · tdy_reu_amt + min_ord_alow_amt / min_ord_alowq (미수불가 = 가장 보수적) 파싱 시 형식이 두 가지로 섞여 있다 율 3개 : "%가 포함된 백분율 값" → float("40%") 는 ValueError 금액·수량: "0-padding 부호 포함 12자리" → int() 로. lstrip("0") 금지 kt00013 은 같은 성격인데 15자리 — 폭을 가정한 코드는 거기서 깨진다
kt00011 응답의 세 가지 율과 구간별 칸, 그리고 섞여 있는 두 가지 문자열 형식

3. 함정 ② 율에 % 기호가 붙어 있다

공식 명세는 이 세 필드의 description"%가 포함된 백분율 값"이라고 적어 두었습니다. 즉 "40"이 아니라 "40%" 형태로 옵니다.

>>> float(resp["aplc_rt"])
ValueError: could not convert string to float: '40%'

그런데 같은 응답 안의 금액·수량 필드는 형식이 또 다릅니다. profa_40ord_alowq 같은 항목의 설명은 "단위: 1주, 좌측 0-padding 처리된 부호 포함 12자리 숫자"입니다. 한 응답 안에 두 가지 문자열 규격이 섞여 있다는 뜻이라, 파서를 필드 종류별로 갈라야 합니다.

def pct(v: str) -> float:
    """'40%' → 40.0 · 빈 값 → 0.0"""
    return float((v or "0").replace("%", "").strip() or 0)

def won(v: str) -> int:
    """'000000012345' → 12345 · 부호 포함 · lstrip('0') 쓰지 말 것"""
    return int((v or "0").strip() or 0)     # '0000' 을 lstrip 하면 '' 가 되어 깨진다

rate = pct(resp["aplc_rt"])                 # 적용증거금율
cash = won(resp["ord_alowa"])               # 주문가능현금
debt = won(resp["uncla"])                   # 미수금 — 0 이 아니면 이미 사고다

4. 함정 ③ kt00012는 칸 수가 다르다

신용으로 사는 봇이라면 kt00012(신용보증금율별주문가능수량)를 같이 씁니다. 요청 바디가 stk_cd·uv똑같이 생겨서 함수를 복사하고 싶어지는데, 응답이 다릅니다.

구분kt00011 증거금율kt00012 신용보증금율
구간20·30·40·50·60·100 (6칸)30·40·50·60 (4칸) — 20·100 없음
접두어profa_assr_
율 필드stk_profa_rt·profa_rt·aplc_rtstk_assr_rt·stk_assr_rt_nm(이름 문자열)
미수불가min_ord_alow_amt·min_ord_alowqmin_amt·min_qty같은 뜻, 다른 이름
미수가능없음out_alowa·out_pos_qty

공통 상수 RATES = (20, 30, 40, 50, 60, 100)을 두 TR에 같이 쓰면 사고가 납니다. kt00012에는 assr_20ord_alowqassr_100ord_alowq도 없습니다. dict.get()으로 읽으면 조용히 None이 되고, 그걸 int()에 넘기면 그제서야 터집니다. 구간 목록을 TR별로 따로 정의하십시오.

# TR 마다 구간과 접두어가 다르다 — 상수를 공유하지 말 것
TIERS = {
    "kt00011": (("profa_", (20, 30, 40, 50, 60, 100)), ("min_ord_alow_amt", "min_ord_alowq")),
    "kt00012": (("assr_",  (30, 40, 50, 60)),          ("min_amt",          "min_qty")),
}

def orderable_by_tier(api_id: str, resp: dict) -> dict[int, int]:
    (prefix, tiers), _ = TIERS[api_id]
    out = {}
    for r in tiers:
        key = f"{prefix}{r}ord_alowq"       # profa_40ord_alowq / assr_40ord_alowq
        if key in resp:
            out[r] = won(resp[key])
    return out

5. kt00013 증거금세부내역 — 요청 바디가 없다

종목이 아니라 계좌 전체의 증거금 구성을 볼 때 씁니다. kt00013은 명세상 request.body가 비어 있습니다 — 종목코드를 넣지 않습니다. 응답은 50개 항목이고, 봇이 실제로 보게 되는 것은 대개 이쪽입니다.

두 가지가 kt00011과 다릅니다. 첫째, 금액 필드가 15자리입니다(kt00011·kt00012는 12자리). 고정폭을 가정한 파서는 여기서 깨집니다. 둘째, 20ord_alow_amt·30ord_alow_amt처럼 필드명이 숫자로 시작합니다 — 파이썬 식별자로 못 쓰므로 딕셔너리 키로만 읽어야 합니다. 같은 성격의 문제를 kt00001·kt00010 편에서 코드까지 정리해 뒀습니다.

6. 실전 코드 — 안전 수량 결정기

규칙은 둘입니다. "율을 못 읽으면 가장 보수적인 칸을 쓴다", "API가 준 수량을 그대로 주문하지 않는다".

def safe_buy_qty(base_url, token, stk_cd, price, safety=0.95) -> int:
    resp = margin_rate(base_url, token, stk_cd, price)

    if won(resp.get("uncla")) > 0:          # 미수금이 있으면 신규 매수를 막는다
        return 0

    rate = pct(resp.get("aplc_rt"))         # 종목이 아니라 '적용' 율
    tiers = orderable_by_tier("kt00011", resp)

    # 적용율 이상인 칸 중 가장 낮은 칸 = 그 종목에 해당하는 한도
    candidates = [r for r in sorted(tiers) if r >= rate]
    tier = candidates[0] if candidates else 100      # 못 읽으면 100% 칸
    qty = tiers.get(tier, 0)

    # 미수를 절대 내지 않으려면 이쪽이 정답
    no_debt = won(resp.get("min_ord_alowq"))
    if no_debt:
        qty = min(qty, no_debt)

    return int(qty * safety)

safety=0.95조회와 주문 사이에 가격이 움직이는 것을 흡수하려는 여유이지 수익을 올리는 값이 아닙니다. API가 허락하는 최대 수량과 전략이 허락하는 수량은 다른 문제이고, 한 번에 얼마를 태울지는 포지션 사이징에서 정합니다. 주문을 실제로 내보내는 쪽은 kt10000 주식 주문, 보유 수량 상한은 kt00018 잔고를 보십시오.

증거금율은 고정값이 아닙니다. 종목별 율은 증권사가 정하고 바뀝니다. 하드코딩하거나 어제 값을 재사용하면 주문 거부나 미수로 이어집니다. 매매 시작 전에 kt00011로 다시 읽으십시오. 보수적으로 잡아 못 사는 것은 복구되지만 넉넉하게 잡아 미수가 나는 것은 복구가 어렵습니다. 구체적인 증거금 정책과 미수 처리는 증권사 약관·공지의 현재 내용을 확인하십시오.

7. 자주 묻는 질문

키움 REST API로 종목의 증거금율을 알 수 있나요?

kt00011이 답합니다. POST /api/dostk/acnt + api-id: kt00011 + stk_cd. 응답 맨 앞에 stk_profa_rt·profa_rt·aplc_rt가 오고 실제 적용값은 aplc_rt입니다.

증거금율을 float()로 바꾸면 왜 에러가 나나요?

명세가 세 율 필드를 "%가 포함된 백분율 값"이라고 적어 뒀기 때문입니다. "40%"가 그대로 옵니다. 금액·수량은 반대로 0-padding 12자리 문자열이라 int()로 처리하고 lstrip("0")은 쓰지 마십시오.

kt00011과 kt00012는 뭐가 다른가요?

구간이 6칸 대 4칸이고 접두어가 profa_assr_입니다. kt00012에는 20%·100% 칸이 없고 미수불가 필드 이름도 min_amt·min_qty로 다릅니다. 같은 파서를 쓰면 깨집니다.

kt00013 증거금세부내역은 언제 쓰나요?

계좌 단위 구성을 볼 때입니다. 요청 바디가 없고 응답이 50개 필드이며 금액이 15자리kt00011의 12자리와 다릅니다.

모의투자에서도 되나요?

공식 명세는 세 TR 모두에 운영 api.kiwoom.com과 모의 mockapi.kiwoom.com을 함께 적어 두고 있습니다. 도메인과 접근토큰이 다르므로 운영 토큰으로 모의 도메인을 부르면 인증에서 막힙니다 (토큰 유효기간과 폐기).

주문이 거부되지 않는 봇이 필요하다면

증거금·잔고·미체결을 모두 반영한 수량 계산부터 실주문까지 맞춰 만들어 드립니다. 24시간 빠른 답변 가능합니다.

무료 상담 시작하기