콘텐츠로 이동

S307 — 4 trigger 원전 정합성 점검 + OF 30분봉 정책 + cp 동적 임계

Date: 2026-05-24 (Sun) Topic: L (시스템 재설계) Predecessor: S306 (5건 오답 원인 분석 + 결함 3종 식별) PM 정책: - OF는 30분봉/900봉 기준 (일봉 fallback 폐기) - 원전에 있는 내용만 제대로 구현 - 룰베이스에서 최적해 불가능. 동적화 가능한 임계만 동적, 나머지는 관행 유지


1. OF 30분봉 정책 적용 (PM 1번 지시)

인프라

  • scripts/discovery/fetch_minute_30.py 신규 — 키움 ka10080 tic_scope=30 fetch + 표준 OHLCV 변환 + parquet 캐시
  • 005930 검증: 900봉(2026-02-13 14:00 ~ 2026-05-22 15:30, 약 69거래일) 저장 → data/minute_charts/30min/005930.parquet

키움 ka10080 응답 파싱

  • 차트 키: stk_min_pole_chart_qry
  • 필드 매핑: cntr_tm → Datetime, open_pric/high_pric/low_pric/cur_prc → OHLC(부호 제거), trde_qty → Volume
  • 시간 역순 응답 → 정순 정렬 + 0가격 봉 제거

코드 변경

  • scripts/discovery/order_flow.py — 컬럼명 *_5d/_20d/_10d*_5bar/_20bar/_10bar (30분봉 가정 명시). docstring에 입력 = 30분봉 OHLCV 명시
  • scripts/discovery/triggers/of_trigger.py재작성. 일봉 fallback 분기 전체 삭제. intraday_available 인자 제거. 30분봉 단일 모드.
  • scripts/discovery/triggers/aggregator.pyintraday_availableof_30m: Optional[dict] 교체. of_30m=None이면 OF trigger 자체를 호출하지 않음 (4 trigger로 verdict 산출). strong_threshold = max(3, n_total - 1)이라 자동 조정.
  • caller 6곳 갱신: s303/s305/s306 백테스트, s303_smoke, _tmp_test_state4, _tmp_test_phase_triggers.

005930 30분봉 OF 결과 (검증)

bvc_buy_ratio_5bar: 0.487 / 20bar: 0.494  (둘 다 0.5 이하 = 매도 우위)
cvd_zscore: -0.838  (CVD 20봉 평균 이하 = 매도 누적)
divergence: 0 / absorption: 0 / exhaustion: 0
upper_wick 0.27 > lower_wick 0.14 (분배 흔적 가능)
decision: HOLD (활성 신호 없음)

5건 verdict 영향 (S306 일봉 기준)

  • 일봉 백테스트는 30분봉 캐시 없음 → OF 자동 제외
  • D1 KT&G만 AVOID → AVOID_STRONG 한 칸 강해짐 (strong_threshold 4→3, sell_votes 3 충족)
  • 나머지 4건 동일

2. VSA cp 동적 임계 (PM 2번 지시, 종목별 52주 rolling)

발견 (정정)

  • vsa_trigger.py:120-121cp > 0.6 / cp < 0.4S302 결정 항목 아님. 출처 불명 임의 값.
  • vsa_trigger.py:120-121의 SC/BC mask에 wide_mask 강제 추가 — 원전 Williams SC/BC 정의에 wide 명시 없음. 임의 가드.
  • vsa_signals.py는 원전 디폴트(close_top=0.7 / close_bottom=0.3) 유지. trigger와 임계 불일치.

S307 동적화 (PM 결정)

  • scripts/discovery/triggers/_thresholds.py 신규 함수: compute_cp_climax_thresholds
  • 윈도우: 252봉(52주, PM 결정 "52주 신고가 기준에 맞춰서")
  • 측정 대상: vol_climax(Q90) 봉의 cp 분포 (vsa_trigger.py SC/BC mask가 high_vol_mask=Q90을 사용하므로 측정 대상 일치)
  • cp_climax_top = 그 분포의 70th percentile (원전 0.7 "상위 30%" 의미 유지)
  • cp_climax_bottom = 그 분포의 30th percentile
  • fallback (표본 < 10): Williams 원전 0.7 / 0.3
  • compute_all_thresholds에 cp_climax_top/bottom + alias(close_top/close_bottom, vsa_signals.py 호환) 추가
  • vsa_trigger.py SC/BC mask: wide_mask 강제 제거 + 동적 cp 임계 적용
  • supply_test / no_demand_bars도 동적 cp 적용 (line 132-133)

