diff --git a/README.md b/README.md index c80f18fe..be21c206 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,16 @@ 실전 주문과 잔고 조회는 KIS API를 사용합니다. 데이터 수집, 리스크 관리, 알림, 대시보드, 리밸런싱 기능도 함께 붙여가며 확장하고 있습니다. -> **현재 상태 (2026-06-01)**: +> **현재 상태 (2026-06-10)**: +> - **바스켓 paper 운영 개시**: `kr_diversified_hold`(분산 대형주 buy&hold, 주식 80%/현금 20%) enabled — 일일 자동 사이클(리밸런싱 → NAV 스냅샷 → DB 백업 → 승격 진행률 보고)로 60영업일 트랙레코드 축적 중. `--mode health`가 사이클 끊김(스냅샷 4일+)을 자동 경고 +> - **paper→live 승격 기준 정의**(`docs/BASKET_PAPER_EVALUATION.md`): 60영업일·스냅샷 커버리지 ≥95%·dead-letter 0건·비용 드래그 ≤1%/년. 베타 전략이므로 "시장 초과수익"은 기준이 아님. `tools/basket_paper_evaluation.py`로 자동 판정(WAIT/PASS_CANDIDATE/FAIL_REVIEW) +> - **바스켓 전용 live gate 분기**: 기존 게이트가 바스켓에 신호 전략용 canonical promotion(벤치마크 초과수익 포함)을 요구해 영구 통과 불가였던 함정 해소 — paper 평가 PASS_CANDIDATE 기반으로 실제로 열리는 경로 확립. 전환 절차는 `docs/BASKET_LIVE_RUNBOOK.md`(모의서버 리허설 → 실계좌 소액 → 목표 자본) +> - live 바스켓 리밸런싱 실행 가능화: BUY가 "paper-only" 차단으로 항상 실패해 SELL-only 현금화가 되던 버그 수정(일반 매수와 동일한 집행 안전장치 + live gate 검사 승계), 회전율 예산 SELL 우선·부분 실행, KIS 잔고 미확인 시 사이징 fail-closed +> - 주문 응답 유실 시 재시도 래퍼가 재전송하던 잔여 구멍 폐쇄(`KISOrderResponseUnknown` → reconcile 대기), 손절가 하한 클램프, 히스터리시스 SELL 해제 부호 수정, 내장 지표 폴백 pandas-ta 패리티(RSI ~12pt 오차 정정) +> - 트랙레코드 도구가 현금 배분(`target_stock_weight`·`min_cash_ratio`)을 무시해 수익·MDD를 과대 보고하던 문제 정정 — 배포 바스켓 정직 수치(2021-12~2026-06): **CAGR +26.9%, Sharpe 1.09, MDD −21.4%** +> - 인자 없이 실행 시 백테스트 자동실행 대신 사용 가이드 출력(`--mode guide`), 운영 문서 v6.1 갱신 +> +> **이전 상태 (2026-06-01)**: > - 적대적 코드 감사로 실거래 안전 버그 정리: KIS 주문이 응답 유실 시 재전송돼 이중 체결되던 경로를 `idempotent=False`로 차단(최대 1회 제출), 서킷 브레이커 재시도 루프 내 재확인, 429 Retry-After HTTP-date 크래시 가드 > - 부분 익절이 매 모니터링 사이클마다 재발동되던 버그 수정(`Position.partial_tp_done` 영속화), 스케줄러 진입 예외 시 손절/익절 스킵 방지, 일일 손실 한도 기준값에 당일 스냅샷 사용 차단 > - 라이브 게이트 fail-closed 보강: NaN/Inf 지표가 임계값 비교를 통과하던 구멍을 막아(`_as_float` 비유한값 → None) 손상된 지표로 라이브 승격되는 것을 차단 diff --git a/docs/BASKET_LIVE_RUNBOOK.md b/docs/BASKET_LIVE_RUNBOOK.md new file mode 100644 index 00000000..e0e448c6 --- /dev/null +++ b/docs/BASKET_LIVE_RUNBOOK.md @@ -0,0 +1,75 @@ +# 바스켓 live 전환 런북 (kr_diversified_hold) + +> 작성: 2026-06-10. paper 운영 평가가 `PASS_CANDIDATE`에 도달한 뒤, 임기응변 없이 +> 단계적으로 live 전환하기 위한 절차서. 승격 기준은 `docs/BASKET_PAPER_EVALUATION.md`, +> 게이트 구현은 `core/live_readiness.py`(바스켓 전용 분기) 참고. + +## 전제 (모두 충족해야 시작) + +``` +.venv\Scripts\python.exe tools/basket_paper_evaluation.py +``` +- 판정 **PASS_CANDIDATE** (60영업일·스냅샷 커버리지 ≥95%·dead-letter 0건·비용 드래그 ≤1%/년) +- `--mode health` 가 바스켓 운영 이슈 없음 +- `--mode deploy_check --basket kr_diversified_hold` 로 계획 주문·예상 비용·회전율 확인 + +## 안전장치 요약 (live 리밸런싱이 통과해야 하는 것들) + +`python main.py --mode rebalance` 가 live에서 주문에 도달하려면 **전부** 통과해야 한다: +1. `config.trading.mode: "live"` (settings.yaml) +2. 환경변수 `ENABLE_LIVE_TRADING=true` +3. CLI 플래그 `--confirm-live` +4. 바스켓별 live gate `basket_rebalance:kr_diversified_hold` + (= paper 평가 PASS_CANDIDATE + 바스켓 enabled + 비중 합 1.0 + 데이터 소스 health) +5. KIS↔DB 포지션 동기화 성공 (실패 시 즉시 중단) +6. KIS 잔고 확인 (미확인 시 사이징 fail-closed — 계획 자체를 중단) +7. 주문 단계: OrderGuard·미체결 조회 fail-closed·체결 확인·reconcile 보류·응답 유실 재전송 금지 + +하나라도 빠지면 주문이 나가지 않는다. 이 차단이 정상 동작이다. + +## 단계적 전환 + +### Phase 0 — paper (현재) +- 일일 자동 사이클(스케줄 작업)이 트랙레코드를 축적 중. 개입 불필요. + +### Phase 1 — KIS 모의투자 서버로 live 경로 리허설 (권장) +실계좌 없이 **live 코드 경로 전체**(KIS 인증·주문·체결조회·sync)를 리허설한다. +1. `.env`: KIS 모의투자 앱키/시크릿/계좌 설정 +2. `settings.yaml`: `kis_api.use_mock: true` (모의투자 도메인), `trading.mode: "live"` +3. 실행: + ``` + set ENABLE_LIVE_TRADING=true + .venv\Scripts\python.exe main.py --mode rebalance --basket kr_diversified_hold --dry-run + .venv\Scripts\python.exe main.py --mode rebalance --basket kr_diversified_hold --confirm-live + ``` +4. 검증: 주문 체결 확인 로그(`✅ 매수 완료`), KIS 모의계좌 잔고 = DB 포지션, + `requires_reconcile` 발생 시 다음 사이클에서 자동 대조되는지 +5. 며칠 반복 후 이상 없으면 Phase 2 + +### Phase 2 — 실계좌 소액 +1. **소액만 입금한 실계좌** 사용 (live 자본은 KIS 잔고 기준으로 사이징되므로 + 계좌 잔고 자체가 리스크 상한이다) +2. `settings.yaml`: `kis_api.use_mock: false`, 실계좌 번호 +3. Phase 1과 동일 명령. `--dry-run`으로 계획 먼저 확인 후 실행 +4. 1~2주 관찰: 체결가 품질(슬리피지), 일일 사이클 안정성, 알림 동작 + +### Phase 3 — 목표 자본 +- Phase 2 이상 없을 때 증액. `max_turnover_ratio`(15%)가 사이클당 거래를 제한하므로 + 증액 직후에도 점진 매입된다(한 번에 시장가 폭탄 없음). + +## 비상 절차 + +| 상황 | 명령 | +|---|---| +| 전 종목 긴급 청산 | `ENABLE_LIVE_TRADING=true` + `.venv\Scripts\python.exe main.py --mode liquidate --confirm-live` | +| live 즉시 중지(주문만 차단) | 환경변수 `ENABLE_LIVE_TRADING` 제거 — 이후 모든 live 주문 경로 차단 | +| paper로 복귀 | `settings.yaml` `trading.mode: "paper"` | + +## 전환 후 일상 운영 + +- 일일: 자동 사이클 보고(리밸런싱 결과·NAV·평가 진행률) 확인 +- `--mode health`: 전략·바스켓·blocker 통합 점검 (스냅샷 끊김 자동 경고) +- DB 백업: `data/backups/`에 일일 자동 (retention 14일) +- 주의: live 일일 NAV 스냅샷은 상시 스케줄러(장마감)가 담당 — 일일 CLI 운영을 + 유지한다면 rebalance 종료 시 저장되는 것은 paper 스냅샷 경로이므로, live 전환 후 + 상시 스케줄러(systemd, `deploy/`) 구동을 권장