diff --git a/.agents/AGENTS.md b/.agents/AGENTS.md new file mode 100644 index 0000000..81ab14b --- /dev/null +++ b/.agents/AGENTS.md @@ -0,0 +1,264 @@ +# kis_bot 프로젝트 에이전트 규칙 (필수 준수 사항) + +## 📖 필수 참조 폴더 (`docs/like_mcp.md/`) 및 문서 + +이 프로젝트에서 작업할 때는 `docs/like_mcp.md/` 디렉토리 내의 핵심 문서들을 **항상** 인지하고 참조해야 합니다. + +### 필수 문서 목록 (경로: `docs/like_mcp.md/`) + +| 문서 | 정확한 파일 경로 | 용도 및 시점 | +|------|------|------| +| **코드 수정 가이드** | `docs/like_mcp.md/MODIFICATION_GUIDE.md` | **[수정 전 필수]** 수정 유형별 필수 `grep` 체크리스트 및 사이드 이펙트 검증 절차 | +| **코드 아키텍처 & 의존성 맵** | `docs/like_mcp.md/code_architecture.md` | **[구조 파악]** 파일 간 import 의존성, 핵심 허브 파일 Top 20, 전략별 모듈 분류 | +| **DB ERD & DDL** | `docs/like_mcp.md/db_erd.md` | **[DB 참고]** MariaDB 테이블 스키마, 컬럼 정의, PK/인덱스 및 관계 | + +--- + +## ⚖️ MCP 도구 vs MD 문서 활용 원칙 (토큰 최적화 & 정확도) + +프로젝트 분석 및 코드 작성 시, **MCP 도구(kis-code-assistant 등)**와 **MD 참조 문서**를 아래 역할 분담에 맞춰 사용합니다: + +1. **거시적 구조 & 영향 범위 파악 → MD 문서 (`docs/like_mcp.md/`)** + - 새 대화 시 또는 작업 전 전체적인 지도(Layer, Hub 파일)가 필요할 때 목차 및 관련 섹션을 빠르게 참고합니다. +2. **미시적 코드 & API 조회 → MCP 도구 우선 사용** + - 특정 파일의 소스코드를 보거나 API 스펙을 탐색할 때는 파일 전체를 읽어 토큰을 낭비하지 말고, MCP 도구(`read_source_code`, `search_*_api` 등)나 `grep_search`를 우선 사용하여 실시간 최신 상태를 조회합니다. +3. **수정 전 `grep` 필수 실행** + - MD 문서는 "어디를 검색할지" 알려주는 지도입니다. 실제 수정을 단행하기 전에는 반드시 `MODIFICATION_GUIDE.md`에 명시된 필수 `grep` 명령을 실행하여 관련 파일 목록을 정확히 확정하세요. + +--- + +## 🔄 코드 변경 시 MD 문서 필수 업데이트 룰 (Stale 방지) + +코드를 수정하거나 새로운 기능을 추가한 후(특히 커밋 전/후)에는 **반드시 MD 문서와의 완결성을 유지**해야 합니다. 아래 상황 발생 시 문서를 무조건 업데이트하세요: + +1. **파일 추가/삭제/이동 또는 import 변경 시** + - `code_architecture.md` 갱신 (스크립트 활용 또는 내용 반영) +2. **DB 테이블/컬럼 또는 환경변수(ENV) 추가/변경 시** + - `db_erd.md` 및 `MODIFICATION_GUIDE.md` 체크리스트 반영 +3. **검증 의무 (실매매 엔진 사전 100% 무결성 검열 필수에 관한 절대 규칙)** + - 코드를 수정하면 실매매/백테스트/웹/파라미터서치 정합성 및 영향도를 100% 검증하고 완료 알림에 변경 내용을 명시합니다. + - **핵심 실매매 코드 수정 또는 DB 파라미터/환경변수(ENV)/스키마 변경 시**에는 반드시 최종 완료 전 `.venv/bin/python3 scripts/test_live_execution_validation.py`를 가동하여 1~5단계 전 구간 100% 통과(`👑 [최종 판정] 완결!`)를 확정 지어야 합니다. + +--- + +## 🚨 하드코딩 절대 금지 (NO HARDCODING) + +- 어떠한 경우에도 코드 내부에 임계값, 비율, 점수, 시간 등의 수치를 직접 하드코딩하지 마세요. +- 숫자값을 추가하거나 수정할 때는 **반드시** `get_env_float()`, `get_env_int()`, `get_env_bool()`을 사용하여 DB/Env에서 불러오도록 작성하세요. + - ❌ `if rsi > 78:` (절대 금지) + - ✅ `rsi_limit = get_env_float("RSI_LIMIT", 78.0); if rsi > rsi_limit:` (필수 적용) +- 변수명은 직관적인 대문자 스네이크 케이스(예: `MAX_DROP_RATE`)로 작성하고 기본값을 설정하세요. +- **신규 env 키 추가 시 4개 세트 등록 의무**: 아래 4곳을 한 세트로 반드시 등록하세요. + 1. 코드 내 `get_env_*` 기본값 지정 + 2. `database.py` ENV 키 목록에 추가 + 3. 필요 시 `*_env_keys.py` 키 목록에 추가 + 4. `apply` 패치 맵에 추가 + - 저장 후 `get_env_from_db`로 **재조회 검증** 필수 + +--- + +## 🏗️ 시스템 아키텍처 원칙 + +### SCAN vs TRIGGER 분리 +- **SCAN 단계**: 조건 필터링을 최소화하여 후보를 DB에 최대한 많이 올립니다. +- **TRIGGER 단계**: 실제 매수 직전 모든 엄격한 필터(보조지표, 호가, 수급 등)를 한 번에 검사합니다. +- 무거운 연산(API 추가 호출, 분봉 분석 등)은 절대 5분 주기 스캔 함수에 넣지 말고, **매수 타점 체크 함수에 넣으세요.** + +### WebSocket 우선, REST 최소화 +- REST는 가능하면 **WebSocket/캐시/DB 재사용**으로 대체하세요. +- REST를 대체할 수 있는 경우에는 최대한 WebSocket을 사용합니다. +- 루프·재큐·벌크 등에서 REST 연타 금지. `SafeRequest`·기존 세마포어·sleep·쿨다운을 우회하는 새 경로를 만들지 마세요. + +### 공통 코드 함수화 +- 여러 전략에서 공통으로 사용할 수 있는 코드는 **반드시 공통 함수로 분리**하여 재사용하세요. +- 전략별로 동일한 로직을 중복 작성하지 마세요. + +### 손절 및 안전 장치 필수 +- 모든 매매 로직에는 손절(Stop-loss) 및 예외 처리 로직이 포함되어야 합니다. +- 코드 작성 후 스스로 아래 항목을 검토하세요: + 1. 손절(Stop-loss) 및 예외 처리 로직이 포함되었는가? + 2. API 호출 제한(429 Error) 및 슬리피지 고려가 되었는가? + 3. `None`/`null`로 인한 런타임 오류가 발생하지 않는가? + 4. 기존 로직과 100% 동일한 기능을 수행하는가? + +--- + +## 🔄 실매↔백테↔파람 정합 규칙 (필수) + +- **실매매 기준으로 백테스트, 파라미터서치 코드를 맞춥니다.** 백테/파람서치 코드는 실매매 코드와 100% 동일해야 합니다. +- **새로 추가한 코드의 기본값은 항상 DB에 추가**해야 하며, 웹 페이지 입력값과 일치해야 합니다. +- 코드 수정 시 **실매매·웹 백테스트·파라미터서치의 결과값이 동일**해야 하며, 검증을 반드시 거쳐야 합니다. +- 수정 사항이 **실매에 영향이 가는지 vs 백테/파라미터에만 영향이 가는지** 명확히 분류한 후 보고하고 수정합니다. +- Optuna 파라미터서치 실행 시: + - 주말/공휴일이면 **최근 거래일**로만 실행 + - 그리드 변경 후 **반드시 새 `--study-name`** 사용 (동일 study 재사용 금지) + - `*_SKIP_HTS_SCAN_DUPES` 는 **false 유지**, 임의로 true로 바꾸지 말 것 + +--- + +## 🚫 절대 금지 사항 (위반 시 작업 중지) + +### 봉 정합·진입 정렬 +- **신호 = T−1 확정봉, 진입 = T(시가/첫 틱).** `live_backtest_align=True` 잠금. +- 유니버스·신호·진입을 **±1분(또는 ±1봉) 보정·오프셋·슬롯 해킹**으로 맞추는 코드 **절대 금지**. +- **`WS_CANDLE_FREEZE_ON_CONFIRM` 끄기(false) 절대 금지.** 사용자 명시 승인 없이 변경 금지. + +### OHLC 폴백 금지 +- 틱 청산/진입 ON이면 봉 OHLC(high/low)로 체결·`max_price`·PnL을 채우지 마세요. +- OHLC 폴백으로 숫자를 변조하는 것은 실매와 다른 엔진을 만드는 행위입니다. + +### HTS 조건식과 코드 분리 +- HTS는 후보 유니버스 참고용입니다. 그리드를 HTS 밴드에 맞추라고 강제하지 말 것. +- `*_SKIP_HTS_SCAN_DUPES` 는 사용자가 언급하기 전까지 **false 유지**. 임의로 true로 바꾸지 말 것. + +### DB 쿼리 안전 규칙 +- SQL 전 **반드시** `SHOW COLUMNS FROM
| ${causeBadge}${nameCell} | ", + "${causeBadge}${nameCell}${linksHtml} | " +) + +js = js.replace( + "if (opts.showDebug) html += `${debugHtml} | `;", + "if (opts.showDebug) html += `${debugHtml} | `;\n html += `${_entryObCellHtml(r.entryOb)} | `;\n html += `${_exitObCellHtml(r.exitOb, r.isOpen)} | `;" +) + +js = js.replace( + " html += `${reasonHtml} | `;", + " html += `${reasonHtml} | `;" # unchanged but kept for context, already handled above +) + +helper_funcs = """/** KR 6자리 종목코드 */ +function _normKrStockCode(code) { + const d = String(code || '').replace(/\\D/g, ''); + if (!d) return ''; + return d.length >= 6 ? d.slice(-6) : d.padStart(6, '0'); +} + +function _tradeExtLinksHtml(r) { + if (r.isUsd || !r.code) return ''; + const c = _normKrStockCode(r.code); + return ` + + `; +} + +function _entryObCellHtml(ob) { + if (!ob) return '-'; + const mr = (ob.mid_ratio || 0).toFixed(1); + const wr = (ob.whale_ratio || 0).toFixed(1); + return `M:${mr}%