이 문서는 domain-rag-lab / lumina-invest / stock-coin-trade 세 저장소에 동일한 내용으로 복사되어 있다. 변경 시 세 저장소를 함께 갱신하고 버전을 올린다. 변경 이력은 문서 끝에 적는다. 연동 방식은 저장소별 독립 배포 + HTTP API다. 상대 저장소 코드 import·DB 직접 접근은 금지한다.
| 항목 | 규칙 |
|---|---|
| 인증 | 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)은 재시도 금지. 승인 토큰 발급·조회·잔고는 재시도 가능 |
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) |
{
"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} ]}
STRATEGY_API_KEY 가 설정된 pr 에서는 X-API-Key 가 일치하거나 pr 로그인 세션의 Authorization: Bearer <token> 이 유효하면 통과한다.
Bearer 는 pr LEAN 백테스트 화면의 「이 조건을 전략 스펙으로 저장」(브라우저에서 POST /strategies)을 위한 것이며, lumina 서버 간 호출은 계속 X-API-Key 를 쓴다.
- 전략설정 「운영 모드」 가 ② 백테스트 기반 규칙 일 때만 스펙 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 화면이 조건을 미리 채운다.
Base: https://<stock-coin-trade>/openapi/v1/kis (기존 /openapi/v1/orders는 가상 주문이므로 사용하지 않는다)
요청:
{"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-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>"
응답 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"}}응답: {"ok": true, "date": "20261002", "orders": [ ...2-3의 order... ]}
응답: {"ok": true, "order": {..., "status": "CANCEL_REQUESTED"}}
응답:
{"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 | 의미 |
|---|---|
| (없음) | 당일/기간 체결 목록(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 연결 실패 |
| 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 기록 |
응답: 전일대비 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).
- 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)
- 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 에서 폴링·컬럼으로 확정