Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
249 changes: 249 additions & 0 deletions docs/PAPER_MONTH1_REVIEW_AND_PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
# 페이퍼 운영 1개월 리뷰 & 개선 설계 (2026-07-02)

> 대상: `kr_diversified_hold` paper 트랙레코드, 2026-06-10 ~ 2026-07-02 (17영업일, 60일 기준의 28%)
> 데이터 출처: 운영 DB(`portfolio_snapshots`/`positions`/`trade_history`), `tools/basket_paper_evaluation.py`,
> FinanceDataReader 종가. 이 문서는 **진단과 계획만** 담는다 — 구현은 항목별 별도 PR로.

---

## 0. 한 줄 결론

**이번 달 -5.47%는 "전략이 틀렸다"는 신호가 아니라, "설계가 아직 실행되지 않았다"는 신호다.**

- 격차의 절반 이상은 **자본 결정 미실행**의 직접 비용이다 — 하이닉스 슬롯 공백(-1.5%p),
주식 배치 61%(설계 80%), 6/10 하루에 몰아서 산 진입 타이밍(-1%p 내외).
- 나머지는 균등가중 바스켓 vs 시총가중 지수의 **구성 괴리**(-3.7%p)로, 설계가 수용한 변동이다.
다만 월 단위로 이만큼 벌어진다는 사실이 리포트에 보이지 않아 "프로그램이 못 번다"로 읽혔다.
- 따라서 할 일은 전략 교체가 아니라 세 가지: **① 자본 결정 실행(오너 결정 1건),
② 결측 없는 사이클(커버리지 94% → 95%+), ③ 판단 가능한 리포트(벤치마크·배치율·진행률 표기).**

---

## 1. 사실 관계 (전부 DB·평가 도구에서 실측)

| 항목 | 값 | 비고 |
|---|---|---|
| 운영 기간 | 2026-06-10 ~ 07-02, 17영업일 | 60일 판정 기준의 28% (`WAIT`) |
| NAV | 10,000,000 → 9,452,986 (**-5.47%**) | MDD -10.69% (6/15 고점 → 6/29 저점) |
| 같은 구간 KS11 | **+0.71%** (7,730.8 → 7,786.1) | 격차 **-6.18%p** ← 이 문서의 분석 대상 |
| 거래 | **6/10 매수 9건이 전부, 이후 0건** | 드리프트 8%p 미도달(하이닉스 제외, 아래 참고) |
| 현금 | **3,887,986원(41.1%)에서 한 달째 고정** | 설계 20% — 원인은 §2 |
| 스냅샷 커버리지 | 16/17 = **94% < 게이트 95%** | **6/26(금) 결측, 원인 기록 없음** |
| 누적 거래비용 | 0.0961% (연환산 1.43%, 판정 미적용) | 초기 매입 일회성 — 60일 시점에 재평가 |
| 시장 상황 | 지수 일간 -10% ~ +8% 스윙의 극변동 구간 | 6/23 하루 -10%, 지수 자체 고점대비 -14.6% |

### 종목별 성과 (6/10 종가 → 7/2 종가)

| 종목 | 수익률 | 보유 | 슬롯 소진율* |
|---|---|---|---|
| **SK하이닉스** | **+18.4%** | **0주 (미체결)** | 0% — 1주 204.8만 > 슬롯 80만 |
| KB금융 | +12.1% | 5주 | 98% |
| 신한지주 | +5.6% | 8주 | 100% |
| 삼성전자 | -1.2% | 2주 | 76% |
| 카카오 | -5.9% | 18주 | 86% |
| NAVER | -11.9% | 3주 | 89% |
| LG화학 | -11.9% | 2주 | 81% |
| POSCO홀딩스 | -12.0% | 2주 | 91% |
| 현대모비스 | -12.5% | 1주 | 69% |
| 현대차 | -17.8% | 1주 | 75% |

\* 슬롯 = 자본 1,000만 × 실효 8%(주식 80% ÷ 10종목) = 80만원. 정수 주식 절사로 9슬롯 평균 85%만 소진.
**하필 못 산 한 종목이 이번 달 최고 상승(+18.4%)이었다** — 자본 결정을 미룬 비용이 실측된 셈.

### 배치 구조 (왜 현금이 41%인가 — 버그 아님, 산수)

