콘텐츠로 이동

S306 — S305 명백 오답 5건 원인 분석

Date: 2026-05-24 (Sun) Topic: L (시스템 재설계) Predecessor: S305 (retrace 게이트 백테스트 + 13 케이스 검증) PM 지시: "모든 경우 적중은 불가능. 명백 결함의 원인만 파악."


0. 분석 범위

S305 13 케이스 직접 실행 결과 중 명확한 오답 5건을 단일 시점에 다시 돌려서, 현재 시스템이 무엇을 못 봤는지 raw로 식별. 산출물:

  • scripts/backtest/s306_diagnose.py — 5건 verdict + 다중 윈도우 impulse + 최근 climax 후보 dump
  • scripts/backtest/s306_climax_check.py — 최근 40봉의 모든 큰 vol 봉 cp 분포 dump
  • data/backtest/s306/diagnostics.json — raw JSON

1. 5건 시스템 출력 vs 실제

Case 종목 시점 pos60 시스템 verdict 실제 D+60 실제 D+5/10/20
A3 012450 한화에어로 2025-09-30 100% MIXED_BUY_LEAN (buy=3, sell=1) -14.54% -15.7 / -12.0 / -8.8
B1 005930 삼성전자 2022-09-30 5.4% MIXED_SELL_LEAN (buy=1, sell=3) +9.42% +4.3 / +6.4 / +13.0
B3 373220 LGES 2023-11-01 0% MIXED_SELL_LEAN (buy=1, sell=3) 0.00% +15.9 / +19.6 / +18.4
D1 033780 KT&G 2025-03-15 0% (lb252 28.8%) AVOID (buy=0, sell=3) +29.68% +5.9 / +8.1 / +11.2
E1 035720 카카오 2022-10-15 11.3% MIXED_SELL_LEAN (buy=1, sell=2) +18.87% -5.0 / -5.2 / +14.2

공통 패턴: 저점 4건(B1·B3·D1·E1) SELL/AVOID + 신고가 1건(A3) BUY_LEAN.


2. 결함 1 — 신고가 분배(BC) 미검출

정의 위치

scripts/discovery/triggers/vsa_trigger.py:116-119

sc_mask = high_vol_mask & (c.diff() < 0) & (cp > 0.6) & wide_mask
bc_mask = high_vol_mask & (c.diff() > 0) & (cp < 0.4) & wide_mask

A3 한화에어로 신고가에서 발견된 분배 흔적 (현 SC/BC 조건이 놓침)

최근 20봉 vol>=p75 봉 cp 분포: 4개 / cp_mean 0.78 / cp_min 0.47
2025-08-08 vol HIGH      cp=0.17 dc=-5.47%   ← 큰 vol + cp 낮음 + 하락, 그러나 spread WIDE 아님
2025-08-12 vol p75       cp=0.05 dc=-3.30%   ← 분배 흔적이지만 p75 (HIGH 아님)
2025-09-19 vol HIGH      cp=0.47 dc=-0.10%   ← cp<0.5 도 분배 신호인데 0.4 컷

결함

  1. BC 조건이 c.diff()>0 (상승봉) 강제 — 신고가 분배는 보통 큰 vol에 cp가 낮은 봉 형태로 나타나는데, 하락봉이면 SC(매집)로 분류돼 의미 뒤집힘.
  2. cp<0.4 임계가 너무 빡빡 — 0.47 같은 중간값도 분배 흔적이지만 누락.
  3. WIDE spread 강제 — 신고가 권에서는 spread가 압축되면서 분배되는 경우 많음. WIDE 강제는 BC 검출 못함.
  4. 위치 컨텍스트 부재pos60 >= 90%일 때 cp<0.5 vol봉이 모이면 BC 패턴인데, 위치를 보지 않음.

B1·B3·D1 저점에서 발견된 매집 흔적 (현 SC 조건이 놓침)

