콘텐츠로 이동

키움 REST API 클라이언트 재구현 인수인계서

작성: 2026-05-15 (Cowork 세션) 수행 주체: PM 머신의 Claude Code (키움 API 네트워크 도달 가능 환경) 사유: Cowork 샌드박스는 mockapi.kiwoom.com/api.kiwoom.com이 허용목록 차단(HTTP 403 blocked-by-allowlist)이라 토큰 발급·API 호출 검증 불가. 작성은 가능하나 검증 루프를 돌릴 수 없어 머신 측으로 이관.


1. 배경

  • 원본 scripts/kiwoom_rest_api.py 풀 클라이언트(~30 메서드 + 토큰 발급)와 claude_trader 패키지, api_keys.txt가 이전 세션에서 소실됨.
  • 2026-05-13 11:12, 원본이 pykrx 기반 33줄 stub으로 덮어쓰여짐 (현재 상태). stub은 get_daily_chart/get_minute_chart만 구현.
  • 백업 압축본 6개 전수 확인 — 원본 클라이언트 없음. 재구현 외 경로 없음.
  • api_keys.txt는 PM이 프로젝트 루트에 복원 완료.

2. 목표 / 성공조건

키움 REST API를 실제로 호출하는 KiwoomRestAPI 클라이언트를 재구현하여 의존 스크립트 9개를 복구한다.

검증 항목 성공 기준
토큰 발급 mock 서버에서 OAuth2 토큰 정상 발급
fetch_market_top.py 실행 등락률 상위/거래량 상위 정상 수집, JSON 저장
의존 스크립트 8개 import 및 핵심 메서드 호출 스모크 테스트 통과

3. 자격증명

api_keys.txt (프로젝트 루트), 형식 — 키 이름과 값 사이 : (공백 포함) 구분:

secret : <secretkey>
api : <appkey>
파서 작성 시 : 구분자와 앞뒤 공백 strip 처리 주의.

4. 엔드포인트 / 설정

근거: knowledge_base/system/TOOL_REFERENCE.md §1, docs/work_logs/2026-01-16_rest_api_setup.md, _archive/config_inactive_20260512.zip > production_config.yaml.

항목
mock base URL https://mockapi.kiwoom.com
real base URL https://api.kiwoom.com
토큰 엔드포인트 /oauth2/token
차트 /api/dostk/chart
시세/정보 /api/dostk/stkinfo
호가/시장 /api/dostk/mrkcond
주문 /api/dostk/ordr
rate limit 데이터 요청 간 1.0s, max 5 req/s

토큰 gotcha (TOOL_REFERENCE.md §1): - 응답 토큰 키 = token (NOT access_token) - 만료 키 = expires_dt (YYYYMMDDHHmmss 형식, NOT expires_in)

5. 구현 범위 — 메서드 표면

의존 스크립트 9개를 grep하여 확정한 실제 호출 메서드만. 원본의 ~30개 전부가 아니라 아래만 구현하면 9개 스크립트가 복구됨. (주문/계좌 메서드는 이번 범위 아님 — 호출하는 스크립트 없음.)

Foundation

  • __init__(is_mock=...)KiwoomRestAPI(is_mock=True)와 bare KiwoomRestAPI() 둘 다 호출됨. is_mock 기본값 필요. 참고: docs/work_logs/2026-02-19_session148_live_mode_activation.md에 따르면 원본은 is_mockconfig.api.is_mock에서 읽었음 — 기본값 처리 방식 결정 필요.
  • _request(api_id, params, cont_yn='N', next_key='') — 내부 요청 헬퍼. 반환: (result_dict, next_key) 튜플. result_dict에는 return_code(int, 0=성공), return_msg, 그리고 API별 데이터 키가 포함됨 — 호출처는 result.get("return_code") != 0로 성공 여부 판정(근거: collect_ka90010_full.py:26). collect_ka90010_full.pyapi._request("ka90010", params, cont_yn, next_key)로 직접 호출하므로 public 시그니처로 노출 필요. ka90010 params 예시: {date, amt_qty_tp, mrkt_tp, min_tic_tp, stex_tp}, 데이터 키 prm_trde_trnsn.

시세/시장 메서드