```
설계: 주식 80.0% (10종목 × 8%) + 현금 20.0%
실제: 주식 61.1% (9종목, 취득원가) + 현금 38.9%
공백 -18.9%p = 하이닉스 슬롯 -8.0%p + 9슬롯 정수 절사 -10.9%p
```

리밸런서는 매일 돌았고 하이닉스 슬롯의 드리프트(8%p)는 매번 트리거됐지만, 수량 계산이
0주(80만 < 1주 가격)라 체결 불가 — #422가 이 침묵 스킵을 경고로 가시화했고, 남은 것은
운영자 결정이다. 나머지 9종목의 개별 드리프트는 8%p 미만이라 리밸런싱이 없던 것도 정상.
**단, "종목별 드리프트"만 보는 트리거는 집계 배치율(61% vs 80%)의 이탈을 영영 못 본다** — §4 P1-5.

---

## 2. 격차 분해 — -6.18%p는 어디서 왔나

기준선을 두 개 세우면 격차가 "통제 가능한 것"과 "설계가 수용한 것"으로 정확히 갈라진다.

```
실제 NAV -5.47%
│ ② 실행 격차 -2.50%p ← 통제 가능 (프로그램·결정의 몫)
설계 NAV -2.97% ┘ = 하이닉스 공백 -1.5%p + 진입 타이밍 -0.7~-1.0%p
(EW10·주식80%) + 수수료 -0.1%p + 절사 잔여
│ ① 구성 격차 -3.68%p ← 설계가 수용한 변동 (가시화 대상)
KS11 +0.71% ┘ = 균등가중 10종목 vs 반도체 쏠림 시총지수
```

- **① 구성 격차(-3.68%p)**: 이번 달 지수 상승분은 사실상 반도체(하이닉스 +18.4%)가 만들었고,
균등가중 바스켓은 지수 대비 반도체 비중이 낮다. 이건 균등가중 분산 설계의 본질적 성격으로,
4.5년 백테스트에서 장기적으로는 지수급 수익을 확인했기에 수용한 리스크다. **문제는 크기가
아니라 이 숫자가 어디에도 표시되지 않아, 오너가 -5.47%를 전부 "프로그램 탓"으로 읽게 되는 것.**
- **② 실행 격차(-2.50%p)**: 전부 손 쓸 수 있는 항목이다.
- 하이닉스 공백 ≈ -1.5%p → **자본 결정(§3)으로 제거**
- 진입 타이밍 ≈ -0.7~-1.0%p: 6/10 오전 일괄 매수했는데 그날 지수가 -4.5%로 마감
(예: NAVER를 238,500에 사고 당일 종가 227,000). 일회성이지만, 재시작·live 초기 매입에서
재발 방지 옵션 검토 → §4 P2-9
- 수수료·슬리피지 -0.10%p: 저회전 설계가 지켜진 결과. 양호.
- **현금 41%의 역설**: 이번 구간(보유 종목 하락장)에선 오히려 +2%p 이상 완충으로 작용했다.
하지만 이건 운이지 설계가 아니다 — 반대 구간이면 그대로 역풍. "덜 잃어서 다행"이 아니라
"의도한 80%로 돌려놔야 할 이탈"로 읽는 게 맞다.

### 이번 달에서 "정상"이었던 것 (바꾸면 안 되는 것)

- **MDD -10.69% < 지수 낙폭 -14.6%** — 리스크 완충은 작동했다 (원인이 의도치 않은 현금이긴 하지만).
- **회전 0, 비용 0.1%** — "사서 들고 있기" 설계가 실제로 지켜졌다.
- **17일 실적으로 전략을 판단하지 않는다** — 60일 규율은 이런 달을 위해 만든 것이다.
알파 부재 결론(`docs/PROFITABILITY_FINDINGS.md`)도 이번 결과로 흔들리지 않는다:
"이번 달 나빴으니 다른 전략을 찾자"가 가장 흔한 자멸 패턴이고, 그 길은 이미 검증에서 반증됐다.

---

## 3. 오너 결정 1건 — 자본 (P0, 이것 하나가 실행 격차의 대부분을 없앤다)

#422에서 제시한 A/B/C 중 **A(자본 증액)를 다시 권고**한다. 단, 당시 계산은 하이닉스 213만원
기준이라 **최신 시세(242.4만)로 최소 자본이 올라갔다: ≥ 3,030만원** (242.4만 ÷ 8%).

### 자본 규모별 슬롯 채움 시뮬레이션 (7/2 종가 기준)