B1 005930 저점 5.4% — vol>=p75 6개 / cp_mean 0.47 / cp_max 1.00
  2022-08-10 vol p75   cp=0.83 dc=-1.50%   ← cp 높음(매집 흔적)이지만 vol HIGH 아님
  2022-09-27 vol p75   cp=1.00 dc=+0.56%   ← cp 1.0 인데 dc>0이라 BC로 분류돼 미발화
  2022-09-30 vol ULTRA cp=0.72 dc=+0.95%   ← ULTRA vol + cp 높음 + 저점 도달 = SC 전형, dc>0이라 미발화

B3 LGES 저점 0% — vol>=p75 9개 / cp_mean 0.36 / cp_max 0.98
  2023-10-11 vol HIGH WIDE cp=0.86 dc=+7.31%   ← 큰 vol + 강한 반등 + cp 높음 = AR 전형
  2023-10-24 vol p75 WIDE  cp=0.98 dc=+2.75%   ← AR 추가 시도

D1 KT&G 저점 0% — vol>=p75 8개 / cp_mean 0.63 / cp_max 1.00
  2025-02-25 vol p75   cp=1.00 dc=+0.00%
  2025-03-06 vol p75   cp=0.97 dc=+2.37%
  2025-03-13 vol HIGH  cp=0.94 dc=+0.95%   ← climactic close, 저점 도달 직전 매집 흔적

E1 카카오 저점 11% — 결정적 봉
  2022-10-14 vol HIGH WIDE cp=0.96 dc=+8.67%   ← ULTRA에 근접 + cp 0.96 + 강한 양봉 = AR/SC 후 반등 전형

결함 (저점 SC/AR)

  1. SC 조건이 c.diff()<0 (하락봉) 강제 — Selling Climax는 매도 절정 후 close가 회복되는 봉이라 dc>0인 경우가 매우 흔함. Wyckoff Phase A AR(Automatic Rally)도 dc>0.
  2. 저점 위치 컨텍스트 부재pos60 <= 10%이면서 vol봉 cp_mean이 높으면 매집 신호인데, 평균을 보지 않고 봉 하나하나의 dc 부호만 봄.
  3. 연속 봉 쌍 미평가 — 10/13 cp 0.00 (selling climax 후보) → 10/14 cp 0.96 (AR) 같은 2봉 쌍이 진짜 신호인데 단일 봉만 평가.

3. 결함 2 — 단일 윈도우 60봉만 사용 (다중 윈도우 합의 부재)

정의 위치

vsa_trigger.py:160, wyckoff_trigger.py:135, bulkowski_trigger.py:176 — 전부 find_impulse_retracement(ohlcv, lookback=60) 하드코드.

다중 윈도우 raw 결과

Case lb60 impulse lb60 retrace_cur lb120 impulse lb120 retrace_cur lb252 impulse lb252 retrace_cur
A3 한화 42.48% 4.18% PERSIST 70.82% 2.51% PERSIST div/0 -
B1 삼전 17.25% 14.55% PERSIST 24.93% 10.07% PERSIST 35.89% 6.99% PERSIST
B3 LGES 32.95% 1.62% PERSIST 39.44% 1.35% PERSIST 40.30% 1.32% PERSIST
D1 KT&G 19.76% 2.14% PERSIST 25.16% 1.68% PERSIST 51.38% 48.35% RESOLVING_EARLY
E1 카카오 43.89% 19.75% PERSIST 50.83% 17.05% PERSIST 63.89% 13.57% PERSIST

