누적 알파 −1.03%p (n=2) — 하루는 지수를 이겼는데 노출 지표 두 개가 정면으로 어긋난다
실현 2거래 1승 1패로 순손익 −223원(−0.0022%)인데 벤치 B&H가 −1.401%라 당일 알파는 +1.399%p였지만, 표본 2일 누적 알파는 여전히 −1.0323%p이고 같은 원자료에서exposure_pct는 59.398%·core_actual_pct는 0.0%로 서로를 부정한다.
1. 지수를 이겼나 — 하루는 이겼고, 누적(n=2)은 졌다
| 창 | bot_pct | bench_index_pct | bench_bh_pct | alpha_pct |
|---|---|---|---|---|
| 20d | −0.7949 (bot_days 10) | +0.6657 (bench_days 2) | +1.0301 (bench_days 2) | −1.0323 (alpha_days 2) |
| 60d | −0.7949 (10) | +0.6657 (2) | +1.0301 (2) | −1.0323 (2) |
창이 섞여 있다. bot은 10일 누적, 벤치·알파는 2일(8/14·8/18)이다. 그리고 보고된 −1.0323은 어느 산식으로도 재현되지 않는다: bot_pct − bench_bh_pct = −1.825, 일별 알파 단순합(−2.4657 + 1.3989) = −1.0668, 복리 결합 = −1.101. 0.03%p 차이의 출처를 확인하지 못했다. 결함으로 올린다.
당일 알파는 산수가 맞는다: net_pnl_pct(−0.0022325) − bench_bh_pct(−1.4010827) = +1.3988502 = alpha_pct. 즉 당일 알파는 실현손익만 쓴다(D3와 같은 정의 문제). 오늘의 +1.40%p는 봇이 잘 벌어서가 아니라 지수가 −1.40% 빠지는 동안 봇의 실현손익이 사실상 0이었기 때문이다.
수익률 비교가 성립하는지부터 판정할 수 없다.
| 지표 | 값 |
|---|---|
exposure_pct | 59.398% |
core_actual_pct | 0.0% (기대 60.0) |
| 15:40 WARN | 코어 노출 격차 −60.0%p — 069500 실제 0.0/목표 24.0 · 379800 실제 0.0/목표 36.0 |
unrealized_pnl | 0.0 |
mtm_pnl_pct | +0.162027% |
bench_intraday_pct | −4.1014% |
8/14에 확인한 관계(코어 미실현 = 장중지수 × 노출)를 오늘 적용하면 −4.1014 × 0.594 = −2.436%가 나와야 한다. 실제 mtm_pnl_pct는 +0.162%다. 관계가 깨졌고, 노출이 59%였는지 0%였는지도 원자료가 서로 다르게 말한다. exposure_pct_avg = 59.231은 8/14(59.065)과 오늘(59.398)의 단순 평균이다 — 8/14에 미해결로 남긴 분모 질문의 답은 "벤치 표본일 2일"이다.
2. 결과 — 실현 2건, 비용이 총이익을 삼켰다
| 항목 | 값 |
|---|---|
| 레짐 | GREEN (09:30:02) · 코스피 +2.798% · 기울기 +0.572%p · 코스닥 −0.286% · 전일 +2.416% |
| 대상 | 069500 + 229200 |
| 거래 / 승 | 2 / 1 (승률 50%, n=2 — 구간을 낼 수 없다) |
| 총이익 / 비용 / 순손익 | +371원 / −594.25원 / −223.25원 (−0.0022%) |
| 누적 실현 / cum_return / MDD | −0.7949% / −0.7952% / 0.9557% (MDD 변동 없음) |
| 워치독 / API 오류 | 0 / 0 |
| 관찰 | 정적 25 → 동적 3 (ETF 3종 dynamic_detail: null 유지) |
| 지수 | 최저 −2.642%, 최고 +3.405% |
| 아카이브 | 25종목 9,794봉 |
시간 순서
| 시각 | 일 |
|---|---|
| 08:55:39 | WARN 포지션 복원 2건 — 379800 144주 @24,953.74 · 069500 21주 @110,191.53 |
| 09:30:02 | GREEN, 대상 069500 + 229200 |
| 09:35:23 | 229200 신호 14,835 → 지정가 14,835 / 67주 (눌림 0.436%) |
| 09:35:41 | 체결 14,835 (18초), slippage 0.0 |
| 09:45:38 | trail_exit 14,942 — 순 +6,869.74원 (+0.6912%), mfe 1.146 / mae −0.169 |
| 09:45:39 | 1.1초 뒤 재진입 신호 14,950 → 지정가 14,950 / 66주 (눌림 0.433%) |
| 09:45:41 | 체결 14,950 (2초) |
| 09:48:50 | stop_loss 14,847 — 순 −7,092.99원 (−0.7189%), mfe 0.067 / mae −0.635 |
| 15:40:38 | WARN 코어 노출 격차 −60.0%p (봇이 스스로 "결함 #7"을 찍었다) |
세 가지가 확정된다.
(a) 069500은 대상이었지만 한 건도 거래되지 않았다. 실현 2건 모두 229200이다. 사유는 원자료에 없다.
(b) 손절 실행이 파라미터보다 깊다 — 실전에서도. 14,950 → 14,847 = −0.689%(기준 −0.6%), 순 −0.719%. mae −0.635와도 어긋난다. 재생 편차(D5)와 같은 방향이다. 실전 손절 누적 7건.
(c) 청산 1.1초 뒤, 더 높은 가격에 재진입해 3분 만에 손절했다. trail_exit 14,942 → 재진입 14,950. 쿨다운이 없다. 하루 표본이므로 규칙을 바꾸지 않고 가설로 넘긴다.
비용 구조: 총이익 +371원에 비용 594원이라 승률 50%에도 순손실이다. 회당 명목 약 100만원(자본 10%)에 왕복 비용 약 297원 = 0.03%. 목표 +1.0%·손절 −0.6% 구조에서 이 비용이 기대값을 어느 정도 깎는지는 표본 2건으로 계산하지 않는다.
3. replay 비교 — 트레일링 대조군이 처음으로 차이를 만들었다
| 재생 | 관찰 | 거래 | 기대값 | 순손익 |
|---|---|---|---|---|
| v4 ETF 레짐 (현재 전략) | — | 4 | −0.034%/거래 | −6,748원 (−0.07%) |
| v4 트레일링 끔 (대조군) | — | 4 | +0.188%/거래 | +37,520원 (+0.38%) |
| v2 반사실 (구 VWAP 회귀) | 3 | 3 | −1.105%/거래 | −164,102원 (−1.64%) |
| v2 트레일링 끔 | 3 | 3 | −1.105%/거래 | −164,102원 (v2 반사실과 동일) |
| v2 옛 유니버스 상한 | 1 | 2 | −1.018%/거래 | −100,474원 (−1.00%) |
| v2 3단계 지수차단 −1.5 | 3 | 3 | −1.105%/거래 | −164,102원 (v2 반사실과 동일) |
| v2 4단계 손절·익절·사이즈 | 3 | 3 | −1.980%/거래 | −75,013원 (−0.75%) |
(a) v4 재생이 실전을 재현하지 못한다. 재생 4건(229200 09:40 14,840 / 229200 09:51 14,915 / 069500 10:06 113,445 / 229200 10:27 15,020) 대비 실전은 09:35 14,835·09:45 14,950 2건이다. 진입 시각이 약 5분, 가격이 5~35원 어긋나고 069500 진입은 재생에만 있다. 거래 건수부터 다른 도구의 출력을 실전 판정에 쓸 수 없다. n=1로 확정되는 대조군 소실이다 — 결함으로 올린다.
(b) 트레일링을 끄면 오늘은 +44,268원 좋았다. 차이가 난 거래는 2건이고 둘 다 같은 형태다: trail_exit +0.60% / +0.45% → take_profit +0.97% / +0.97%. v4의 무장·되돌림선이 목표 +1.0%에 닿기 전에 먼저 작동해 이익을 절반 이하로 자른다. 실전에서도 같은 일이 있었다: 19번 거래는 mfe 1.146%로 목표 +1.0%를 넘겼는데 trail_exit +0.72%(총)로 끝났다. 방향은 재생 2건 + 실전 1건이 모두 일치하지만 n=3이다. 파라미터를 바꾸지 않고 가설로 넘긴다.
(c) v2는 3건 전부 손절, 트레일링 차이 0. 무장선 3.0%에 닿은 거래가 없어 v2 대조군은 오늘도 정보량이 없다.
(d) 옛 상한은 오늘도 손실 축소 방향이다. 갭 ≤3.0·변동폭 ≤2.5로 조이면 관찰 3 → 1종목(086520 에코프로: 갭 −0.86 · 변동폭 2.27 · 거래량비 0.87), 손실 −1.64% → −1.00%. 다만 여전히 음수이고, 같은 종목 재진입으로 거래는 2건이 됐다. 5거래일째 "완화가 손익 양방향을 키운다"는 정황이 같은 형태로 나온다 — 가설로 넘긴다.
(e) 3단계 −1.5는 지수가 −2.64%까지 빠진 날에도 판정되지 않았다. 출력이 기준값과 한 글자도 다르지 않다. v2 진입은 11:08·11:41이고 차단 26분과 겹치지 않았다는 뜻으로 읽힌다.
(f) 4단계에서 8/14 형태가 재현됐다. 기대값 −1.105 → −1.980%로 악화, 자본손실 −1.64 → −0.75%로 개선(POSITION_FRACTION=0.13). 손절 폭 효과와 사이징 효과가 여전히 분리되지 않는다(가설 3에 표본 3건 추가).
(g) D5가 6건 더 늘었다. 기준 −0.6%에 −1.04 / −1.06 / −1.21%, 기준 −1.5%에 −1.93 / −1.93 / −2.08%. 누적 12건, 한 번도 반대 방향이 없다.
(h) 유니버스 개수 일치가 복구됐다. v2 관찰 3 = 실전 동적 통과 3(동진쎄미켐·에코프로·두산테스나), v2가 거래한 131970·005290·086520 전부 통과 목록 안이다. 8/14의 9 vs 8 불일치는 오늘 재현되지 않았다(가설 5는 유지 — 하루로는 판정하지 않는다).
4. 조건 C — 26분, 9거래일 만에 처음 걸렸다
blocked_minutes = 26, 임계 −1.0%, 지수 최저 −2.642%.
| 날짜 | blocked | 진입창(09:30~14:00, 271분) 기준 | 지수 최저 |
|---|---|---|---|
| 8/7 | 271분 | 100% | −6.51% |
| 8/10 | 0분 | 0% | −0.987% |
| 8/11 | 4분 | 1.5% | −1.363% |
| 8/12 | 0분 | 0% | +1.164% |
| 8/13 | 0분 | 0% | +2.588% |
| 8/14 | 0분 | 0% | +0.525% |
| 8/18 | 26분 | 9.6% | −2.642% |
지수가 −1.5% 아래로 내려간 첫날인데도 3단계 조건("−1.0~−1.5 구간에 머문 분에 진입 성립 1회")은 미충족이다: −1.5 대조군 출력이 기준과 동일했다. 차단된 26분이 몇 시부터인지는 원자료에 시각이 없어 확인하지 못했다 — 실전 진입 2건(09:35·09:45)이 차단창 밖이었는지도 판정할 수 없다. 값이 0이 아닌 첫날인데 분모·시각 검증은 여전히 불가능하다.
5. 미해결 결함 — 7건, probe 7건 실행, 그중 3건은 형식 오류로 답이 없다
| ID | 나이 | 요약 | probe 결과 판정 |
|---|---|---|---|
| D1 | 2일 | 코어가 산 379800이 watchlist에 없다 | 미해결. sql:core_orders가 8/14 체결 2건만 돌려줬고 후보군은 답하지 않는다. 379800은 오늘 25종목에도 없다 — probe가 질문에 답하지 않는 것이 막고 있다 |
| D2 | 2일 | 코어 지정가가 신호가보다 위 (24,915 → 24,950) | 판정 불가. 같은 probe가 주문가를 찍지 않는다. probe 교체 필요 |
| D3 | 2일 | cum_return과 rolling.bot_pct의 미실현 포함 여부가 다르다 | 실행 불가 — probe 문자열에 설명문을 붙여 등록 실패. 오늘 정황: 미실현 0인 날 cum(−0.7952)과 bot_pct(−0.7949)가 수렴했고, mtm_pnl_pct +0.162는 두 계열 어디에도 없다 |
| D4 | 2일 | 체결가=주문가인데 slippage가 null | 미해결, 범위 좁혀짐. 오늘 lab 2건은 slippage 0.0으로 정상 기록 — null은 코어 경로 한정 정황 |
| D5 | 2일 | 재생 손절 실행가가 파라미터보다 깊다 | 미해결, 6건 추가(누적 12건 전부 한 방향). probe 종류가 허용 목록(tick·sql)에 없어 실행 불가 |
| D6 | 2일 | 회고 결함이 진화 블록에 오르지 않아 defects가 빈 배열 | 해결. defects 7건 · defect_counts.probing = 7 · probes_run = 7 |
| D7 | 1일 | 코어 노출 격차 −60.0%p (실제 0.0 vs 목표 60.0) | 미해결. probe가 8/14 체결 2건만 돌려줬다. 그 두 건의 비고가 stop_loss·trail_exit이므로 코어가 이미 청산된 정황이지만, 오늘 08:55에 같은 수량이 복원됐고 exposure_pct는 59.398이다 |
D3·D5·D6의 probe가 실행되지 않은 원인은 내 쪽이다. 검증 칸에 등록된 이름(sql:exit_expectancy 등) 대신 설명 문장을 넣었다. 결함으로 올려 오늘 고친다.
evolution.stale_days = 3인데 개별 결함은 전부 stale: false다. 이 필드가 무엇을 세는지 원자료에 정의가 없어 확인하지 못했다.
6. events — 28건, 경고 3건, 주문·체결이 2건 남는다
| type/level | n |
|---|---|
| fill INFO | 6 |
| order INFO | 6 |
| bot INFO | 5 |
| universe INFO | 3 |
| bot WARN | 2 |
| watchdog INFO | 2 |
| archive · gate · report INFO | 각 1 |
| report WARN | 1 |
order 6 / fill 6인데 lab 거래 2건은 주문 4·체결 4다. 남는 2주문·2체결은 08:55에 복원된 코어 2종목의 청산으로 읽히지만 trades 배열에 없다. cancel 0 · 미체결 0. 특정 type이 수천 건인 루프 징후는 없다.
+16,203원 규모(mtm_pnl_pct 0.162% × 자본)의 손익이 실현(−223원)에도 미실현(0)에도 없다. 이 돈의 출처를 확인하지 못했다. 결함으로 올린다.
report WARN은 봇이 스스로 코어 노출 격차를 감지해 결함 번호까지 찍은 것이다 — 자기 진단이 작동한 첫 사례다.
7. 내일 확인할 것
- 코어가 청산됐는가 복원됐는가. 08:55 복원 WARN과 15:40 실제 0.0%가 같은 하루에 있다
- 069500이 대상인데 왜 한 건도 거래되지 않았나
- 차단 26분의 시각. 진입창 안이었는지 밖이었는지
- 청산 직후 재진입에 쿨다운이 있는가
- v4 재생과 실전의 진입 시각 5분 차이가 봉 해상도 문제인가 신호 판정 시점 문제인가
조치 — 파라미터는 바꾸지 않는다
실현 표본은 오늘 2건, 누적 9건이다. 트레일링 대조군이 처음으로 차이(+44,268원, 차이 발생 거래 n=2)를 냈지만 그 재생은 오늘 실전을 재현하지 못했다. n<500에서 트레일링·손절·상한·사이즈를 건드리지 않는다.
| 단계 | 조건 | 현재 |
|---|---|---|
| 3 조건 C −1.5 | 지수가 −1.0~−1.5 구간에 머문 분에 진입 성립 1회 | 지수 최저 −2.642%로 구간을 통과했으나 −1.5 대조군 출력이 동일 — 미충족 (10거래일 연속) |
| 4 손절 −1.5 | 실전 손절 10건 누적 | 7건 (오늘 1건 추가) |
| 4 익절 +2.5 | 고점 +3.0% 도달 거래 1건 | 0건. 오늘 최대 mfe 1.146% |
| 5 거래량비 | 재생이 실전을 재현한 뒤 판정 | 보류 — v4 재생이 거래 건수부터 어긋났다 |
10거래일 정리
| 날짜 | 전략 | 레짐 | 실현 거래 | 승 | 실현 순손익률 | 노출 | 지수 최저 |
|---|---|---|---|---|---|---|---|
| 8/4 | v2 | — | 0 | — | 0% | — | −2.83% |
| 8/5 | v2 | — | 2 | 0 | −0.42% | — | +4.57% |
| 8/6 | v2 | — | 2 | 0 | −0.25% | — | −1.82% |
| 8/7 | v2 | — | 0 | — | 0% | — | −6.51% |
| 8/10 | v2 | — | 2 | 0 | −0.232% | — | −0.987% |
| 8/11 | v4 | RED_B | 0 | — | 0% | — | −1.363% |
| 8/12 | v4 | GREEN | 1 | 1 | +0.118% | — | +1.164% |
| 8/13 | v4 | FLAT | 0 | — | 0% | — | +2.588% |
| 8/14 | v4 + core | FLAT | 0 | — | 0% | 59.07% | +0.525% |
| 8/18 | v4 + core | GREEN | 2 | 1 | −0.0022% | 59.40% / 0.0% | −2.642% |
누적 9거래 2승 7패, 실현 −0.7949%, cum −0.7952%, MDD 0.9557%.
오늘 얻은 것은 하나다: 트레일링이 v4에서 목표 +1.0%를 못 채우게 막는다는 첫 신호(재생 2건 + 실전 1건, 전부 같은 방향). 잃은 것은 더 크다 — 노출·미실현·재생 세 계측이 각자 다른 이야기를 하고 있어서 오늘 지수를 이겼다는 +1.40%p가 실력인지 계측 오류인지 판정할 수 없다.
진화 블록
| 종류 | 내용 | 검증 |
|---|---|---|
| 결함 | 같은 daily 블록에서 exposure_pct 59.398 과 core_actual_pct 0.0 이 서로를 부정한다 | sql:core_exposure |
| 결함 | 08:55 복원된 코어 2종목의 청산이 trades 배열에 없다 — order 6·fill 6 대비 lab 거래는 주문 4·체결 4 | sql:core_orders |
| 결함 | mtm_pnl_pct +0.162% (약 16,203원) 가 실현(−223원)에도 unrealized(0)에도 없다 | 사람이 mtm_pnl_pct 가 어느 계좌·어느 시점 가격을 쓰는지 코드에서 확인한다 |
| 결함 | rolling.alpha_pct −1.0323 을 원자료로 재현할 수 없다 — bot 10일과 bench 2일을 섞고 있고 일별 합은 −1.0668 이다 | 사람이 rolling 창의 bot·bench 표본일 정렬과 알파 결합 방식을 확인한다 |
| 결함 | v4 재생이 실전을 재현하지 못한다 — 실전 2건(09:35 14,835 · 09:45 14,950) 대 재생 4건(09:40 14,840 · 09:51 14,915 · 069500 10:06 · 10:27) | sql:unfilled_orders |
| 결함 | D3·D5·D6 의 probe 칸에 설명 문장을 넣어 3건이 실행 불가로 반환됐다 | 사람이 세 결함의 probe 칸을 등록된 이름으로 교체했는지 확인한다 |
| 가설 | v4 트레일링이 목표 +1.0% 도달 전에 작동해 기대값을 깎는가 — 오늘 대조군 차이 44,268원 n=2 및 실전 mfe 1.146% 거래 1건 | 60거래일 재생에서 TRAIL_ENABLED 0/1 기대값과 take_profit 도달 비율을 비교 |
| 가설 | 청산 직후 재진입 쿨다운이 기대값을 개선하는가 — 오늘 1.1초 뒤 더 높은 가격에 재진입해 3분 만에 손절 | 500거래 이상 백테스트에서 쿨다운 0/60/300초 격자로 기대값 비교 |
| 가설 | 갭·변동폭 상한 완화가 손실 방향에서도 손익 규모를 키우는가 — 오늘 −1.64% 대 옛 상한 −1.00%, 5거래일째 같은 방향 | 60거래일 재생에서 GAP_MAX·RANGE_MAX 격자로 손익 분포의 분산을 측정 |
| 해결 | D6 | defects 7건 등록 · defect_counts.probing 7 · probes_run 7 로 빈 배열 상태가 끝났다 |