| initial_capital | 슬롯(8%) | 하이닉스 | 전체 배치율(설계 80% 대비) | 하이닉스 가격 여유 |
|---|---|---|---|---|
| 1,000만 (현재) | 80만 | **0주** | 76% (실효 61%) | — |
| 3,000만 | 240만 | **0주 (242.4만 > 240만!)** | ~87% | 미체결 재발 |
| 3,200만 | 256만 | 1주 (95%) | ~95% | +5.6%까지 |
| **3,400만 (권고)** | 272만 | 1주 (89%) | **~95%** | **+12.2%까지** |
| 6,200만 | 496만 | 2주 (98%) | ~97% | +2.3%까지 |

- **권고: `initial_capital: 34000000`** — 3,200만은 하이닉스가 5.6%만 더 오르면 다시 미체결이
된다. 3,400만이 채움율(95%)과 가격 여유(+12%)의 균형점. paper 자본은 실돈이 아니므로 비용 0.
- **더 좋은 선택지가 있다면**: live 전환 시 실제로 투입할 자본 규모를 안다면 **그 금액으로**
재시작하는 것이 최선이다. 자본이 다르면 절사 구조가 달라져 기록의 대표성이 떨어지기 때문.
(미정이면 3,400만으로.)
- B안(하이닉스 제외·재배분)이 차선인 이유: 4.5년 백테스트(10종목)와의 구성 일관성이 깨지고,
이번 달처럼 하이닉스가 주도하는 구간의 수익 원천을 스스로 제거한다.
C안(현상 유지)이 차선인 이유: 61% 배치로 60일을 완주해도 "설계와 다른 것"의 기록이라
평가 가치가 낮다. 게다가 이번 달로 C의 비용(-1.5%p/월 수준)이 실측됐다.

### 실행 절차 (#427 도구로 준비 완료 — 가역·비파괴)

```powershell
# 1) config/baskets.yaml의 kr_diversified_hold에 한 줄 추가: initial_capital: 34000000
# 2) dry-run으로 이전 대상 확인
.venv\Scripts\python.exe tools/restart_basket_track_record.py --basket kr_diversified_hold
# 3) 적용 — 기존 17일 기록은 @archived-<날짜> 키로 이전(삭제 아님, --undo 가능)
.venv\Scripts\python.exe tools/restart_basket_track_record.py --basket kr_diversified_hold --apply
# 4) 다음 일일 사이클(10:07)부터 새 자본으로 초기 매입, 트랙레코드 0/60 재시작
```

**트레이드오프를 정직하게**: 17일 기록을 아카이브하고 0/60부터 다시 센다. 아깝지만 —
(a) 17일은 전체의 28%이고, (b) 그 17일은 "설계와 다른 배치"의 기록이며, (c) 평가 문서가
말하듯 늦출수록 버리는 기록만 커진다. 지금이 손실 최소 시점이다.
**순서 주의**: 재시작 후 또 6/26류 결측이 나면 커버리지 게이트(95%)가 다시 위험해지므로,
P0-1(하트비트·재시도)을 먼저 머지하고 재시작하는 순서를 권장한다 (§5 일정).

---

## 4. 개선 로드맵 (코드 작업 목록 — 각 항목 별도 PR, 이 문서는 계획만)

각 항목에 [축]과 수용 기준을 명시한다. 축 = 안정성 / 편의성 / 수익성 / 기능.

### P0 — 자본 결정과 같은 주에

| # | 항목 | 축 | 내용 · 수용 기준 |
|---|---|---|---|
| 1 | **사이클 하트비트 + 당일 결측 경보 + 자동 재시도** | 안정성 | 6/26 결측은 `operation_events`에 사이클 이벤트가 없어 원인 추적 자체가 불가능했다. cycle_start/cycle_end 이벤트 기록, 10:30까지 스냅샷 없으면 Discord 경보, 11:00·14:00 자동 재시도. **수용: 결측 당일 인지 100%, 재시도로 당일 복구.** |
| 2 | **SMTP_PASSWORD 재발급** (오너 액션 ~5분) | 안정성 | 이메일 경보가 6/11부터 죽어 있어 Discord가 단일 장애점이다. Gmail 앱 비밀번호 재발급 → `.env` 갱신 → `tools/`의 알림 테스트로 확인. **수용: 경보 채널 2개 활성.** |
| 3 | **일일 리포트 v2** | 편의성 | 현재 리포트(총평가금·현금·일일/누적·MDD·보유·매매)는 "얼마"만 있고 "왜"가 없다. 추가: ① 같은 구간 KS11과 격차 ② 배치율(실제 주식비중 vs 설계 80%) ③ 진행률(n/60, 커버리지 %, 잔여 결측 예산 n일) ④ 미체결 슬롯 경고(예: "하이닉스 0주 — n일째, 자본 결정 대기") ⑤ 누적 비용. 데이터는 전부 evaluator에 이미 있음 — 구현 위치는 #425의 스냅샷 리포트부(core/basket_rebalancer.py). **수용: 리포트만 보고 시장 대비/설계 대비/일정 대비 판단 가능.** |

