KIS Open API 조회전용 연동 + 직접매매 절대금지 안전게이트

매수/매도 주문 및 계좌 잔고조회를 API로 직접 실행하지 않는다는 원칙을
코드 레벨에서 강제하는 안전게이트(governance/rules/06, 07)와 함께,
시세/호가/공매도거래비중 등 조회전용 KIS Open API 연동 및 SQLite
수집 파이프라인을 추가한다.

- kis_api_client_v1: 모든 요청이 _assert_read_only를 통과해야 하며
  /trading/ 경로·주문 TR_ID는 RuntimeError로 즉시 차단
- kis_data_collection_v1: KIS 우선 + Naver 폴백, 네트워크 실패는
  개별 ticker 단위로 흡수(배치 전체 중단 없음)
- data_collection_store_v1 / storage_backend_v1: SQLite 캐노니컬
  저장소, PostgreSQL 전환 대비 백엔드 추상화
- Gitea 영업일 스케줄(2시간 간격) + CI 강제 게이트
  (validate_no_direct_api_trading_v1, validate_kis_api_credentials_v1)
This commit is contained in:
2026-06-21 20:04:44 +09:00
parent 34f6eebba6
commit 4cb206a269
20 changed files with 2034 additions and 0 deletions
+7
View File
@@ -2,6 +2,13 @@ schema_version: agents_rule.v1
rule_id: CORE_LOCKS_V1
title: Core locks and no-hallucination rules
summary:
- "[NO_DIRECT_API_TRADING] 매수/매도 주문은 어떤 API(한국투자증권 KIS Open API 포함)를 통해서도
직접 실행하지 않는다. 이 엔진의 모든 산출물은 '제안'이며, 실제 주문 실행은 반드시 사람이
HTS에서 수동으로 입력한다. 이 원칙을 어기면 엔진 전체가 의미를 잃는다(사용자 직접 지시,
2026-06-21) — governance/rules/06_no_direct_api_trading.yaml 참조."
- "[NO_KIS_ACCOUNT_BALANCE_QUERY] KIS Open API로 계좌 보유종목/잔고를 조회하지 않는다.
보유종목의 유일한 출처는 HTS 캡처 → account_snapshot이다(사용자 직접 지시, 2026-06-21)
— governance/rules/07_no_kis_account_balance_query.yaml 참조."
- Use spec/13_formula_registry.yaml for all prices, stops, targets, quantities.
- Do not invent prices, quantities, or formulas.
- If harness data is missing, print DATA_MISSING — 하네스 업데이트 필요.
@@ -0,0 +1,55 @@
schema_version: agents_rule.v1
rule_id: NO_DIRECT_API_TRADING_V1
title: API를 통한 매수/매도 직접 실행 절대 금지 — 최상위 안전 규칙
priority: CRITICAL
origin: "사용자 직접 지시 (2026-06-21): '반드시 지침에 가장 중요한 하네스인 매수/매도는
API를 통해서 직접하지 않는다가 원칙이다. 이걸 지키지 않는다면 엔진으로서 의미는 없다.'"
has_code_implementation: true
code_path:
- "src/quant_engine/kis_api_client_v1.py"
- "tools/validate_no_direct_api_trading_v1.py"
summary:
- "이 엔진(은퇴자산포트폴리오 퀀트엔진)은 어떤 외부 API를 통해서도 매수/매도 주문을
직접 실행하지 않는다. 한국투자증권 KIS Open API를 포함해, 향후 연동되는 모든
브로커/거래소 API에 동일하게 적용된다."
- "이 엔진의 모든 산출물(final_decision_packet, sell_priority, rebalance orders 등)은
'제안(proposal)'이지 '주문 실행(execution)'이 아니다. 실제 매수/매도 주문은 반드시
사람이 HTS(홈트레이딩시스템)에서 직접 확인 후 수동으로 입력한다."
- "이 원칙은 데이터 수집(read-only) API 사용을 금지하지 않는다 — 시세/호가/공매도/
투자자별 매매동향 등 조회성 데이터 수집은 허용된다. 금지 대상은 주문 제출
(order placement), 정정(modify), 취소(cancel) API 호출뿐이다."
scope:
applies_to:
- "한국투자증권(KIS) Open API — https://apiportal.koreainvestment.com"
- "향후 추가되는 모든 브로커/거래소 Open API 연동"
prohibited_actions:
- "주문 제출(매수/매도 주문 전송) API 호출"
- "기존 주문 정정/취소 API 호출"
- "잔고를 변경시키는 모든 쓰기성(write) API 호출"
allowed_actions:
- "시세 조회(현재가, 호가, 일자별 시세)"
- "공매도 일별추이 조회"
- "투자자별 매매동향 조회"
- "계좌 잔고/평가 조회(읽기 전용)"
enforcement:
code_level:
rule: "KIS API 클라이언트 모듈(src/quant_engine/kis_api_client_v1.py)의 모든 HTTP 요청은
단일 공유 함수를 통해서만 전송되며, 그 함수는 차단 목록(FORBIDDEN_TR_ID_PREFIXES,
FORBIDDEN_PATH_SUBSTRINGS)에 해당하는 TR_ID/경로를 만나면 즉시 RuntimeError를
발생시켜 요청을 중단한다. 주문 제출/정정/취소 함수는 이 코드베이스에 일체 작성하지
않는다(함수 자체가 존재하지 않음 — 가드는 방어적 2차 안전장치)."
test: "tests/unit/test_kis_api_client_v1.py — 차단 목록에 있는 TR_ID/경로로 요청 시
RuntimeError가 발생하는지 검증 + 소스코드 전체에 주문 제출 엔드포인트 경로
문자열(/uapi/domestic-stock/v1/trading/order-cash 등)이 한 글자도 존재하지 않는지
정적 grep 검증."
review_level:
rule: "이 모듈에 새 함수를 추가할 때마다 반드시 KIS Open API 공식 문서에서 해당
TR_ID가 조회(quotations)/순위(ranking)/계좌조회(read-only) 카테고리인지 확인하고,
trading(주문) 카테고리 함수는 어떤 이유로도 추가하지 않는다."
violation_consequence: "이 규칙을 어기면 엔진 전체가 '제안 시스템'에서 '자동매매 시스템'으로
변질되어 프로젝트의 핵심 전제(사람이 최종 승인·입력)가 깨진다. 사용자가 명시적으로
'엔진으로서 의미는 없다'고 표현한 절대 우선 규칙이다."
@@ -0,0 +1,44 @@
schema_version: agents_rule.v1
rule_id: NO_KIS_ACCOUNT_BALANCE_QUERY_V1
title: KIS Open API로 계좌 보유종목/잔고 정보를 조회하지 않는다 — 필수 지침
priority: CRITICAL
origin: "사용자 직접 지시 (2026-06-21): 'OPEN API에 계좌 보유종목에 대한 정보는 사용하지
않는다. 필수 지침이다.'"
has_code_implementation: true
code_path:
- "src/quant_engine/kis_api_client_v1.py"
- "tools/validate_no_direct_api_trading_v1.py"
summary:
- "한국투자증권(KIS) Open API는 시세/호가/공매도/투자자매매동향 등 시장 전체에 공개된
조회성 데이터 수집에만 사용한다. 계좌 보유종목·잔고·평가금액 조회(주식잔고조회 등)
API는 호출하지 않는다."
- "보유종목 정보의 유일한 출처(source of truth)는 기존 HTS 캡처 → ChatGPT 파싱 → GAS
account_snapshot 시트 워크플로우다. 이 원칙은 [[feedback_direction_a_no_manual_input]]
(positions 수동입력 금지)와 같은 계열의 데이터 출처 통제 규칙이며, KIS API가 그
경로를 대체하거나 보강하지 않는다."
- "이 규칙은 governance/rules/06_no_direct_api_trading.yaml(주문 미실행)과 별개의
독립적인 제약이다 — 06번 규칙은 '쓰기(주문)'를 금지하고, 이 규칙은 '계좌 식별 데이터
조회(읽기)'를 금지한다. 두 규칙 모두 충돌 없이 동시에 적용된다."
scope:
prohibited_tr_ids:
- "TTTC8434R" # 주식잔고조회(실전)
- "VTTC8434R" # 주식잔고조회(모의)
prohibited_path_substrings:
- "/trading/inquire-balance"
rationale: >
이미 governance/rules/06의 FORBIDDEN_PATH_SUBSTRINGS=("/trading/",)가 이 경로를
구조적으로 차단하지만(주식잔고조회도 /trading/ 하위 경로), 이 규칙은 그것이
'주문 차단의 부수효과'가 아니라 '계좌정보 비조회'라는 독립적이고 의도적인 정책임을
명시한다.
enforcement:
code_level: "src/quant_engine/kis_api_client_v1.py에 inquire-balance 관련 함수를 작성하지
않는다(함수 자체가 존재하지 않음). TTTC8434R/VTTC8434R을 FORBIDDEN_TR_ID_PREFIXES에
추가해 2차 방어."
test_level: "tests/unit/test_kis_api_client_v1.py — TTTC8434R/VTTC8434R 차단 검증 +
tools/validate_no_direct_api_trading_v1.py 정적 스캔에 동일 TR_ID/경로 포함."
violation_consequence: "계좌 보유정보를 KIS API로 조회하면 HTS 캡처 기반 단일 진실원천
원칙이 깨지고, 두 개의 서로 다른 보유종목 데이터 경로가 생겨 정합성 검증이 불가능해진다."