결함

  1. D1 KT&G: lb60/120은 PERSIST이지만 lb252 RESOLVING_EARLY (절반 회수). 더 큰 추세 관점에서는 이미 반등 시작 시점인데 lb60만 보면 "하락 지속"이라고 함. 다중 윈도우 합의 부재로 lb60이 단독 결정.
  2. B1 삼전: lb60 impulse 17.25%, lb252 35.89%. 60봉 안에서는 작은 impulse만 보이지만 252봉으로 보면 35.89% DOWN 후반 = 매도 소진 단계. 그러나 시스템은 lb60만 보고 추가 하락 예상.
  3. B3·E1: 모든 윈도우에서 PERSIST지만, 60일 최저점(pos60 0~11%)이라는 위치 정보가 retrace 게이트에 들어가지 않음. retrace_ratio < 38.2%면 무조건 PERSIST로 강등 (vsa_trigger.py retrace 게이트 로직). 이건 "impulse 시작점에서 어디?"만 보고 "60일 범위 어디?"는 안 봄.
  4. impulse_direction이 raw에서 None 반환_retracement.py의 dict 키는 impulse_dir이지만 진단 스크립트가 impulse_direction 키로 읽음(s306 진단 코드 버그). 단, 시스템 본체는 정상 동작. _retracement.py 본체에 swing_high_date/swing_low_date 필드 자체가 없음 — 5건 raw 모두 None.

4. 결함 3 — retrace 게이트가 절대값 통과만 보고 "이미 충분히 빠짐"을 인식 못 함

정의 위치

vsa_trigger.py / wyckoff_trigger.py retrace 게이트 — retrace_ratio_current < 0.382이면 PERSIST로 강등.

결함

  1. retrace_ratio는 "impulse 대비 회수율" — DOWN impulse 50%에서 cur가 5%만 반등했어도 비율로는 10%라서 PERSIST. 그러나 절대 50% 빠진 종목은 추가 하방 여지가 작음 (KT&G -51% / E1 카카오 -64%).
  2. 위치 정보가 게이트에 들어가지 않음pos60 <= 10%인데 SELL을 그대로 두는 건 비대칭. 신고가에 BUY를 강등하는 게이트는 있어도 저점에 SELL을 강등하는 게이트는 없음.
  3. 5건 중 4건이 저점에서 SELL — 시스템은 "하락 추세 지속"만 보고 "더 빠질 공간이 거의 없음"을 인식 못 함.

5. 3 공통 결함 요약

# 결함 코드 위치 영향 케이스
1 SC/BC 조건이 c.diff() 부호로 분류 (Wyckoff 원전과 불일치) vsa_trigger.py:116-117 B1, B3, E1 (SC), A3 (BC)
2 모든 trigger가 lookback=60 하드코드 — 다중 윈도우 합의 부재 vsa_trigger.py:160, wyckoff_trigger.py:135, bulkowski_trigger.py:176 D1 (lb252만 RESOLVING), B1 (lb252 후반 impulse)
3 retrace 게이트가 비율만 보고 위치(pos60/120)는 무시 vsa/wyckoff retrace 게이트 B1, B3, D1, E1 (저점 SELL)

6. PM에게 제안할 다음 단계 (S307 후보)

이 분석은 원인 파악이지 즉시 패치 결정이 아님. PM 결정 필요:

(a) SC/BC 정의 재작성: Wyckoff 원전(Pruden, Plummer)에서 SC는 "매도 절정 후 close 회복"이므로 dc<0만 보지 말고 연속 2봉 쌍(전봉 dc<<0 cp 낮음 → 당봉 cp 0.7+ 큰 vol)을 SC로 검출. (b) 다중 윈도우 합의 도입: 60/120/252 동시 평가, 합의 카운트로 confidence 조정 (AMT trigger의 short/mid/long 패턴 이식). (c) 위치 컨텍스트 게이트: pos60 <= 15% && retrace 게이트 SELL → 강등(CAUTION으로) / pos60 >= 85% && BUY → 강등.

또는 PM 판단: "결함 3종은 인정하지만 즉시 수정은 과적합 위험" → 결함을 문서화하고 다음 백테스트 사이클에서 함께 본다.


7. 산출물

  • scripts/backtest/s306_diagnose.py — 5건 단일 시점 trigger raw + 다중 윈도우 impulse + climax 후보
  • scripts/backtest/s306_climax_check.py — 최근 40봉 큰 vol 봉 cp 분포 dump
  • data/backtest/s306/diagnostics.json — 5건 raw JSON

8. 이월

S305 미해결 항목 유지: - 다음 정규 EVENING 실행 시 §2.5 슬림화 실동작 확인 (S297) - survivorship bias 보정