Skip to content

Latest commit

 

History

History
180 lines (156 loc) · 12.7 KB

kis-autotrade-api.md

File metadata and controls

180 lines (156 loc) · 12.7 KB

KIS 자동매매 연동 API 계약 (v0.7, 2026-10-15)

이 문서는 domain-rag-lab / lumina-invest / stock-coin-trade 세 저장소에 동일한 내용으로 복사되어 있다. 변경 시 세 저장소를 함께 갱신하고 버전을 올린다. 변경 이력은 문서 끝에 적는다. 연동 방식은 저장소별 독립 배포 + HTTP API다. 상대 저장소 코드 import·DB 직접 접근은 금지한다.

0. 공통 규약

항목 규칙
인증 Authorization: Bearer <api_key> (stock-coin-trade Open API), X-API-Key: <key> (domain-rag-lab 전략 API)
환경 environment: "paper"(KIS 모의 Testbed) 또는 "real"(KIS 실전). 생략 시 paper. real은 서버 플래그 KIS_REAL_ORDER_ENABLED=true가 없으면 항상 거부
종목코드 KRX 6자리 숫자 문자열 ("005930"). lumina 내부 005930.KS 표기는 게이트웨이 호출 전 접미사를 제거한다
방향 side: "BUY" / "SELL" (대문자). lumina 내부 buy/sell은 게이트웨이가 변환
주문유형 orderType: "MARKET" / "LIMIT". LIMIT은 price(원, 정수, 호가 단위 일치) 필수
멱등키 clientOrderId: 호출자가 만드는 1~64자 문자열. 같은 키로 재요청하면 새 주문을 내지 않고 저장된 결과를 돌려준다
시간 ISO 8601, KST(+09:00) 명시
오류 응답 {"ok": false, "error": "<CODE>", "message": "<사람이 읽는 메시지>"} + HTTP 상태
재시도 주문(POST /orders)은 재시도 금지. 승인 토큰 발급·조회·잔고는 재시도 가능

1. 전략 스펙 API — domain-rag-lab → lumina-invest

Base: https://<domain-rag-lab>/backtests

메서드 경로 설명
GET /strategies 백테스트 합격 전략 목록
GET /strategies/{strategy_id} 최신 합격 버전 스펙
GET /strategies/{strategy_id}/versions/{version} 특정 버전 스펙
GET /strategies/{strategy_id}/versions (v0.6) 모든 버전(불합격 포함)과 판정 사유. {strategy_id, latest_passed_version, versions:[{version, name, passed, failed[], universe_size, entry, backtest_result, created_at}]}. 파일이 없으면 404. lumina 전략설정 「버전 이력」·수익율검증이 사용
POST /strategies/{strategy_id}/revalidate 최신 합격 스펙의 규칙·파라미터로 백테스트 재실행({ticker?, start_date?, end_date?, criteria?}) → 새 버전 저장. 201/422
POST /strategies 백테스트 실행 → 합격 판정 → 저장. 본문 {strategy_id, name?, universe[], backtest: BacktestRequest, criteria?, signal_weights?, position_sizing?}. 201=합격 스펙, 422=불합격(detail.failed)

StrategySpec (응답 본문)

{
  "strategy_id": "ma_cross_kr_large",
  "version": 3,
  "name": "이동평균 교차 (대형주)",
  "universe": ["005930", "000660"],
  "timeframe": "1d",
  "entry": {"indicator": "ma_cross", "params": {"short_window": 20, "long_window": 60}, "condition": "short_above_long"},
  "exit":  {"indicator": "ma_cross", "params": {"short_window": 20, "long_window": 60}, "condition": "short_below_long"},
  "signal_weights": {"technical": 0.7, "lightgbm": 0.3, "buy_threshold": 0.6, "sell_threshold": -0.6},
  "position_sizing": {"max_position_pct": 30.0, "max_symbols": 5},
  "backtest_result": {
    "period": {"start": "2021-01-01", "end": "2026-09-30"},
    "annualized_return_pct": 12.4, "max_drawdown_pct": -14.2, "sharpe_ratio": 0.91,
    "trade_count": 48, "win_rate_pct": 56.3, "engine": "lean"
  },
  "acceptance": {"passed": true, "criteria": {"max_drawdown_pct_lte": 20, "trade_count_gte": 30, "annualized_return_pct_gt": 0}},
  "created_at": "2026-10-02T12:00:00+09:00"
}

목록 응답: {"strategies": [ {strategy_id, version, name, backtest_result 요약, created_at} ]}

인증 (v0.6)

STRATEGY_API_KEY 가 설정된 pr 에서는 X-API-Key 가 일치하거나 pr 로그인 세션의 Authorization: Bearer <token> 이 유효하면 통과한다. Bearer 는 pr LEAN 백테스트 화면의 「이 조건을 전략 스펙으로 저장」(브라우저에서 POST /strategies)을 위한 것이며, lumina 서버 간 호출은 계속 X-API-Key 를 쓴다.

