AlgoLab Blog · 키움증권 REST · 수급 데이터 · 2026

키움 ka10045 종목별기관매매추이 — 누적은 시작일 기준

키움 REST · 시세 2026-10-31 · 약 7분 읽기 · 알고랩 AlgoLab
한 줄 요약

ka10045(종목별기관매매추이요청)는 stk_cd 종목 하나를 넣으면 strt_dt~end_dt 동안 날짜별 기관 순매매(orgn_daly_nettrde_qty)·외국인 순매매(for_daly_nettrde_qty)를 1주 단위로 주는 시계열 TR입니다. 함정은 셋입니다. ① orgn_dt_acc·for_dt_acc(기간누적)는 명세에 단위·기준이 비어 있는데, 예시를 검산하면 요청한 시작일부터 더한 값이라 strt_dt를 바꾸면 같은 날 누적도 바뀝니다. ② 맨 위 orgn_prsm_avg_pric(기관추정평균가)는 날짜별이 아니라 기간 전체 한 값이고, orgn_prsm_unp_tp 1·2(매수·매도단가)는 이 한 필드만 바꿉니다. ③ close_pric는 하락일에 "-132500"처럼 부호가 붙습니다. 거래소는 stex_tp가 아니라 stk_cd 접미사(_NX·_AL)로 고릅니다. (키움 공식 명세 kiwoom_api_spec.json·공식 GitHub 예제 기준, 2026-10-31 확인)

목차

  1. ka10045는 무엇을 주나 — 비슷한 TR 4개와 나누기
  2. 요청·응답 실물
  3. 함정 6가지
  4. 받아서 저장하는 코드
  5. 자주 묻는 질문

1. ka10045는 무엇을 주나 — 비슷한 TR 4개와 나누기

메뉴 위치는 국내주식 > 시세, URL은 POST /api/dostk/mrkcond로 어제 정리한 ka10044 일별기관매매종목과 같은 주소입니다. 같은 URL에 여러 TR이 붙어 있어 헤더 api-id: ka10045로만 구분됩니다. ka10044가 "기간 동안 기관이 많이 산 종목 순위"라면 ka10045는 "이 종목을 기관·외국인이 날마다 얼마나 샀나"입니다. 기관·외국인 수급을 주는 키움 TR이 많아 먼저 용도를 나눠 둡니다.

TR입력결과 모양투자자수량 단위
ka10045 종목별기관매매추이stk_cd + 기간종목 1개 · 날짜별기관(합계)·외국인 2열1주
ka10044 일별기관매매종목시장 + 기간기간 합계 · 종목 순위기관100주
ka10059 종목별투자자기관별stk_cd + dt 하루종목 1개 · 날짜별개인·투신·연기금 등 세분unit_tp로 선택
ka10060 종목별투자자기관별차트stk_cd + dt 하루종목 1개 · 날짜별세분unit_tp로 선택
ka10131 기관외국인연속매매현황시장 + 기간(dt 1·3·5·…)종목 순위기관·외국인—

ka10045만의 장점은 기간(strt_dt~end_dt)을 한 번에 넣는다는 점과, 응답에 외국인 한도소진율(limit_exh_rt)과 기관·외국인 추정평균가가 함께 온다는 점입니다. 개인·연기금·투신처럼 기관을 쪼개 봐야 하면 ka10059로, "기관 5일 연속 순매수 종목"처럼 조건 검색이 목적이면 ka10131로 가는 편이 빠릅니다.

같은 날짜, strt_dt만 다르게 — orgn_dt_acc가 달라진다 dt D1 D2 D3 orgn_daly_nettrde_qty +5,000 -2,000 +4,000 orgn_dt_acc (strt_dt=D1) 5,000 3,000 7,000 orgn_dt_acc (strt_dt=D2) — -2,000 2,000 설명용 숫자 · 누적 기준은 공식 예시 검산으로 추정(명세 설명 공란)
ka10045 기간누적은 저장값이 아니라 요청마다 다시 계산되는 값

2. 요청·응답 실물