메서드 API ID 호출 시그니처 (실제 사용) 반환 형태 호출처
get_top_change_rate ka10027 (market='000', sort_type='1'\|'3', stex_tp='2') dict, 키 pred_pre_flu_rt_upper (list). item: stk_cd,stk_nm,flu_rt,cur_prc fetch_market_top, fetch_limit_up, fetch_nxt_market
get_top_volume_today ka10030 (market='000', sort_tp='3', mang_stk_incls='14', stex_tp='2', cont_yn='Y', next_key=...) 튜플 (dict, next_key). dict 키 tdy_trde_qty_upper (list) fetch_market_top, fetch_nxt_market
get_current_price ka10001 (code) flat dict, 키 cur_prc. 장마감 후 exp_cntr_pric=0 주의. 모의투자 cur_prc=0 빈번 fetch_nxt_market
get_expected_price (미확정) (code) 예상체결가. ka10001의 exp_cntr_pric 필드 래핑인지 별도 호출인지 라이브 확인 필요 fetch_nxt_market
get_inst_trading_trend ka10045 (확정) (code, start_date=, end_date=) dict, 키 stk_orgn_trde_trnsn (list). item: dt,for_daly_nettrde_qty,orgn_daly_nettrde_qty,close_pric,for_dt_acc,orgn_dt_acc. 근거: collect_stock_flow_series.py:40,45 + candidate_from_theme.py:307-308 candidate_from_theme, collect_stock_flow_series
get_program_trading_daily_all ka90013 (확정) (code, base_date=None, max_pages=N, delay=N) — base_date 생략 호출 있음 dict (bare list 아님), 키 stk_daly_prm_trde_trnsn (list). 페이지네이션 집계 래퍼. item: dt/date,prm_buy_qty,prm_sell_qty,prm_netprps_qty. 근거: collect_program_trading.py:49,51 + collect_stock_flow_series.py:64,66 collect_program_trading, collect_stock_flow_series
get_daily_chart ka10081 (code) dict, 키 stk_dt_pole_chart_qry (list). item: dt,cur_prc,open_pric,high_pric,low_pric,trde_qty. 부호 +/- prefix check_wait_conditions, mtf_chart_profiler, fetch_market_top(간접)
get_minute_chart ka10080 (확정) (code, minute_type='5') dict, 키 stk_min_pole_chart_qry (list, daily와 키 다름). item: cntr_tm,open_pric,high_pric,low_pric. 근거: mtf_chart_profiler.py:248-249 mtf_chart_profiler

API ID 주의: config/data_sources.yaml 14-16줄은 top_change_rate/top_volume_today/top_volume_prev모두 ka10030으로 주석 달았으나, 이는 data_sources.yaml의 복붙 오류로 보임. TOOL_REFERENCE.md §1은 ka10027(등락률 상위)·ka10030(당일 거래량)으로 구분하고, 아카이브에 test_ka10027_fields.py·test_ka10030_fields.py가 별도 존재 → ka10027/ka10030은 별개 API. 위 표 기준(get_top_change_rate=ka10027) 채택. 라이브에서 최종 확인 권장.

참고: 현재 stub의 get_daily_chart/get_minute_chart는 pykrx 기반. config/data_sources.yaml fallback_rules는 daily_ohlcv의 fallback으로 FDR를 허용하므로, ka10081 재구현 + pykrx/FDR fallback 구조로 가도 됨. PM 아키텍처 방침: 정확도 우선 데이터는 키움, 과거 추세는 FDR.

6. 스펙 출처

  • knowledge_base/system/TOOL_REFERENCE.md §1 — API ID, 엔드포인트, 응답키, 토큰 gotcha, ka10063 부호 파싱(--282=-282) 등
  • config/data_sources.yaml 9-27줄 — kiwoom_rest_api 엔드포인트 매핑, fallback_rules, cross_validation_rules
  • docs/work_logs/2026-01-16_rest_api_setup.md — 초기 셋업 (토큰 발급/ka10081/ka10059 연동 성공 기록)

7. 미검증 영역 (라이브에서 확인하며 채울 부분)

TOOL_REFERENCE.md에 없는 것 — 학습데이터로 지어내지 말고 mock 서버 에러 메시지로 확인 (원 개발자도 "파라미터명은 에러 메시지로 확인"이라 기록함, 2026-01-16_rest_api_setup.md):

  1. 토큰 요청 본문의 정확한 필드명 (grant_type, appkey, secretkey/appsecret 등)
  2. API 호출 시 헤더 구성 — authorization: Bearer {token}, api-id: {ka#####}, cont-yn, next-key 등의 정확한 헤더명
  3. 각 ka#####의 정확한 요청 파라미터명 (시그니처의 market/sort_type 등이 REST 파라미터로 어떻게 매핑되는지)
  4. get_expected_price의 정확한 API ID와 반환 형태 (ka10001 exp_cntr_pric 필드 래핑인지 별도 호출인지). — get_inst_trading_trend·get_program_trading_daily_all·get_minute_chart는 §5에서 소스로 API ID·반환키 확정됨, 미검증 영역 아님.

8. 검증 루프

  1. api_keys.txt 파싱 → mock 서버 토큰 발급. 실패 시 토큰 요청 본문/헤더 조정.
  2. 메서드별 단건 호출 테스트 — get_top_change_rate부터. 에러 메시지로 파라미터명 확정.
  3. fetch_market_top.py 실행 → 등락률/거래량 상위 + JSON 저장 확인.
  4. 나머지 8개 스크립트 import + 핵심 메서드 스모크 테스트: candidate_from_theme.py, check_wait_conditions.py, collect_ka90010_full.py, collect_program_trading.py, collect_stock_flow_series.py, fetch_limit_up.py, fetch_nxt_market.py, mtf_chart_profiler.py
  5. 통과 후 docs/topics/_index.md에 복원 완료 기록.

9. 제약 (CLAUDE.md 준수)

  • scripts/kiwoom_rest_api.py 1개 파일만 교체. 의존 스크립트 9개는 건드리지 않음 — 메서드 시그니처를 위 §5에 맞추면 수정 불필요. 만약 시그니처 불일치가 불가피하면 PM 보고 후 진행.
  • 검증 없이 "동작함" 단정 금지. 각 메서드는 실제 호출 결과로만 검증.
  • 미확정 부분(§7)은 추측으로 채우지 말고 에러 기반으로 확인.