lumina 측 사용 (v0.6)

  • 전략설정 「운영 모드」 가 ② 백테스트 기반 규칙 일 때만 스펙 entry/exit 가 매매를 결정한다(①공격 모드는 종목 교집합·사유 표시, ③사용자 설정은 미사용). QUANT_SPEC_UNIVERSE_STRICT=true 면 universe 교집합이 비었을 때 매수하지 않는다.
  • 전략설정 카드가 GET /strategies/{id}·/versions 로 규칙·백테스트 결과·버전 이력을 보여 주고, 「최근 기간으로 재검증」 이 POST /strategies/{id}/revalidate 를 중계한다(/api/quant/strategy/revalidate).
  • 「pr 에서 이 전략 백테스트 열기」 링크: https://pr.edumgt.co.kr/?view=backtest&strategy=<indicator>&ticker=<6자리>&short=&long=&breakout=&interval=&start=&from_fd=<strategy_id> — pr 화면이 조건을 미리 채운다.

2. 주문 API — lumina-invest → stock-coin-trade

Base: https://<stock-coin-trade>/openapi/v1/kis (기존 /openapi/v1/orders는 가상 주문이므로 사용하지 않는다)

2-1. 승인 토큰 발급 POST /order-approval

요청:

{"environment": "paper", "symbol": "005930", "side": "BUY", "orderType": "LIMIT", "quantity": 3, "price": 71000, "clientOrderId": "u1:005930:BUY:20261002:1"}

응답 200:

{"ok": true, "approvalToken": "<opaque>", "expiresIn": 60, "intent": {"environment":"paper","symbol":"005930","side":"BUY","orderType":"LIMIT","quantity":3,"price":71000,"clientOrderId":"..."}}
  • 토큰은 발급 API Key + 주문 의도(intent) 해시에 묶인다. 의도의 어떤 필드든 바뀌면 주문 단계에서 거부된다.
  • 60초 후 만료, 1회 사용 후 소멸.

2-2. 주문 POST /orders

요청: 2-1과 동일한 본문 + "approvalToken": "<opaque>" 응답 200 (접수):

{"ok": true, "order": {
  "clientOrderId": "u1:005930:BUY:20261002:1", "orderNo": "0000123456", "orgNo": "91252",
  "environment": "paper", "symbol": "005930", "side": "BUY", "orderType": "LIMIT",
  "quantity": 3, "price": 71000, "estimatedAmount": 213000,
  "status": "ACCEPTED", "orderTime": "2026-10-02T10:31:05+09:00", "message": "..."
}, "duplicate": false}
  • 같은 clientOrderId 재요청 → 200 + 저장된 order + "duplicate": true (승인 토큰 검증은 생략하지 않는다)
  • 실패 시 ok:false. KIS가 rt_cd != "0"을 돌려주면 HTTP 502 + error: "KIS_<msg_cd>"

2-3. 체결 상태 GET /orders/{orderNo}?environment=paper

응답 200:

{"ok": true, "order": {"orderNo": "0000123456", "clientOrderId": "...", "environment": "paper", "symbol": "005930", "side": "BUY",
  "status": "FILLED", "orderedQuantity": 3, "filledQuantity": 3, "remainingQuantity": 0,
  "orderPrice": 71000, "avgFilledPrice": 70900, "updatedAt": "2026-10-02T10:31:40+09:00"}}

2-4. 당일 주문 목록 GET /orders?environment=paper&status=OPEN|ALL

응답: {"ok": true, "date": "20261002", "orders": [ ...2-3의 order... ]}

2-5. 취소 DELETE /orders/{orderNo}?environment=paper

응답: {"ok": true, "order": {..., "status": "CANCEL_REQUESTED"}}

2-6. 잔고 GET /balance?environment=paper

응답:

{"ok": true, "balance": {"environment": "paper", "cashBalance": 9500000, "totalEvalAmount": 10120000, "totalProfitLoss": 120000,
  "holdings": [{"symbol": "005930", "name": "삼성전자", "quantity": 3, "avgPrice": 70900, "currentPrice": 71500, "evalAmount": 214500, "profitLoss": 1800, "profitLossRate": 0.85}]}}

lookup 필드 (2-3 응답, 상태의 근거)

lookup 의미
(없음) 당일/기간 체결 목록(inquire-daily-ccld)에서 찾아 정규화
holdings_inference 체결 목록이 비어 있어 주문 전후 보유수량 변화로 추정 (inference 객체 동봉). KIS 모의투자는 체결 목록 output1 을 항상 비워 돌려준다
ambiguous_open_orders 같은 종목에 열린 주문이 둘 이상이라 추정 불가. 저장된 상태 그대로
not_in_daily_ccld 목록에도 없고 추정 근거도 없음. 저장된 상태 그대로(PENDING 이면 UNKNOWN)

주문 상태 정규화

status 의미 KIS 근거
ACCEPTED 접수됨, 미체결 주문 응답 rt_cd=0, 체결조회 rmn_qty = ord_qty
PARTIALLY_FILLED 일부 체결 0 < tot_ccld_qty < ord_qty
FILLED 전량 체결 rmn_qty = 0, tot_ccld_qty = ord_qty
CANCEL_REQUESTED 취소 요청 접수 취소 응답 rt_cd=0
CANCELLED 취소 완료 체결조회에서 취소 확인
REJECTED 거부 주문 응답 rt_cd≠0 또는 체결조회 거부 사유
UNKNOWN 조회 실패 조회 API 오류. 호출자는 재조회

