노출 0.21%로 얻은 알파 +6.11%p — 이건 이긴 게 아니라 자리에 없었던 것이다
지수가 B&H 기준 −6.21% 무너지는 동안 봇은 시간가중 노출 0.213%로 실현 −0.1069%(2거래 0승)를 냈고, 그래서 당일 알파 +6.108%p·3일 누적 알파 +5.139%p가 찍혔지만 이 숫자는 전략의 성과가 아니라 부재의 기록이다.
1. 지수를 이겼나 — 숫자는 이겼다고 말하지만 비교가 성립하지 않는다
| 창 | bot_pct | bench_index_pct | bench_bh_pct | alpha_pct |
|---|---|---|---|---|
| 20d | −0.901 (bot_days 11) | −5.1813 (bench_days 3) | −5.2484 (bench_days 3) | +5.1393 (alpha_days 3) |
| 60d | −0.901 (11) | −5.1813 (3) | −5.2484 (3) | +5.1393 (3) |
D11의 답을 오늘 찾았다. 알파는 재현된다. 산식은 bot_pct가 아니라 벤치와 정렬된 3일의 봇 실현손익 복리를 쓴다.
| 항목 | 계산 | 값 |
|---|---|---|
| 봇 3일 실현 복리 | 0 · (−0.0022325) · (−0.1069126) | −0.10914% |
| 벤치 B&H 3일 복리 | (+2.4657) · (−1.4011) · (−6.2145) | −5.24842% |
| 차 | −0.10914 − (−5.24842) | +5.13928 (보고값 5.1393) |
8/18에도 같은 산식이 맞는다: −0.0022325 − (+1.03004) = −1.03227 (보고값 −1.0323). 어제 "재현 불가"라고 쓴 것은 내가 bot_pct(11일 누적)를 알파의 봇 항으로 착각했기 때문이다. D11은 해결로 넘기고, 남는 문제는 산수가 아니라 표시다 — 같은 rolling 표에 11일 누적과 3일 정렬값이 같은 열처럼 놓여 있어 나란히 읽을 수 없다. 이건 새 결함으로 올린다.
exposure_pct_avg = 39.559 = (59.065 + 59.398 + 0.2127) / 3 정확히 일치. 8/14부터 남겨둔 "분모가 무엇인가"의 답도 확정됐다: 벤치 표본일 3일의 단순 평균이다.
그리고 오늘 노출은 0.213%다. 수익률 비교 자체가 성립하지 않는다. exposure_pct의 정의도 오늘 산수로 확정된다:
| 거래 | 명목 / 자본 | 보유 | 기여 |
|---|---|---|---|
| 917주 × 1,090 = 999,530원 | 9.995% | 09:58:36→10:02:48 = 4.2분 | — |
| 918주 × 1,089 = 999,702원 | 9.997% | 11:18:19→11:22:25 = 4.1분 | — |
| 합 | — | 8.3분 / 390분 | (9.995×4.2 + 9.997×4.1)/390 = 0.2127% |
보고값 0.212739와 소수점 넷째 자리까지 같다. exposure_pct는 시간가중 명목/자본이다. 즉 오늘 봇은 하루 390분 중 8분만 시장에 있었고, 그 8분에서 돈을 잃었다. 지수가 −6.2% 빠진 것과 봇의 −0.107%는 같은 축에 놓을 수 없는 숫자다.
2. 결과 — 인버스를 두 번 사서 두 번 다 졌다. mfe는 두 건 모두 0.0이다
| 항목 | 값 |
|---|---|
| 레짐 | RED_B (09:30:02) · 코스피 −6.378% · 기울기 −0.004%p · 코스닥 −2.406% · 전일 −1.549% |
| 대상 | 114800 KODEX 인버스(1×) 고정 |
| 거래 / 승 | 2 / 0 (승률 0%, n=2 — 구간을 낼 수 없다) |
| 총손익 / 비용 / 순손익 | −10,093원 / −598.26원 / −10,691.26원 (−0.1069%) |
| 누적 실현 / cum_return / MDD | −0.901% / −0.9012% / 0.9557% (MDD 변동 없음) |
| 미실현 / mtm_pnl_pct | 0.0 / −0.1069% (= 실현과 동일) |
| 노출 | 0.2127% (코어 기대 60.0 · 실제 0.0) |
| 워치독 / API 오류 | 0 / 0 |
| 관찰 | 정적 27 → 동적 0 (ETF 3종 dynamic_detail: null) |
| 지수 | 최저 −6.777%, 최고 −3.799% |
| 아카이브 | 27종목 10,578봉 |
| 시각 | 일 |
|---|---|
| 09:30:02 | RED_B — 대상 114800 고정 |
| 09:58:34 | 신호 1,090 (day_high 1101 · 눌림 0.999% · vwap 1090.98) → 지정가 1,090 / 917주 |
| 09:58:36 | 체결 1,090 (2.5초), slippage 0.0 |
| 10:02:48 | trend_loss 1,085 — 순 −4,884.17원 (−0.4886%), mfe 0.0 / mae −0.367 |
| 11:18:16 | 신호 1,089 (눌림 1.090% · vwap 1086.30) → 지정가 1,089 / 918주 |
| 11:18:19 | 체결 1,089 (3.0초), slippage 0.0 |
| 11:22:25 | trend_loss 1,083 — 순 −5,807.08원 (−0.5809%), mfe 0.0 / mae −0.551 |
확정되는 것 셋.
(a) 두 진입 모두 한 번도 플러스가 아니었다. mfe_pct가 두 건 다 0.0이다. 눌림 매수(0.999% / 1.090%) 직후 계속 밀려 4분 만에 추세이탈로 나갔다. 지수가 −6.4% 빠지는 날 인버스를 샀는데도 그렇다 — 인버스는 이미 09:58 이전에 고점 1,101을 찍고 내려오는 중이었고, 봇은 그 하락을 두 번 매수했다. n=2다. 규칙을 바꾸지 않고 가설로 넘긴다.
(b) 청산은 손절이 아니라 trend_loss다. 2번 거래 청산가 1,083은 진입 시각 vwap 1086.30 × (1−0.003) = 1083.04와 일치한다. 손절선 −0.6%(1,082.5)에 닿기 전에 추세이탈이 먼저 작동했다. 실전 손절 누적은 7건에서 늘지 않았다.
(c) 비용 구조가 어제와 반대다. 손실 10,691원 중 가격이 10,093원(94%), 비용이 598원(6%). 회당 왕복 약 299원 = 명목의 0.03%로 8/18과 같다. 증권거래세 0(ETF)이다.
3. replay 비교 — v4가 처음으로 실전을 거의 재현했다. v2는 관찰 0으로 전부 무정보
| 재생 | 관찰 | 거래 | 기대값 | 순손익 |
|---|---|---|---|---|
| v4 ETF 레짐 (현재 전략) | — | 2 | −0.627%/거래 | −62,654원 (−0.63%) |
| v4 트레일링 끔 (대조군) | — | 2 | −0.627%/거래 | −62,654원 (현재 전략과 완전 동일) |
| v2 반사실 (구 VWAP 회귀) | 0 | 0 | — | 표본 없음 |
| v2 트레일링 끔 | 0 | 0 | — | 표본 없음 |
| v2 옛 유니버스 상한 | 0 | 0 | — | 표본 없음 |
| v2 3단계 지수차단 −1.5 | 0 | 0 | — | 표본 없음 |
| v2 4단계 손절·익절·사이즈 | 0 | 0 | — | 표본 없음 |
(a) D12가 크게 좁혀졌다 — 진입은 2건 모두 일치, 청산은 1건 어긋난다.
| 실전 | 재생 | |
|---|---|---|
| 1번 | 09:58 1,090 → 10:02 1,085 (−0.4886%) | 09:59 1,090 → 10:02 1,085 (−0.49%) |
| 2번 | 11:18 1,089 → 11:22 1,083 (−0.5809%) | 11:18 1,089 → 11:22 1,081 (−0.76%) |
거래 건수·종목·진입가·진입 분이 맞는다. 어긋난 것은 2번의 청산가 2틱이고, 그 방향은 재생이 더 깊다 — D5(재생 손절 실행가가 파라미터보다 깊다)와 같은 방향이다. 다만 D5는 파라미터 대비 비교이고 오늘 것은 재생 대 실전 비교라 표본을 합산하지 않는다. 청산가가 vwap−0.3%에서 결정되므로 재생의 vwap 계열이 실전과 미세하게 다르다는 정황이다. D12는 해결로 올리지 않는다.
(b) 재생 규모가 실전의 6배다. 재생 누적 −62,654원(−0.63%) 대 실전 −10,691원(−0.107%). 거래·가격이 같은데 손익 규모가 다르다 — 재생 사이징이 자본 10%가 아니라는 뜻으로 읽히나 원자료에 재생 사이징 값이 없어 확인하지 못했다.
(c) 재생과 실전의 가드 입력값이 다르다. 실전 레짐 prev_close_pct −1.5493, 재생 출력 "가드 통과(전일 −1.63%)". 같은 날 같은 판정을 같은 입력으로 하지 않고 있다. 오늘은 둘 다 가드 통과라 결과가 같았지만, 가드 임계 −3.0 근처에서는 판정이 갈린다. n=1로 확정되는 결정론적 불일치다 — 결함으로 올린다.
(d) 트레일링 대조군은 오늘 차이 0. 두 거래 다 mfe 0.0이라 무장선 3.0%에 근처도 못 갔다. 차이 발생 거래 n=0 — 가설 7에 정보를 더하지 못했다.
(e) v2는 관찰 0종목이다. 그런데 이게 오늘 가장 좋은 소식이다. 재생 탈락 사유 개수와 실전 watchlist의 reject 개수가 완전히 일치한다.
| 사유 | 재생 | 실전 watchlist 집계 |
|---|---|---|
| 거래량 | 15 | 15 |
| 갭 | 12 | 12 |
| 변동폭 | 9 | 9 |
| 데이터부족 | 3 | 3 (ETF 3종 dynamic_detail: null) |
27종 전부 설명된다. 8/14의 9 vs 8 불일치는 이틀 연속 재현되지 않았고, 오늘은 개수가 아니라 사유별 분해까지 맞았다. 가설 5는 유지하되 유리한 방향의 표본이 하나 더 쌓였다.
(f) 대상 114800은 passed_dynamic 0 · dynamic_detail null인데 거래됐다. ETF는 동적 필터를 우회하고 레짐이 직접 지정한다 — 사흘째 같은 형태이고, 설계로 읽히나 원자료에 명시가 없다.
4. 조건 C — 271분, 진입창 100%를 막았다는데 그 안에서 2건이 체결됐다
blocked_minutes = 271, 임계 −1.0%, 지수 최저 −6.777% · 최고 −3.799%.
| 날짜 | blocked | 진입창(271분) 기준 | 지수 최저 |
|---|---|---|---|
| 8/7 | 271분 | 100% | −6.51% |
| 8/10~8/14 | 0~4분 | 0~1.5% | −1.36 ~ +2.59% |
| 8/18 | 26분 | 9.6% | −2.642% |
| 8/19 | 271분 | 100% | −6.777% |
진입 2건(09:58·11:18)은 09:30~14:00 창 안이다. 차단이 271분 전부라면 이 두 건은 성립할 수 없다. 즉 지수차단은 etf_regime_pullback 경로에 적용되지 않는다 — 매도일에 인버스를 사는 전략이므로 설계일 가능성이 크지만, 그렇다면 blocked_minutes는 실제로 거래하는 경로와 무관한 지표이고 8/7 이후 열흘간 이 값을 읽어온 것이 전부 헛것이다. n=1로 확정되는 모순이라 결함으로 올린다.
3단계 조건(−1.0~−1.5 구간 체류 중 진입 성립 1회)은 오늘도 미충족이다. 지수가 하루 종일 −3.80% 아래에 있어 그 구간을 지나가지도 않았다. 11거래일 연속 미충족.
5. 미해결 결함 — 12건, probe 12건 실행, 그중 5건은 형식 때문에 답이 없다
| ID | 나이 | 요약 | probe 결과 판정 |
|---|---|---|---|
| D1 | 3일 · stale | 코어가 산 379800이 watchlist에 없다 | 미해결. sql:core_orders가 사흘째 8/14 2행만 반환. 막는 것: 등록된 probe 중 코어 후보군을 답할 수 있는 질의가 없다. |
| D2 | 3일 · stale | 코어 지정가가 신호가보다 위 | 판정 불가. 같은 probe가 주문가를 찍지 않는다. 위와 동일한 이유로 막혀 있다 |
| D3 | 3일 · stale | cum_return과 rolling 계열의 미실현 포함 여부가 다르다 | 실행 불가(3일째). probe 문자열에 설명문이 붙어 있다. 오늘 정황: 미실현 0이라 mtm_pnl_pct = net_pnl_pct = −0.1069로 완전 수렴, cum(−0.9012)은 복리 누적으로 확인됨 |
| D4 | 3일 · stale | 체결가=주문가인데 slippage null | 미해결, lab은 정상. 오늘 lab 2건 slippage 0.0. null은 코어 경로 한정 정황이 이틀째 |
| D5 | 3일 · stale | 재생 손절가가 파라미터보다 깊다 | 실행 불가. probe 종류가 허용 목록(tick·sql) 밖. 오늘 손절 표본 0건이라 누적 12건에서 늘지 않음 |
| D7 | 2일 | 코어 노출 격차 −60.0%p | 미해결. sql:core_exposure가 8/19·8/18 모두 −60.0%p, 8/14만 −1.1%p로 답했다. 코어는 8/14 이후 이틀 연속 0%다 |
| D8 | 2일 | exposure_pct와 core_actual_pct가 서로를 부정 | 오늘은 모순 없음. 노출 정의(시간가중)가 확정됐고 오늘은 lab만으로 0.2127%가 정확히 재현된다. 8/18의 59.398 대 0.0 모순은 그대로 남는다 |
| D9 | 2일 | 8/18 복원 코어 2종의 청산이 trades에 없다 | 미해결. 오늘은 order 4 / fill 4로 lab 2거래와 정확히 맞아 잔여 주문이 없다. 8/18의 잔여 2건은 여전히 설명되지 않음 |
| D10 | 2일 | mtm_pnl_pct가 실현·미실현 어디에도 없다 | 실행 불가. 오늘은 세 값이 일치해 재현 안 됨 — 코어 보유가 있는 날에만 나타나는 정황 |
| D11 | 2일 | alpha_pct를 재현할 수 없다 | 해결. 위 1장 산식으로 8/18·8/19 두 날 모두 소수점 넷째 자리까지 재현 |
| D12 | 2일 | v4 재생이 실전을 재현하지 못한다 | 미해결, 크게 좁혀짐. 진입 2/2 일치, 청산 1/2 불일치(1,083 대 1,081). probe sql:unfilled_orders는 "건수 0"만 답해 질문에 답하지 않는다 |
| D13 | 2일 | probe 칸에 설명 문장을 넣어 실행 불가 | 미해결, 원인 확정. 오늘도 D3·D5·D10·D11·D13 다섯 건이 "허용되지 않은 probe 종류"로 반환됐다 |
D13이 막힌 이유가 오늘 확정됐다. 회고 규칙은 "자동화할 수 없으면 사람이 할 확인을 한 문장으로 쓴다"고 하는데, probe 실행기는 tick·sql 두 종류만 받는다. 그래서 사람 확인용으로 쓴 문장은 등록은 되지만 매일 실행 불가로 되돌아온다. 규칙과 파서가 충돌한다. 사람 확인이 필요한 결함은 probe가 영원히 답하지 않으므로, 내가 본문에서 직접 판정하고 근거를 적는 방식으로 처리한다. D1·D2는 그 반대 경우다 — 등록된 질의를 썼는데 그 질의가 질문에 답하지 않는다. 사흘째 같은 2행을 받고 있고, 이건 결함 나이만 늘리는 짓이다.
stale_days = 3, D1~D5가 stale: true. 이 다섯 건은 전부 8/14에 열렸고 사흘 동안 한 걸음도 못 갔다. 회고의 실패다.
6. events — 22건, 경고 0건
| type/level | n |
|---|---|
| bot INFO | 5 |
| fill INFO | 4 |
| order INFO | 4 |
| universe INFO | 3 |
| report INFO | 2 |
| watchdog INFO | 2 |
| archive · gate INFO | 각 1 |
order 4 / fill 4 / cancel 0이 lab 2거래(진입·청산 각 2)와 정확히 맞는다. 8/18의 잔여 2주문·2체결 같은 잉여가 없다. 수천 건짜리 루프 징후 없음.
warnings가 빈 배열인 것이 오히려 문제다. 어제는 15:40에 봇이 스스로 코어 노출 격차 −60.0%p를 WARN으로 찍었다. 오늘 sql:core_exposure는 8/19에도 격차 −60.0%p라고 답했는데 경고가 없다. 같은 조건에서 자기 진단이 발화하지 않았다. 결함으로 올린다.
7. 내일 확인할 것
- 코어가 8/14 이후 왜 한 주도 안 사는가. 목표 60%가 이틀 연속 0%인데 주문 기록도 없다
- 지수차단이 ETF 레짐 경로에 적용되는가. 적용되지 않는다면
blocked_minutes를 무엇에 쓰는가 - 재생과 실전의 전일 지수 등락률(−1.63 대 −1.55)이 왜 다른가
- 재생 사이징. 같은 2거래에서 손익 규모가 6배다
- RED_B 눌림 매수가 인버스 하락 구간을 잡는 빈도
조치 — 파라미터는 바꾸지 않는다
실현 표본은 오늘 2건, 누적 11건(2승, 승률 18.2%, n=11)이다. 오늘 얻은 것은 전부 정의 확정과 재현이지 통계가 아니다. n<500에서 눌림폭·추세이탈·손절·상한을 건드리지 않는다.
| 단계 | 조건 | 현재 |
|---|---|---|
| 3 조건 C −1.5 | 지수가 −1.0~−1.5 구간에 머문 분에 진입 성립 1회 | 지수가 하루 종일 −3.80% 아래 — 구간을 지나지 않음. 미충족 (11거래일 연속) |
| 4 손절 −1.5 | 실전 손절 10건 누적 | 7건 (오늘 0건 — 2건 모두 trend_loss) |
| 4 익절 +2.5 | 고점 +3.0% 도달 거래 1건 | 0건. 오늘 최대 mfe 0.0% |
| 5 거래량비 | 재생이 실전을 재현한 뒤 판정 | 조건부 진전 — 유니버스는 탈락 사유까지 완전 일치, v4 진입 2/2 일치, 청산 1건 불일치. 거래 표본이 v2 0건이라 여전히 보류 |
11거래일 정리
| 날짜 | 전략 | 레짐 | 실현 거래 | 승 | 실현 순손익률 | 노출 | 지수 최저 |
|---|---|---|---|---|---|---|---|
| 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% |
| 8/19 | v4 | RED_B | 2 | 0 | −0.1069% | 0.21% / 코어 0.0% | −6.777% |
누적 11거래 2승 9패, 실현 −0.901%, cum −0.9012%, MDD 0.9557%(변동 없음).
오늘 얻은 것은 계측 세 개의 확정이다: 알파 산식(3일 정렬·봇 실현 복리), 노출 정의(시간가중 명목/자본), 유니버스 재생 일치(사유별 개수까지). 잃은 것은 명확하다 — 지수가 6% 무너지는 날 인버스를 지정받고도 두 번 다 mfe 0.0으로 졌고, 코어는 이틀째 아무것도 사지 않았으며, 진입창 100%를 막았다는 차단 지표 안에서 거래가 두 건 나갔다. +6.11%p 알파는 실력이 아니라 8분짜리 참여의 부산물이다.
진화 블록
| 종류 | 내용 | 검증 |
|---|---|---|
| 결함 | 조건 C 차단 271분(진입창 100%) 안에서 진입 2건이 체결됐다 — 지수차단이 etf_regime_pullback 경로에 적용되지 않는다 | 사람이 지수차단 조건이 ETF 레짐 진입 경로에 적용되는지 코드에서 확인하고 적용되지 않으면 blocked_minutes 지표의 대상 경로를 명시한다 |
| 결함 | 재생과 실전의 전일 지수 등락률이 다르다 — 실전 가드 입력 −1.55% 대 재생 출력 −1.63% | 사람이 실전 레짐 판정과 replay_etf.py 가 전일 종가를 같은 소스에서 읽는지 확인한다 |
| 결함 | 코어 노출 격차 −60.0%p가 이틀 연속인데 오늘은 WARN 이 없다 — events.warnings 빈 배열 | sql:core_exposure |
| 결함 | rolling 블록의 bot_pct 는 11일 누적인데 alpha_pct 는 벤치 정렬 3일 실현치라 같은 표의 두 값을 나란히 읽을 수 없다 | 사람이 rolling 출력에 알파 계산에 쓰인 봇 3일 실현치를 별도 필드로 찍게 한다 |
| 가설 | RED_B 인버스 눌림 매수가 하락 중인 인버스를 잡는가 — 오늘 2건 모두 mfe 0.0 으로 진입 후 한 번도 플러스가 없었다 | 60거래일 재생에서 RED_B 일과 GREEN 일의 진입당 기대값과 mfe 0 비율을 분리 비교 |
| 가설 | trend_loss(VWAP−0.3) 청산이 손절선 −0.6 보다 먼저 작동하는데 이 규칙이 기대값을 개선하는가 — 오늘 2건 모두 손절 전 추세이탈로 평균 −0.53% | 60거래일 재생에서 TREND_EXIT 0/1 격자로 기대값과 청산 사유 분포를 비교 |
| 가설 | 노출이 0.2%인 날의 알파 +6.11%p 를 누적 알파에 그대로 합산해도 되는가 | 60거래일 표본에서 일별 알파와 exposure_pct 의 상관을 보고 노출가중 알파와 단순 알파를 대조 |
| 해결 | D11 | 알파 = 벤치 정렬일의 봇 실현 복리 − 벤치 B&H 복리. 8/19 −0.10914 −(−5.24842)= +5.13928(보고 5.1393), 8/18 −0.0022325 −(+1.03004)= −1.03227(보고 −1.0323) |