### P1 — 2주 내

| # | 항목 | 축 | 내용 · 수용 기준 |
|---|---|---|---|
| 4 | **성과 귀속 자동화** | 편의성·수익성 | §2의 분해(실제 vs 설계NAV vs KS11 → 실행 격차/구성 격차)를 evaluator가 매 사이클 계산·저장. 이번 달은 수작업으로 했지만 매달 손으로 할 일이 아니다. **수용: 주간 리포트에 두 격차가 숫자로 표기.** |
| 5 | **집계 배치율 감시 (+선택적 top-up)** | 수익성 | 종목별 드리프트 트리거는 집계 이탈(61% vs 80%)을 못 본다. 배치율이 설계 대비 -5%p 초과 이탈 시 health ATTENTION. 선택 단계(별도 결정): 회전상한 내에서 잔여현금 재배치 주문. 규칙은 단순하게 유지 — 복잡한 조건은 오버피팅으로 가는 문. **수용: 배치율 이탈이 24h 내 ATTENTION으로 표면화.** |
| 6 | **스냅샷 시점 정합** | 안정성 | 현재 NAV는 10:07(아침) 마크인데 벤치마크는 종가라 비교에 시점 왜곡이 있다. 장마감 후(15:40+) 스냅샷으로 이동하거나 동시점 지수를 함께 저장. **수용: NAV와 벤치가 같은 시점 기준.** |
| 7 | **주간 요약 리포트 (금요일)** | 편의성 | 일일 숫자는 노이즈가 커서 판단 주기로 부적합. 주간: 수익/격차 분해/커버리지/이벤트/다음 주 예정. **수용: 오너가 주 1회 이것만 봐도 운영 판단 가능.** |

### P2 — 승격(60일) 전

| # | 항목 | 축 | 내용 |
|---|---|---|---|
| 8 | kr_balanced_5050 병행 트랙레코드 | 안정성 | 50/50 배분을 같은 기간 paper로 병행 — 승격 시점에 "80% vs 50%" 실측 비교군 확보. 기능은 이미 구현됨(enabled만). |
| 9 | 분할 진입 옵션 (기본 off) | 수익성 | 6/10 하루 일괄 매입의 타이밍 비용(-1%p) 재발 방지용으로 초기 매입 2~3분할 옵션. 상승장 기회비용이라는 반대급부를 문서에 명시하고 기본은 끈다 — 재시작·live 첫 매입에만 검토. |
| 10 | 승격 게이트 현황판 완성 | 편의성 | #423 대시보드에 4개 축(기간/커버리지/미해결 주문/비용) 진행률 게이지. |
| 11 | 월간 리허설 유지 | 안정성 | 금요일 복원 리허설 + KIS 모의서버 live 경로 리허설(게이트 통과 전 실계좌 불가는 유지). |

### P3 — 승격(PASS_CANDIDATE) 후

| # | 항목 | 축 | 내용 |
|---|---|---|---|
| 12 | 소액 live 전환 | 기능 | `docs/PAPER_TO_LIVE_RUNBOOK.md` 절차 그대로: 오너 승인 → ENABLE_LIVE_TRADING + --confirm-live → readiness gate → 소액. |
| 13 | 증액 규칙 | 안정성 | 분기 리뷰에서만 증액 결정(성과 쫓는 수시 증액 금지), 회당 상한 명시. |

---

## 5. 일정 (오늘 = 2026-07-02 수)