오류 코드

HTTP error 상황
400 INVALID_REQUEST 필드 검증 실패 (종목코드, 수량, 호가 단위 등)
401 UNAUTHORIZED API Key 없음/폐기
403 APPROVAL_INVALID 승인 토큰 만료·불일치·재사용
403 SCOPE_FORBIDDEN 이 API Key에 KIS 주문 권한 없음 (api_key.scopes 에 kis:order/kis:* 없음. env 화이트리스트는 폐기)
403 REAL_ORDER_DISABLED environment=real인데 서버 플래그 꺼짐 또는 계좌 소유자 아님
409 INSUFFICIENT_BALANCE / INSUFFICIENT_HOLDINGS 예수금/보유수량 부족 (사전 검증)
409 ORDER_IN_PROGRESS 동일 환경 주문 락 점유 중
404 ORDER_NOT_FOUND 체결 조회/취소 대상 주문을 당일 내역에서 찾지 못함
422 LIMIT_EXCEEDED 회당 금액/수량 한도 초과
429 RATE_LIMITED API Key 분당 호출 제한
502 KIS_<msg_cd> KIS가 거부 (메시지는 KIS msg1). 응답에 order(REJECTED 기록) 포함
502 KIS_QUOTE_UNAVAILABLE MARKET 주문 금액 추정용 현재가 조회 실패
503 KIS_CONFIG_REQUIRED / KIS_CONNECTION_ERROR 자격증명 미설정 / KIS 연결 실패

lumina-invest 측 클라이언트 오류 코드 (게이트웨이 응답이 아닌 호출 실패)

code 상황 호출자 처리
GATEWAY_NOT_CONFIGURED STOCK_COIN_TRADE_BASE_URL/API_KEY 미설정 레거시 직접 호출로 폴백
GATEWAY_UNREACHABLE 연결/타임아웃 (주문 POST 는 재시도 없음) live_orders.status=UNKNOWN → confirm_fills 가 당일 목록에서 매칭
GATEWAY_INVALID_RESPONSE JSON 아님 ERROR 기록

2-7. 시세 GET /quote/{symbol}?environment=paper (v0.7, 읽기 전용)

응답: 전일대비 change 는 부호 포함(KIS prdy_vrss 절대값에 prdy_vrss_sign 4·5 면 음수). 현재가가 0 이면 KIS_QUOTE_UNAVAILABLE(502). symbol 은 6자리 코드(아니면 422 INVALID_REQUEST).

{"ok": true, "environment": "paper", "quote": {"symbol": "005930", "price": 71500, "change": -500, "changeRate": -0.69, "prevClose": 72000,
  "open": 72000, "high": 72300, "low": 71200, "volume": 1234567, "upperLimit": 93600, "lowerLimit": 50400}}

사용처: stock-kms-portal iv 챗봇 CheckQuote 인텐트(Lambda iv-lex-trade-hook).

3. 구현 현황 (2026-10-02)

  • stock-coin-trade: 2절 전부 구현 (app/api/routes/openapi_kis.py, app/services/brokers/kis_autotrade.py). 스코프는 api_key.scopes(kis:order) 단일(2026-10-02 env 화이트리스트 폐기). 당일/기간 조회는 KIS 연속조회 페이지네이션 적용
  • lumina-invest: 클라이언트 app/services/brokers/stock_coin_trade_gateway.py, 로더 app/services/strategy_loader.py
  • domain-rag-lab: 1절 전부 구현 (app/api/routes/strategies.py)

4. 변경 이력

  • v0.7 (2026-10-15) 시세 GET /quote/{symbol} 추가(iv 챗봇 CheckQuote 용, 읽기 전용)
  • v0.6 (2026-10-13) GET /strategies/{id}/versions(불합격 포함 이력), Bearer 세션 인증 허용(pr 화면 export), lumina 운영 모드 3분할(②에서만 스펙 적용)·유니버스 엄격 적용·재검증 중계·pr 백테스트 프리필 링크 명시
  • v0.5 (2026-10-02) 권한을 api_key.scopes 로 일원화(env 폐기), 미결 사항 확정(폴링·가상 /orders 유지)
  • v0.4 (2026-10-02) 체결 조회 lookup/inference 필드, 모의투자 체결 목록 제약 명시
  • v0.3 (2026-10-02) api_key.scopes 스코프 우선, revalidate, 연속조회 페이지네이션 반영, win_rate_pct 채움
  • v0.2 (2026-10-02) POST /strategies(export) 추가, 오류 코드 ORDER_NOT_FOUND/KIS_QUOTE_UNAVAILABLE, lumina 클라이언트 코드 표, 구현 현황 절
  • v0.1 (2026-10-02) 최초 작성. 미결: 체결 webhook 여부(현재 폴링), API Key 스코프 컬럼(현재 env 화이트리스트). → v0.5 에서 폴링·컬럼으로 확정