헤더는 다른 키움 REST TR과 같습니다 — api-id, authorization: Bearer ..., 다음 페이지가 있으면 응답 헤더의 cont-yn·next-key를 다시 보냅니다(연속조회 정리). body 다섯 개는 모두 필수입니다. 명세의 요청 예시 그대로입니다.

POST https://api.kiwoom.com/api/dostk/mrkcond
api-id: ka10045
Content-Type: application/json;charset=UTF-8

{
    "stk_cd": "005930",
    "strt_dt": "20241007",
    "end_dt": "20241107",
    "orgn_prsm_unp_tp": "1",
    "for_prsm_unp_tp": "1"
}
필드한글명값 (명세 원문)
stk_cd종목코드KRX 039490 · NXT 039490_NX · SOR 039490_AL
strt_dt · end_dt시작일자 · 종료일자YYYYMMDD (최대 기간은 명세에 없음)
orgn_prsm_unp_tp기관추정단가구분1 매수단가 · 2 매도단가
for_prsm_unp_tp외인추정단가구분1 매수단가 · 2 매도단가

명세의 응답 예시입니다. 요약 두 필드가 맨 위에, 날짜별 리스트가 stk_orgn_trde_trnsn 키에 옵니다.

{
    "orgn_prsm_avg_pric": "117052",
    "for_prsm_avg_pric": "0",
    "stk_orgn_trde_trnsn": [
        {"dt": "20241107", "close_pric": "133600", "pre_sig": "0", "pred_pre": "0",
         "flu_rt": "0.00", "trde_qty": "0", "orgn_dt_acc": "158",
         "orgn_daly_nettrde_qty": "0", "for_dt_acc": "28315",
         "for_daly_nettrde_qty": "0", "limit_exh_rt": "+26.14"},
        {"dt": "20241106", "close_pric": "-132500", "pre_sig": "5", "pred_pre": "-600",
         "flu_rt": "-0.45", "trde_qty": "43", "orgn_dt_acc": "158",
         "orgn_daly_nettrde_qty": "0", "for_dt_acc": "28315",
         "for_daly_nettrde_qty": "11243", "limit_exh_rt": "+26.14"}
    ],
    "return_code": 0,
    "return_msg": "정상적으로 처리되었습니다"
}

삼성전자 거래량이 43주인 것으로 보아 테스트값입니다. 숫자 자체보다 형식(부호·정렬·필드 구성)을 읽는 용도로 봐야 합니다.

3. 함정 6가지

① 기간누적(*_dt_acc)은 시작일 기준이다

명세의 orgn_dt_acc·for_dt_acc는 한글명("기관기간누적"·"외인기간누적")만 있고 단위 칸이 비어 있습니다. 바로 아래 orgn_daly_nettrde_qty가 "단위: 1주"인 것과 대조적입니다. 예시를 검산하면 11월 6일 외국인 일별 +11,243주, 누적 28,315주이고 11월 7일은 일별 0주, 누적 28,315주로 그대로입니다. 즉 누적은 요청한 strt_dt부터 그 날까지 일별값을 더한 것과 맞습니다. 이 해석이 맞다면 strt_dt를 바꿔 다시 받으면 같은 날짜의 누적이 전부 바뀝니다. 매일 증분으로 받아 DB에 쌓는 봇이 누적값을 그대로 저장하면 날마다 기준이 다른 숫자가 한 열에 섞입니다. 일별값만 저장하고 누적은 직접 cumsum()하세요. (명세가 기준을 밝히지 않으니 실계좌 응답 두 번으로 확인해 보길 권합니다.)

② 추정평균가는 기간 전체 한 값이고, 단가구분은 그 한 값만 바꾼다

orgn_prsm_avg_pric·for_prsm_avg_pric는 리스트 바깥, 응답 최상위에 한 번씩만 옵니다. 날짜별 평균가가 아니라 요청 기간 전체에 대한 추정치입니다. 그래서 필수 입력인 orgn_prsm_unp_tp·for_prsm_unp_tp(1 매수단가·2 매도단가)는 요약 두 필드에만 영향을 주고, 날짜별 리스트는 똑같이 옵니다. 매수·매도 평균가를 둘 다 보려면 두 번 호출해야 하고, 둘째 호출은 리스트를 버려도 됩니다. 예시처럼 외국인 평균가가 "0"이면 해당 기간 추정치가 없다는 뜻으로 보고 0원으로 계산하지 마세요.