| 날짜 | 내용 | 담당 |
|---|---|---|
| 7/2 (수) | 이 문서 리뷰 + **자본 결정** (A안 34M 권고) | 오너 |
| 7/3 (목) | P0-1 하트비트/재시도 구현 PR, P0-2 SMTP 재발급 | 개발 / 오너 |
| 7/6 (월) | P0-3 리포트 v2 PR → **트랙레코드 재시작 실행** (0/60) | 개발 |
| 7/13 (월)까지 | P1-4~7 순차 PR | 개발 |
| 8월 말 | 중간 점검 (30/60 부근): 커버리지·배치율·격차 분해 리뷰 | 오너+개발 |
| ~9월 말 | 60일 도달 → `basket_paper_evaluation` 판정 → PASS 시 런북 Phase 진행 | 오너 |

## 6. 하지 않을 것 (이번 결과가 유혹하는 것들)

- **전략 교체·신규 알파 추가** — 17일 성과는 판단 근거가 아니고, 알파 부재는 이미 검증된 결론.
- **성과를 쫓는 파라미터 튜닝** (드리프트 임계값·종목 교체를 최근 수익률 보고 조정) — 오버피팅 재입장.
- **레버리지·파생** — 논외.
- **승격 전 실계좌 연결** — 게이트가 있는 이유가 이번 달 같은 달이다.
- **60일 기준 임의 완화** — 단축은 평가 문서의 절차(명시적 결정 + promotion 레버)로만.

## 7. 성공 기준 (다음 리뷰에서 이 표만 확인하면 된다)

| 지표 | 현재 | 목표 |
|---|---|---|
| 배치율 (설계 80% 대비) | 76% (실효 61%/80%) | **≥ 95%** 상시 |
| 미체결 슬롯 | 1 (하이닉스) | **0** |
| 스냅샷 커버리지 | 94% | **≥ 95%** (결측 ≤ 3/60, 당일 인지 100%) |
| 리포트 판단력 | 절대 수익만 표시 | 벤치 격차·배치율·진행률 표기 |
| 실행 격차 (월간) | -2.5%p | **±0.3%p 이내** (하이닉스 해소 후) |
| 경보 채널 | Discord 단일 | **2개** (Discord+Email) |
| 비용 (연환산) | 1.43% (일회성 왜곡) | **≤ 1.0%** (60일 시점 판정) |

## 부록 A. NAV 시계열 (실측)

| 날짜 | 총평가 | 현금 | 주식 | | 날짜 | 총평가 | 현금 | 주식 |
|---|---|---|---|---|---|---|---|---|
| 6/10 | 9,960,286 | 3,887,986 | 6,072,300 | | 6/23 | 9,848,286 | 3,887,986 | 5,960,300 |
| 6/11 | 9,868,086 | 〃 | 5,980,100 | | 6/24 | 9,550,786 | 〃 | 5,662,800 |
| 6/12 | 10,375,386 | 〃 | 6,487,400 | | 6/25 | 9,684,086 | 〃 | 5,796,100 |
| 6/15 | 10,585,036 | 〃 | 6,697,050 | | **6/26** | **결측** | | |
| 6/16 | 10,578,936 | 〃 | 6,690,950 | | 6/29 | 9,435,586 | 〃 | 5,547,600 |
| 6/17 | 10,446,086 | 〃 | 6,558,100 | | 6/30 | 9,540,986 | 〃 | 5,653,000 |
| 6/18 | 10,290,386 | 〃 | 6,402,400 | | 7/1 | 9,497,986 | 〃 | 5,610,000 |
| 6/19 | 10,349,036 | 〃 | 6,461,050 | | 7/2 | 9,452,986 | 〃 | 5,565,000 |
| 6/22 | 10,057,836 | 〃 | 6,169,850 | | | | | |

현금이 한 달 내내 동일한 것이 §1 "거래 0건"의 물증이다. 고점 6/15 → 저점 6/29 = MDD -10.86%(종가 기준).

## 부록 B. 명령어 모음 (운영 치트시트)

```powershell
# 진행률·이슈 수시 확인
.venv\Scripts\python.exe tools/basket_paper_evaluation.py
# 통합 헬스 (exit 0/1/2)
.venv\Scripts\python.exe main.py --mode health
# 배포 전 점검
.venv\Scripts\python.exe main.py --mode deploy_check
# 트랙레코드 재시작 (자본 결정 후)
.venv\Scripts\python.exe tools/restart_basket_track_record.py --basket kr_diversified_hold # dry-run
.venv\Scripts\python.exe tools/restart_basket_track_record.py --basket kr_diversified_hold --apply # 적용
```
Loading