6건 동적 임계 결과 (sample_n=26)

종목 cp_climax_top (원전 0.7) cp_climax_bottom (원전 0.3) 해석
005930 (latest) 0.773 0.165 큰 vol 봉이 양극단
012450 한화에어로 9/30 0.841 0.480 신고가 추세 — bottom 0.480, 원전 0.3보다 높음. cp<0.480이면 BC 검출 (분배 흔적 더 잘 잡힘)
005930 2022-09-30 0.611 0.261 양극단 살짝 약함
373220 LGES 11/01 0.795 0.231 양극단 명확
033780 KT&G 3/15 0.786 0.232 양극단
035720 카카오 10/15 0.835 0.142 매우 강한 양극단 (panic↔강한 반등 둘 다)

5건 verdict 영향

  • VSA 단독 decision은 모두 동일 (SC/BC count 변화는 있으나 판정부 pchg 조건 등이 우선)
  • 5건 전체 verdict 동일

3. 4 trigger 원전 정합성 점검 결과

A. 원전 정합 (변경 불필요)

trigger 항목 출처
VSA 8 신호 정의(ND/NS/SV/CV/BC/SC/EUR/EDR) Tom Williams, Master the Markets
VSA 윈도우 분리 (baseline 30 / climax 20 / nd_ns 3 / trend 20) Williams + Better Volume + S301
Wyckoff TR 125봉 / EVENT 3봉 / SWING 5 / TREND 20 Pruden + StockCharts S301
Wyckoff Spring/UT 침범 1% Robert Evans (wyckoffsmi.com) S302
Wyckoff SOS/SOW/LPS/LPSY 검출 정의 Pruden 원전 정합
AMT 윈도우 20/60/120 multi-window Steidlmayer composite + Aspen S301
AMT Value Area 0.70 Steidlmayer 1σ=68.27%
AMT POC stable band = ATR 25th percentile S302 PM 결정
Bulkowski RECTANGLE 65 / FLAG 15 / PENNANT 20 / THROWBACK 30 thepatternsite.com
Bulkowski vol_confirm = 종목별 70th percentile S302 PM 결정
Bulkowski Breakout = 패턴 상/하단 close 돌파 + trendline ≥2회 터치 원전 정합
OF BVC (Easley/LdP/O'Hara 2012) / CVD divergence (Bookmap) 30분봉 모드 (PM 결정)

B. 관행 (외부 차티스트 표준, PM 인정)

trigger 항목 평가
Wyckoff vol_mult > 1.2 (SOS/SOW 거래량 동반) 원전 미명시지만 차티스트 관행
Wyckoff breakout_tol = 1.5% 원전 0.5~2% 범위 중간값
Wyckoff ma_window = 20봉 관행 (Better Volume)
Wyckoff climax_vol_mult = 2.0 (SC/BC) 원전 "2~3배" 권고 최소값
Bulkowski top_touches/bot_touches ≥2 원전 정합

C. 동적화 적용 (S307)

trigger 항목 변경
VSA SC/BC cp 임계 252봉 종목별 동적 (Q70/Q30)
AMT POC 정체 임계 poc_mig < 0.15 S302 poc_stable_band (ATR 25th) 동적 적용 (S307 추가)

D. 원전 근거 없는 임의 가드 (유지 + 기록, PM 결정)

PM 원칙: "기준이 딱 맞추는 것은 어렵고 관행적으로 사용하는 것을 활용해도 문제가 될 것 같지 않다. 룰베이스에서 최적해는 불가능."

trigger 위치 임계 의미
Wyckoff wyckoff_trigger.py:235, 239 last_age <= 5 SOS/SOW 발생 후 5봉 이내만 BREAKING
Wyckoff wyckoff_trigger.py:253 cause_bars >= 3 P&F cause (원전은 box count, 코드는 봉 수)
Wyckoff wyckoff_trigger.py:302 up_score + down_score >= 4 → conf +0.05 swing 시퀀스 강도 보너스
AMT amt_trigger.py:95, 98 poc_mig > 0.3 / < -0.3 POC 이동 강 임계
AMT amt_trigger.py:112-114 vah_dist_atr / val_dist_atr / nearest_lvn_atr < 0.5 VAH/VAL/LVN 근접 ATR 0.5
AMT amt_trigger.py:116, 119, 122 rotation ≥4 / ≤-4 / abs<4 rotation factor 강/약 임계
Bulkowski bulkowski_trigger.py:77-78 0.99 / 1.01 "터치" 1% 허용폭
Bulkowski bulkowski_trigger.py:88 slope < range × 0.001 "수평" 0.1% 임계
Bulkowski bulkowski_trigger.py:105 slope_diff < 0.3 flag 두 trendline 평행 30%
Bulkowski bulkowski_trigger.py:211 box_h > 15 (추세 판정) 15% 임의
Bulkowski bulkowski_trigger.py:37-38 RECTANGLE_HEIGHT_MAX=0.20, FLAG_HEIGHT_MAX=0.10 패턴 height 통계 기반

유지. 동적화 작업 시도 시 임계 자체가 다른 의미인 경우가 많아 단순 percentile 매핑 부적합. PM 원칙 "최적해 불가, 관행으로 충분".


4. 5건 verdict 변화 (S306 → S307)

Case S306 S307 변화 원인
A3 한화에어로 MIXED_BUY_LEAN MIXED_BUY_LEAN 동일
B1 삼전 MIXED_SELL_LEAN MIXED_SELL_LEAN 동일
B3 LGES MIXED_SELL_LEAN MIXED_SELL_LEAN 동일
D1 KT&G AVOID AVOID_STRONG OF 제외로 strong_threshold 4→3 충족
E1 카카오 MIXED_SELL_LEAN MIXED_SELL_LEAN 동일

명백 오답 5건의 verdict는 4/5 동일. D1만 한 칸 강해짐(SELL 방향 그대로 강도 ↑). 5건 명백 오답 자체는 여전히 해결 안 됨 — 시스템 한계로 인정. S306 결함 분석 그대로 유효.


5. 시스템 상태 요약

변경된 파일

  • scripts/discovery/fetch_minute_30.py (신규)
  • scripts/discovery/order_flow.py (컬럼명 30분봉 명시)
  • scripts/discovery/triggers/of_trigger.py (재작성, 일봉 fallback 폐기)
  • scripts/discovery/triggers/aggregator.py (intraday_available → of_30m)
  • scripts/discovery/triggers/_thresholds.py (cp 동적 임계 함수 추가)
  • scripts/discovery/triggers/vsa_trigger.py (SC/BC mask 동적 cp + wide_mask 제거)
  • scripts/discovery/triggers/amt_trigger.py (poc_stable_band 적용 확장)
  • caller 6곳 (intraday_available 인자 제거)
  • data/minute_charts/30min/005930.parquet (30분봉 캐시 1종)

미해결 (이월)

  • 다른 종목 30분봉 캐시 (S307 시점 005930만 검증)
  • 5건 명백 오답 자체는 시스템 한계로 인정. PM이 만능 차트 분석기 만들지 말라고 명시
  • vsa_signals.py와 vsa_trigger.py 임계 체계 불일치 (vol/spread multiplier vs percentile). 일관 정렬은 별도 작업
  • 카테고리 D 임의 가드 12+건은 유지 (PM 원칙 "관행으로 충분")

6. PM 핵심 교정 (S307)

  1. "OF는 30분봉/900봉" — PM 정책 확정. 일봉 fallback 작업이 무의미했음 확인 후 폐기.
  2. "원전에 있는 내용만 제대로 구현" — 임의 추가(2봉 쌍, AR/UR, vote 매트릭스, mw_override) 다 폐기.
  3. "임계는 한국 시장에 맞춰서 — 종목별 rolling" — cp 동적 임계 추가 (252봉 rolling).
  4. "관행으로 충분, 룰베이스에서 최적해 불가" — vol_mult 1.2 / breakout_tol 1.5% / ma_window 20 / climax_vol_mult 2.0 등 유지.
  5. "도식적 위치=감정 매핑 금지" — 본질 매트릭스(불균형/균형 × 가속/해소 × 방향) 외 가드 거부.
  6. "만능 차트 분석기 X" — 시장상황 + 재료가 더해져야 차트도 의미 있음. 5건 명백 오답을 차트 트리거로 해결하려던 방향 자체 폐기.