③ close_pric의 마이너스는 가격이 아니라 방향이다

명세 설명은 "단위: 원, 부호가 포함된 숫자"입니다. 예시 11월 6일 close_pric는 "-132500", 대비기호 pre_sig "5"(하락), 전일대비 "-600"입니다. float("-132500")을 그대로 종가로 쓰면 수익률·평균단가 계산이 전부 뒤집힙니다. 가격은 abs(), 방향은 pred_pre 부호로 판단합니다. 키움 REST 시세 TR 대부분이 같은 규칙이라 공통 파서에 넣어 두면 편합니다.

④ pre_sig에 명세에 없는 "0"이 온다

명세의 pre_sig 값은 "1: 상한가, 2:상승, 3:보합, 4:하한가, 5:하락" 다섯 개인데, 예시 11월 7일 행은 "0"입니다. 거래량도 "0"이라 거래가 없던 행으로 보입니다. {"1":"상한가",...}[pre_sig]처럼 딕셔너리로 바로 찾으면 KeyError가 나니 .get(pre_sig, "없음")으로 받으세요. 거래량 0인 날을 그대로 지표 계산에 넣을지도 정해 둬야 합니다.

⑤ 거래소 구분은 stex_tp가 아니라 종목코드 접미사

같은 URL의 ka10044는 stex_tp(1 KRX·2 NXT·3 통합)를 받지만, ka10045 요청 필드에는 stex_tp가 없습니다. 명세는 stk_cd 설명에 "KRX:039490, NXT:039490_NX, SOR:039490_AL"을 적어 두었습니다. ka10044 코드를 복사해 stex_tp만 바꾸는 식으로는 NXT를 고를 수 없으니, 종목코드 자체를 바꿔 보내야 합니다. NXT·SOR이 왜 갈리는지는 NXT·KRX 주문 라우팅에 정리했습니다.

⑥ 최신일이 맨 위 — 공식 예제는 10페이지에서 끊는다

예시 리스트는 20241107 → 20241106 순서, 즉 내림차순입니다. 누적 계산 전에 sort_values("dt")로 뒤집어야 ①의 cumsum()이 맞습니다. 또 공식 예제 get_domestic_stock_institution_trade_trend.py는 MAX_PAGES = 10, REQUEST_DELAY_SECONDS = 0.2로 연속조회를 10페이지에서 멈춥니다. 한 페이지 행 수는 명세에 없으니, 긴 기간을 받을 때는 마지막 행 dt가 strt_dt까지 내려왔는지 확인하세요. 오류는 HTTP 200에 본문 return_code로 오고, 호출 한도 초과는 1700("허용된 API 요청 개수를 초과하였습니다")입니다(키움 return_code 정리).

4. 받아서 저장하는 코드

requests와 pandas만 씁니다. 토큰 발급은 생략했습니다.

import time, requests, pandas as pd

URL = "https://api.kiwoom.com/api/dostk/mrkcond"

def num(s):
    s = (s or "").strip()
    return float(s) if s not in ("", "-", "+") else None

def ka10045(token, stk_cd, strt_dt, end_dt, unp_tp="1"):
    body = {"stk_cd": stk_cd, "strt_dt": strt_dt, "end_dt": end_dt,
            "orgn_prsm_unp_tp": unp_tp, "for_prsm_unp_tp": unp_tp}
    head = {"api-id": "ka10045", "authorization": f"Bearer {token}",
            "Content-Type": "application/json;charset=UTF-8"}
    rows, summary = [], None
    while True:
        r = requests.post(URL, json=body, headers=head, timeout=10)
        j = r.json()
        if j.get("return_code") != 0:
            raise RuntimeError(f"{j.get('return_code')} {j.get('return_msg')}")
        if summary is None:   # 기간 전체 한 값
            summary = {"orgn_avg": num(j.get("orgn_prsm_avg_pric")),
                       "for_avg": num(j.get("for_prsm_avg_pric"))}
        rows += j.get("stk_orgn_trde_trnsn", [])
        if r.headers.get("cont-yn") != "Y":
            break
        head["cont-yn"], head["next-key"] = "Y", r.headers.get("next-key")
        time.sleep(0.2)

    df = pd.DataFrame(rows)
    df["close"] = df["close_pric"].map(num).abs()          # ③ 부호 제거
    for c in ["orgn_daly_nettrde_qty", "for_daly_nettrde_qty", "trde_qty"]:
        df[c] = df[c].map(num)
    df["limit_exh_rt"] = df["limit_exh_rt"].map(num)
    df = df.sort_values("dt").reset_index(drop=True)        # ⑥ 오름차순
    # ① 누적은 저장하지 않고 직접 계산
    df["orgn_cum"] = df["orgn_daly_nettrde_qty"].cumsum()
    df["for_cum"] = df["for_daly_nettrde_qty"].cumsum()
    keep = ["dt", "close", "trde_qty", "orgn_daly_nettrde_qty",
            "for_daly_nettrde_qty", "orgn_cum", "for_cum", "limit_exh_rt"]
    return df[keep], summary

DB에는 (stk_cd, dt)를 키로 일별값만 넣고, 같은 날짜가 다시 오면 덮어쓰게(upsert) 만들면 기간을 겹쳐 받아도 안전합니다. 키움 REST 전체 구조(토큰·도메인·TR 분류)는 키움 REST API 자동매매 가이드에서 먼저 보시면 이 TR이 어디에 놓이는지 잡힙니다.

5. 자주 묻는 질문

ka10045의 orgn_dt_acc(기관기간누적)는 무엇을 누적한 값인가요?

명세에는 한글명 '기관기간누적'만 있고 단위·기준 설명이 비어 있습니다. 공식 응답 예시를 검산하면 요청한 strt_dt부터 그 날짜까지의 일별 순매매수량(orgn_daly_nettrde_qty)을 더한 값과 맞습니다. 따라서 strt_dt를 바꿔 다시 조회하면 같은 날짜의 누적값도 달라지므로, 저장은 일별 순매매수량으로 하고 누적은 직접 계산하는 편이 안전합니다.

orgn_prsm_unp_tp를 1과 2로 바꾸면 무엇이 달라지나요?

응답 맨 위 요약 필드 orgn_prsm_avg_pric(기관추정평균가)이 매수단가 기준인지 매도단가 기준인지만 바뀝니다. 날짜별 리스트 stk_orgn_trde_trnsn에는 추정단가 필드가 없어서 영향이 없습니다. 외국인 쪽 for_prsm_unp_tp도 for_prsm_avg_pric 하나에만 적용됩니다. 매수·매도 평균가를 둘 다 원하면 두 번 호출해야 합니다.

ka10045 응답의 종가가 음수로 오는데 오류인가요?

오류가 아닙니다. close_pric 설명이 '부호가 포함된 숫자'이고, 부호는 전일 대비 방향을 뜻합니다. 공식 예시에서도 하락한 날 close_pric가 -132500으로 옵니다. 가격으로 쓸 때는 abs()로 부호를 떼고, 방향은 pred_pre나 pre_sig로 판단하세요.

ka10045에서 NXT나 통합 시세는 어떻게 고르나요?

ka10044처럼 stex_tp 필드가 없고, stk_cd 값으로 구분합니다. 명세 원문은 KRX 039490, NXT 039490_NX, SOR 039490_AL 형식입니다. 아무 접미사 없이 6자리만 넣으면 KRX 기준입니다.

기관·외국인 수급을 쌓는 봇, 만들어 드립니다

ka10045·ka10044·ka10059로 종목별 기관·외국인 순매매를 매일 받아 단위와 누적 기준을 맞춰 저장하고, 매매 필터로 쓰는 키움 REST 봇을 맞춤 제작합니다. 24시간 빠른 답변 가능합니다.

무료 상담 시작하기