S326 — /discover 원자화 설계서 (v6 6도구 → atomic agent 분해)¶
작성: 2026-05-26 (Tue) 23:35 KST
선행: topic_discovery_walkforward.md Phase E v6 채택
목표: v6 6도구 결합 모델을 production-grade /discover ad-hoc 커맨드로 운영화. 에이전트 원자화 + 데이터 도구 연결 + 하네스 엔지니어링. 이후 기존 /rs_* 커맨드에서 테마/종목 발굴 부분 제거.
0. 원칙 (v2 갱신 — 2026-05-26 23:43)¶
PM 교정: - 입력 데이터 고정 ❌ → 도구 카탈로그 제공 ✅ (에이전트가 도구 선택) - 산식 박제 ❌ → 단일 질문 + 가이드 + 해석 위임 ✅ - 도구 제약 거의 없음 (단, 표준 도구·표준 데이터는 정형화하여 권장)
하이브리드 분담:
| 영역 | 담당 | 이유 |
|---|---|---|
| 수치 산출 (RS, cvd_z, accel_ratio, EA_z, theme_rank...) | 코드 (deterministic) | 백테스트 재현성 + 결정론 |
| 데이터 적재 | 에이전트가 직접 (Read/Bash/MCP) | 유연성 |
| 임계 판정 / 신호 해석 / 결손 대응 | 에이전트 (interpretive) | LLM 강점 활용 |
| 최종 단일 답변 | 에이전트 (verdict + evidence + confidence) | 근거 인용 의무 |
v2 원칙: 1. 1 atomic agent = 1 단일 질문. 합성 판단 금지. 2. 질문은 의미 단위. "L1_gate_ON 컬럼이 True인가?"가 아니라 "오늘 매크로 환경이 매수 진입에 우호적인가?" 3. 도구 제약 거의 없음 — Read, Bash(run_py.ps1), 서브에이전트 호출, WebSearch, MCP 자유 사용. 4. 표준 도구·표준 데이터·판단 가이드 = 정형 제공. 에이전트 정의서가 이걸 명시. 5. 수치 산출 = 코드 위임 의무. 에이전트가 RS를 직접 계산하지 않음. 코드 실행 후 결과를 인용. 6. 출력 = 표준 JSON 스키마 (verdict + evidence + 수치 인용). 다음 agent 입력으로 직결. 7. 각 atomic은 단독 실행 가능 (idempotent). T0 인자만 받음. 8. 하네스 = 게이팅 체인. 앞 게이트가 PASS면 뒷 게이트 skip → 비용 절감.
1. v6 운영 룰 (인용 — sim_v6_6tools.py:8-12)¶
L1 ON + L2 confirmed + stock_RS>0 + theme_RS>0 + leader + rs_vs_theme>=0 + (v6: OF 매수 강세)
score = z(rs_vs_theme) + z(stock_rs) + z(accel) + z(ofm_cvd_z) ← v6
final select: 일별 final_score rank 1
D+20 hold (EXIT 룰 없음)
L2 = transition_to_imb_up_confirmed OR imb_up_acceleration_confirmed (sim_v6:154-157)
Leader = rs_rank ≤ max(3, n//3) (sim_v6:178)
OF 매수 강세 = ofm_cvd_z > 0 AND ofm_bvc_5bar >= 0.55 (sim_v6:193-195)
2. Atomic 분해 (8개) — 의미 질문 중심¶
각 에이전트는 단일 의미 질문에만 답한다. 산식·임계는 가이드일 뿐 박제하지 않는다. 수치는 코드로 산출 후 인용한다.
| ID | Agent | 의미 질문 (해석 위임) |
|---|---|---|
| D1 | discover/macro-judge |
"오늘 매크로 환경이 매수 진입에 우호적인가? 유동성·심리·금리·파생 신호 종합." |
| D2 | discover/chart-judge |
"이 종목 차트가 매수 진입 가치 있는가? 불균형 구조·가속·국면 종합." |
| D3 | discover/relative-strength-judge |
"이 종목이 시장(KOSPI)보다 강한가? 60일 RS + 추세 일관성." |
| D4 | discover/theme-leadership-judge |
"이 종목이 속한 테마가 강한가 + 그 안에서 leader인가?" |
| D5 | discover/orderflow-judge |
"최근 30분봉에서 매수 흐름이 우세한가? CVD/BVC/흡수 종합." |
| D6 | discover/earnings-quality-judge |
"이 종목의 실적 가속(EA)이 점수 가중을 얼마로 받을 가치 있는가?" |
| D7 | discover/portfolio-selector |
"T0 통과 후보들 중 오늘 진입할 1종은 무엇인가? + 사유." |
| D8 | discover/position-monitor |
"보유 종목들의 D+20 hold 동안 상태는 정상인가? HOLD/EXIT/WARN." |
2.1 에이전트 vs 코드 분담 (각 atomic 내부)¶
| atomic | 코드 (deterministic) | 에이전트 (interpretive) |
|---|---|---|
| D1 | scripts/discover/macro_indicators.py → 39열 panel + S317 ★ 신호 발화 표 + S308 regime cell |
위 3 자료 읽고 "우호 Y/N + 근거 + confidence" |
| D2 | scripts/discover/chart_indicators.py → L2 시나리오 enum + accel_ratio + S317 60 룰 발화표 |
"매수 가치 Y/N + 어느 신호 우세인지" |
| D3 | scripts/discover/stock_rs.py → stock_rs, stk_ret60, MA 기울기 |
"RS > 0 충족인가 + 추세 일관성 해석" |
| D4 | scripts/discover/theme_rs.py → primary_theme, theme_rs, theme_rank, rs_vs_theme |
"leader 자격 + 테마 강도 해석" |
| D5 | scripts/discover/of_indicators.py → ofm_cvd_z, ofm_bvc_5bar, lower_wick 비율 |
"매수 흐름 우세 Y/N + 신호 견고성" |
| D6 | scripts/discover/ea_indicators.py → ea_z, ea_yoy, sue |
"weight 0.5/0.8/1.0 결정 + 실적 추세 코멘트" |
| D7 | scripts/discover/score_compose.py → final_score, rank 후보표 |
"rank1 채택 OR 차상위 추천 OR PASS" |
| D8 | scripts/discover/position_status.py → days_held, current_alpha, drawdown |
"HOLD/EXIT/WARN + 사유" |
Claude main session 역할: 하네스. D1 verdict=NEGATIVE면 PASS 종료. POSITIVE면 universe 루프 시작.
3. 각 Atomic — Input Package + 도구 카탈로그 + 판단 가이드 + 출력 스키마¶
핵심 원칙 (v3 보강 — 2026-05-27 00:04): 에이전트가 데이터를 사냥하지 않는다. 하네스(main session)가 호출 전에 Input Package를 사전 조립해 에이전트에 전달한다. 에이전트는 패키지를 받은 상태에서 종합 판정만.
- Input Package = 블록 단위 (의미 단위) 구조화 JSON/YAML
- 모든 패키지는 Pydantic 모델로 검증 (
scripts/discover/schemas.py) - 검증 실패 시 즉시 stop (s236 gatekeeper 계보 계승)
- 에이전트는 추가 도구 사용권 유지 — 패키지가 부족하면 도구로 보강 가능, 단 결정론적 판정은 패키지 인용만으로 가능해야 함
각 절은 에이전트 정의서(.claude/agents/discover/*.md)에 그대로 들어간다.
3.1 D1 — macro-judge¶
의미 질문: "오늘 매크로 환경이 매수 진입에 우호적인가?"
Input Package 빌더: scripts/discover/build_d1_input.py --date T0 → Pydantic D1Input 검증 후 JSON 반환
Input Package 구조 (D1Input):
package_id: D1_input_{date}
date: 2026-05-27
blocks:
liquidity: # 유동성 (Druckenmiller 본질)
fed_net_liquidity_usd_b: 5931.2
delta_20d_b: +230
z_60d: +1.35
walcl_lev: HIGH # enum: LOW/MID/HIGH
walcl_chg_z: +0.82
rrp_chg_z: -1.10
deposit_lev: HIGH # 한국 고객예탁금 (Phase A7)
deposit_chg_z: +0.45
spy_lev / gspc_lev / sox_lev: HIGH/HIGH/MID
evidence_grade: "★★"
sentiment: # 심리 (Howard Marks pendulum)
vix: 14.2
vix_chg_z: -0.32
vix_term_regime: STRONG_CONTANGO
vkospi_fut_oi_chg_z: +1.42 # S317 ★★ bull D+20 1.000
pcr_vol_z: +0.91 # S317 ★★ bull 0.893
cnn_fng: {value: 58.6, label: GREED, delta_1w: -4.6}
aaii / naaim: {available: false} # paywall
evidence_grade: "★★"
rates: # 금리
kr_10y_chg_z: -0.18
us_2y: 4.32 / us_10y: 4.18
curve_2_10: -0.14
real_yield_10y: 1.45
hy_oas: 312 # FRED BAMLH0A0HYM2
hy_regime: EUPHORIA
evidence_grade: "★"
derivatives: # 파생 (KRX 4년 백필, Phase A2)
basis_z: +0.85 # S317 ★★ bull 0.842
fut_oi_chg_z: +1.21 # S317 ★★ bull 0.909
kr_10y_fut_chg_z / kr_10y_fut_volume_chg_z: +0.45 / +0.62
usd_fut_oi_chg_z: -0.42 # 약한 회피
kospi200_fut_chg_z: +0.78
max_pain_dist_z: +0.32
evidence_grade: "★★"
context: # 메타
s308_regime_cell: L_UP_S_UP_BULL
s317_active_signals:
bull: [_NEW_vkospi_fut_oi_chg_z_HIGH, fut_oi_chg_z_HIGH, basis_z_HIGH]
bear: []
today_events: # WebSearch 또는 EVENT_CALENDAR 인용
- {time: "2026-05-27 03:00 KST", event: "FOMC minutes"}
is_option_expiry: false
yesterday_d1_verdict: POSITIVE
data_quality:
missing_columns: []
stale_data: [] # 24h 이상 미갱신 컬럼
schema_version: 1
도구 카탈로그 (선택, 패키지 보강 시):
1. (1차) Input Package — 이미 전달됨, 재호출 없음
2. Read data/macro/panel_4y_daily.parquet — 패키지 외 컬럼 필요 시
3. Read docs/research/2026-05-26_S317_module_audit_v2.md — 검증표 원본 인용 필요 시
4. Agent macro-economist — 모순 신호 발화 시 도메인 의견
5. WebSearch — 패키지 today_events에 없는 긴급 이벤트 의심 시
6. (자유) DART/KRX MCP, fetch_* 스크립트 등 제약 없음
판단 가이드:
- 4 블록 evidence_grade 종합:
- ★★ 다수(3+) + bear 신호 0 → POSITIVE HIGH
- ★★ 2 + bear 신호 1 → POSITIVE MED
- ★ 위주 + bear 1+ → NEUTRAL/NEGATIVE
- bear 신호 ★★ 1+ → NEGATIVE HIGH (회피)
- ★★ bear 신호 목록 (S317 v2 검증):
_NEW_vkospi_fut_oi_chg_z LOW(D+20 0.067),fut_oi_chg_z LOW(0.120),kr_10y_chg_z LOW(0.174),_NEW_kospi200_fut_chg_z LOW(0.158) - S308 regime cell 우선:
L_UP_S_UP_BULL/L_UP_S_DOWN_Contrarian진입 우호 /L_DOWN_S_UP_TopWarning회피 data_quality.missing_columns가 3개 이상이면 자동 confidence LOW
출력 스키마 (D1Output Pydantic):
{
"atomic": "D1_macro_judge",
"package_id_in": "D1_input_2026-05-27",
"date": "2026-05-27",
"verdict": "POSITIVE",
"confidence": "HIGH",
"regime": "L_UP_S_UP_BULL",
"block_grades": {"liquidity": "★★", "sentiment": "★★", "rates": "★", "derivatives": "★★"},
"signals_supporting": [
{"name": "_NEW_vkospi_fut_oi_chg_z", "direction": "HIGH", "value": 1.42, "rule_d20": 1.000, "grade": "★★"}
],
"signals_opposing": [],
"reasoning": "유동성 ★★(WALCL/SPY/SOX lev_HIGH 3/3), 심리 ★★(vkospi_fut_oi_z 1.42 bull D+20 1.000 검증), 파생 ★★(basis_z+fut_oi_z 동반 bull)...",
"tools_used": ["D1Input package", "macro-economist (consulted on rates ambiguity)"]
}
3.2 D2 — chart-judge¶
의미 질문: "이 종목 차트가 매수 진입 가치 있는가?"
Input Package 빌더: scripts/discover/build_d2_input.py --date T0 --code C → D2Input
Input Package 블록 구조 (D2Input):
blocks:
trend: # C1 가격 궤적
ma_20/60/120_slope_z: [...]
drawdown_60d: -0.08
high_proximity_52w: 0.92
range_pos_52w: 0.87
structure: # C3/C4 스윙 + 구조 전환
swing_pattern: HH_HL # enum
l2_scenario: transition_to_imb_up_confirmed
accel_ratio: 1.34
structure_break_stage: NONE
volume_profile: # 1-4 VP
poc_dist_atr: +0.42
va_position: above_vah
up_down_amount_ratio_log: +0.45 # ★★ S317 bull 우호
volume_asymmetry_20d: +0.18
overhang_below_pct: 0.62
vsa: # 1-2 VSA
last_signal: {id: SOS, strength: 2, age: 3}
spring_count_20d: 1 # ★★ bull D+20 0.707
bullish_strength_sum: 4
bearish_strength_sum: 1
orderflow_daily: # 1-5 OF daily
cvd_z: +1.2
bvc_5bar: 0.62
absorption_score_last: +1.8 # ★★ bull D+20 0.846
candles: # 1-7
last_10: [{type: hammer, body_ratio: 0.3, ...}]
lower_upper_wick_ratio: 0.65
s317_signals_active: # 발화 룰 자동 집계
bull: [absorption_score_last_high, spring_count_pos, in_lvn]
bear: []
data_quality: {...}
schema_version: 1
도구 카탈로그 (선택): 위 블록 외에 Agent chartist (C10 종합) / Agent trader/imbalance-map,structure,origin,dynamics (불균형 4 Layer) 자유 호출.
판단 가이드:
- ★★ 진입 시나리오 (v6 검증): transition_to_imb_up_confirmed OR imb_up_acceleration_confirmed
- ★★ 강 bull 신호: absorption_score_last >+1.5 (D+20 0.846), in_lvn (0.818), spring_count_20d>0 (0.707), retracement RESOLVING_EARLY (0.665)
- ★★ 회피 신호: vp_up_down_amount_ratio_log <-0.3 (D+20 0.062 = 94% 하락), vp_volume_asymmetry_20d <-0.3 (0.160), ofm_bvc_5bar <0.45 (0.152), close_pos <0.3 (0.247)
- 역방향 주의 (운영 가치 낮음): err_zscore >+1 (Effort no Result), AMT strong bull
- 신호 1개 강하지만 나머지 모호 → confidence LOW
출력 스키마:
{
"atomic": "D2_chart_judge",
"date": "...", "code": "069540",
"verdict": "POSITIVE | NEGATIVE | NEUTRAL",
"confidence": "HIGH | MED | LOW",
"l2_scenario": "transition_to_imb_up_confirmed",
"accel_ratio": 1.34,
"bull_signals": [{"name": "absorption_score_last", "value": 1.8, "rule_d20": 0.846}],
"bear_signals": [],
"reasoning": "...",
"tools_used": [...]
}
3.3 D3 — relative-strength-judge¶
의미 질문: "이 종목이 시장(KOSPI)보다 강한가?"
Input Package 빌더: scripts/discover/build_d3_input.py --date T0 --code C → D3Input
Input Package 블록 구조:
blocks:
rs_metrics: {stock_rs_60d, stk_ret_60d, kospi_ret_60d, rs_z_cs} # cross-sectional z
rs_trend: {rs_5d, rs_20d, rs_60d, monotonic_up_pct, recent_20d_drawdown}
consistency: {days_above_kospi_60d, max_consec_below, ma200_above}
data_quality: {...}
도구 카탈로그 (선택): raw OHLCV 직접 read 자유.
판단 가이드:
- ★ 베이스라인: stock_rs > 0 (sim_v6 룰 3)
- 추가 점검: 60일 단조 상승 vs 변동 큰 RS / 최근 20일 RS 가속 / MA 200 위
- RS>0이지만 직전 20일 급락이면 confidence LOW
- 데이터 부족 (60일 미만) → UNKNOWN
출력 스키마:
{
"atomic": "D3_rs_judge",
"code": "069540",
"verdict": "POSITIVE | NEGATIVE",
"confidence": "HIGH | MED | LOW",
"stock_rs": 0.082,
"stk_ret60": 0.171,
"rs_trend": "consistent | volatile | recent_weak",
"reasoning": "..."
}
3.4 D4 — theme-leadership-judge¶
의미 질문: "이 종목이 속한 테마가 강한가 + 그 안에서 leader인가?"
Input Package 빌더: scripts/discover/build_d4_input.py --date T0 --code C → D4Input
Input Package 블록 구조:
blocks:
theme_mapping: # ats_main_v2.json 인용
primary_theme: "광통신"
all_themes: ["광통신", "5G"]
theme_rs: # 멤버 상위 30 평균
theme_rs_60d: +0.054
theme_n: 18
theme_rank_in_market: 7 # 전체 테마 중 순위
leadership: # 테마 내 leader 판정
theme_rank: 2 # 종목의 테마 내 RS rank
rs_vs_theme: +0.028
is_leader: true # rank ≤ max(3, n//3)
top3_members: [...]
lifecycle: # sector/lifecycle-tagger 산출
stage: expansion # 5단계 enum
days_in_stage: 12
freshness: 0.7
data_quality: {...}
도구 카탈로그 (선택): Agent sector/leader-judge (5대 기준 교차) / Agent sector/lifecycle-tagger (생명주기 보강) / Agent sector/overheat-detector (과열 점검).
판단 가이드:
- ★★ 베이스라인 (v6 검증): theme_rs > 0 AND rank ≤ max(3, n//3) AND rs_vs_theme ≥ 0
- 테마 멤버 < 3 → 통계 불충분, UNKNOWN
- 종목이 여러 테마 소속 시 primary는 매핑상 첫 번째 — 단, 더 강한 테마가 있다면 명시
- 생명주기 = 소멸 단계면 confidence LOW (테마 RS 양수여도)
출력 스키마:
{
"atomic": "D4_theme_leader_judge",
"code": "069540",
"verdict": "POSITIVE | NEGATIVE | UNKNOWN",
"confidence": "HIGH | MED | LOW",
"primary_theme": "광통신",
"theme_rs": 0.054,
"theme_n": 18,
"theme_rank": 2,
"rs_vs_theme": 0.028,
"is_leader": true,
"lifecycle_stage": "expansion",
"reasoning": "..."
}
3.5 D5 — orderflow-judge¶
의미 질문: "최근 30분봉에서 매수 흐름이 우세한가?"
Input Package 빌더: scripts/discover/build_d5_input.py --date T0 --code C → D5Input
Input Package 블록 구조:
blocks:
availability:
has_30min: true
bars_count: 240
last_bar: "2026-05-26 15:30"
cvd: # 누적 매수강도
cvd_last: 1.42M
cvd_z_40bar: +1.45 # S317 ★★ bull 우호 임계
cvd_slope_z: +0.85
cvd_price_divergence: null # -1/0/+1
bvc: # Buy Volume Concentration
bvc_5bar: 0.60 # S317 ★★ baseline 0.55
bvc_20bar: 0.58
pressure:
buy_pres_sell_pres_diff: +0.35 # S317 ★★ bull > 0.3
lower_upper_wick_ratio: 0.65 # S317 ★★ bull > 1
absorption:
absorption_score_last: 0 # 30분봉은 결손 빈도 높음
absorption_count_20bar: 0
exhaustion_flag: null
s317_signals_active:
bull: [bvc_5bar_high, buy_pres_diff_high]
bear: []
data_quality:
missing_bars_pct: 0.02
가용X 시: blocks.availability.has_30min = false. Pydantic 검증 통과. D5 verdict=UNAVAILABLE 반환.
도구 카탈로그 (선택): raw 30분봉 read / Agent trader/imbalance-dynamics (VSA evr_residual + delta 시계열).
판단 가이드:
- ★★ 베이스라인 (v6 검증): ofm_cvd_z > 0 AND ofm_bvc_5bar ≥ 0.55
- ★★ S317 v2 강신호: OF 30분 lower_wick > upper_wick (D+20 0.644), OF 30분 buy_pres - sell_pres > 0.3 (0.615)
- ★★ 강 회피: ofm_bvc_5bar <0.45 (D+20 0.152), ofm_cvd_z <-1 (0.250)
- 30분봉 미가용 → verdict UNAVAILABLE (skip 아님 — score_compose에서 weight 처리)
- bvc_5만 통과 / cvd_z만 통과 → MED confidence
출력 스키마:
{
"atomic": "D5_of_judge",
"code": "069540",
"verdict": "POSITIVE | NEGATIVE | UNAVAILABLE",
"confidence": "HIGH | MED | LOW",
"ofm_cvd_z": 1.45,
"ofm_bvc_5bar": 0.60,
"ofm_bvc_20bar": 0.58,
"lower_wick_ratio": 0.62,
"reasoning": "..."
}
3.6 D6 — earnings-quality-judge¶
의미 질문: "이 종목의 실적 가속이 점수 가중을 얼마로 받을 가치 있는가?"
Input Package 빌더: scripts/discover/build_d6_input.py --date T0 --code C → D6Input
Input Package 블록 구조:
blocks:
ea_metrics:
ea_yoy_latest: +0.42
ea_z_cs: +0.95 # T0 cross-section z
sue: +1.4 # Foster-Olsen 한국변형
ea_qoq: +0.18 # FA-M4
vintage:
latest_quarter: "2026Q1"
report_date: "2026-04-15"
days_since_report: 42 # PEAD 60거래일 추적 범위 내
is_in_pead_window: true
history:
ea_yoy_5q: [+0.10, +0.15, +0.22, +0.31, +0.42] # 가속 추세
monotonic_up: true
guidance: # FA-M5 (있으면)
last_guidance_signal: BEAT_RAISED
quality: # FA-M1 quality grade
quality_grade: B
data_quality:
missing_data: false
is_fallback_dart: false # FnGuide 5Q 한계 시 true
도구 카탈로그 (선택): mcp__korea-stock-mcp__get_financial_statement (최신 분기 보강) / Agent fundamentals/pead-tracker / Agent fundamentals/guidance-priority.
판단 가이드:
- 베이스라인 (sim_v6): ea_z > 0 → weight 1.0, ea_z < -0.5 → 0.5, 결손 → 0.8
- ea_z 결정 시 cross-sectional 분포 확인 (T0 전체 종목 대비). 단일 z는 시점 의존
- 최근 분기 실적 발표 안 됨 (lag 50d 미만) → weight 0.8 (보수)
- PEAD 추적 중이면 weight 상향 검토
출력 스키마:
{
"atomic": "D6_ea_judge",
"code": "069540",
"verdict": "POSITIVE | NEGATIVE | NEUTRAL",
"ea_z": 0.95,
"ea_yoy": 0.42,
"weight": 1.0,
"rationale": "ea_z > 0, PEAD active",
"missing_data": false
}
3.7 D7 — portfolio-selector¶
의미 질문: "T0 통과 후보들 중 오늘 진입할 1종은 무엇인가?"
Input Package 빌더: scripts/discover/build_d7_input.py --date T0 → D7Input (D1~D6 verdict 통합 + score_compose 결과)
Input Package 블록 구조:
blocks:
d1_macro: {verdict: POSITIVE, confidence: HIGH, regime: L_UP_S_UP_BULL}
candidates: # D2~D6 모두 POS 통과 종목들
- code: "069540"
verdict_chain: {D2: POS, D3: POS, D4: POS, D5: POS, D6: POS}
confidence_chain: {D2: HIGH, D3: HIGH, D4: HIGH, D5: HIGH, D6: HIGH}
raw_metrics: # 코드 산출 인용
stock_rs: 0.082
theme_rs: 0.054
rs_vs_theme: 0.028
accel_ratio: 1.34
ofm_cvd_z: 1.45
ea_z: 0.95
ea_weight: 1.0
score_components_z: # score_compose.py 산출
rs_vs_theme_z: 1.20
stock_rs_z: 1.00
accel_z: 0.90
ofm_cvd_z_z: 1.70
final_score: 4.82
rank: 1
- code: "..." (rank 2~)
gate_funnel:
universe_size: 200
after_D1: 200 # D1=POS 통과
after_D2: 23
after_D3: 14
after_D4: 9
after_D5: 7
after_D6: 7
exposure_context: # exposure-coach 스킬 산출
suggested_exposure: 0.6
market_extreme_regime: normal
data_quality: {...}
도구 카탈로그 (선택): Agent day-trader (GO/WAIT/PASS 종합) / Agent decision/final-picks (단일 박스 응축) / Skill exposure-coach (비중).
판단 가이드:
- 산식 (sim_v6): final_score = z(rs_vs_theme) + z(stock_rs) + z(accel) + z(ofm_cvd_z) * ea_weight
- 일별 rank 1 채택이 기본. 단, rank 1과 rank 2 score 차 < 0.3 → 차상위도 후보 보고
- 통과 0건 → "NO_CANDIDATE" + 어느 게이트에서 막혔는지 stat
- D1 verdict=NEGATIVE면 D7 호출 자체 skip
출력 스키마:
{
"atomic": "D7_portfolio_selector",
"date": "2026-05-26",
"selected": {
"code": "069540", "final_score": 4.82, "rank": 1,
"components": {"rs_vs_theme_z": 1.2, "stock_rs_z": 1.0, "accel_z": 0.9, "ofm_cvd_z_z": 1.7},
"ea_weight": 1.0,
"verdict_chain": {"D1": "POS", "D2": "POS", "D3": "POS", "D4": "POS", "D5": "POS", "D6": "POS"}
},
"runners_up": [...],
"n_passed": 7,
"gate_funnel": {"D1_pass": true, "after_D2": 23, "after_D3": 14, "after_D4": 9, "after_D5": 7}
}
3.8 D8 — position-monitor¶
의미 질문: "보유 종목들의 D+20 hold 동안 상태는 정상인가?"
Input Package 빌더: scripts/discover/build_d8_input.py --as-of T0 → D8Input
Input Package 블록 구조 (보유 종목 list):
blocks:
positions:
- code: "069540"
entry_date: "2026-05-26"
entry_price: 18500
days_held: 10
days_remaining: 10
pnl:
current_ret: 0.041
kospi_ret: 0.012
alpha: 0.029
drawdown_from_entry: -0.018
max_drawdown: -0.035
regime_snapshot: # 진입일 D1 vs 오늘 D1
entry_d1_verdict: POSITIVE_HIGH
today_d1_verdict: POSITIVE_MED
regime_shift: minor_degradation
chart_warning_signals: # S317 bear 신호 발화 여부
ofm_bvc_5bar_low: false
vp_up_down_ratio_log_low: false
cvd_z_low: false
events_since_entry: [] # 공시/뉴스
data_quality: {...}
도구 카탈로그 (선택): Agent postmarket/position-evaluator (HOLD/EXIT/UPGRADE) / Agent trader/exit (9 트리거 참고).
판단 가이드: - v6 베이스라인: D+20 무조건 hold. EXIT 룰 없음 (백테스트 검증 결과) - 실거래 안전 장치 (PM 결정 사항 §10-3): drawdown < -25% 시 WARN, 매크로 regime 급전환(D1 NEGATIVE→D1 매우 강한 NEGATIVE) 시 EXIT 추천 - 일별 PnL 추적 + alpha vs KOSPI 기록
출력 스키마:
{
"atomic": "D8_position_monitor",
"as_of": "2026-06-05",
"positions": [
{"code": "069540", "entry_date": "2026-05-26", "days_held": 10, "days_remaining": 10,
"current_ret": 0.041, "kospi_ret": 0.012, "alpha": 0.029, "drawdown_from_entry": -0.018,
"status": "HOLD", "warnings": []}
]
}
4. 하네스 (실행 흐름) — Input Package 사전 조립 + verdict 기반 게이팅¶
핵심 추가 (v3): 각 atomic 호출 직전 main session이 build_d{n}_input.py를 실행해 Pydantic 검증된 Input Package를 생성. 검증 실패 시 즉시 stop (gatekeeper 계승). 검증 통과한 패키지만 에이전트에 전달.
각 atomic이 verdict: POSITIVE | NEGATIVE | NEUTRAL | UNKNOWN | UNAVAILABLE을 반환. 하네스는 verdict 체인으로 분기.
4.0 호출 단위 패턴 (모든 atomic 공통)¶
1. main: Bash run_py.ps1 scripts/discover/builders/build_d{n}_input.py --date T0 [--code C]
→ Pydantic 검증 통과 시 JSON 출력 / 실패 시 exit 1 + 에러
2. main: Agent discover/{atomic-name} 호출 시 package JSON을 prompt에 임베드
3. agent: 패키지 받음 → 가이드 따라 종합 판정 → Output JSON 반환 (Pydantic 검증)
4. main: Output을 data/discover/verdicts/{T0}/{atomic}.json에 기록
5. main: verdict 분기 결정
[Claude main] /discover T0=2026-05-26
│
▼
D1 macro-judge(T0)
│ verdict?
┌────┼─────┬─────────┐
NEG UNK POS (NEUTRAL은 POS 처리, confidence LOW)
│ │ │
PASS PM universe 후보 추출
종료 확인 (거래대금 20d 상위 200종)
│
▼
[per code] D2 chart-judge
│ NEG → skip / POS → 통과
▼
D3 rs-judge
│ NEG → skip / POS → 통과
▼
D4 theme-leader-judge
│ NEG → skip / UNK → skip / POS → 통과
▼
D5 of-judge
│ NEG → skip / UNAVAIL → 통과(weight↓) / POS → 통과
▼
D6 ea-judge (정보 부착, skip 안 함)
│
▼
[Claude main] candidate panel + verdict_chain 누적
│
▼
D7 portfolio-selector → 일별 rank 1 + runners_up
│
▼
[Claude main] entries.parquet append
│
▼
D8 position-monitor (보유 종목 전체)
│
▼
리포트: data/discover/reports/{T0}.md
(선정 1종 + verdict_chain 인용 + RR + D+20 exit 예정일 + gate_funnel)
4.1 verdict 처리 규칙¶
| atomic | NEGATIVE | NEUTRAL | UNKNOWN | UNAVAILABLE |
|---|---|---|---|---|
| D1 | PASS 종료 | universe 진입 (confidence 표시) | PM 수동 확인 요청 | (해당없음) |
| D2 | skip code | skip code | skip code | skip code |
| D3 | skip code | skip code | skip code | (해당없음) |
| D4 | skip code | skip code | skip code | (해당없음) |
| D5 | skip code | 통과 (HIGH conf 필요) | skip code | 통과 (weight 0.8) |
| D6 | weight 0.5 | weight 0.8 | weight 0.8 | weight 0.8 |
| D7 | n_passed=0 시 NO_CANDIDATE 리포트 | rank1과 rank2 차 작으면 runners_up 보고 | — | — |
| D8 | EXIT 추천 | HOLD 계속 | WARN | — |
4.2 비용/순서 최적화¶
- D1 (1회) → NEGATIVE면 종목 루프 자체 skip
- 종목 루프 내부: D2 → D3 → D4 → D5 순 (cheap → expensive)
- D2/D3/D4 = parquet read + 산술 (싸다). D5만 30분봉 read (조금 비쌈)
- 일별 호출 시간 추정: 200종 × 150ms ≈ 30초. main session 1턴 안에 처리 가능
- D2~D5는 종목별 sub-agent 호출이 아니라 에이전트 1회 호출 + 종목별 코드 반복으로 비용 절감 가능. 단, 의문 종목은 sub-agent 호출 권장
5. Atomic 에이전트 명세서 위치 (v2 갱신)¶
.claude/agents/discover/
├── macro-judge.md (D1) — 의미 질문 + 도구 카탈로그 + 가이드
├── chart-judge.md (D2)
├── relative-strength-judge.md (D3)
├── theme-leadership-judge.md (D4)
├── orderflow-judge.md (D5)
├── earnings-quality-judge.md (D6)
├── portfolio-selector.md (D7)
└── position-monitor.md (D8)
.claude/commands/
└── discover.md (하네스 + §4 흐름)
scripts/discover/ (deterministic 수치 산출 전용. 판정 X)
├── __init__.py
├── schemas.py (Pydantic D1Input/D1Output ~ D8Input/D8Output 16개 + 공통 enum)
├── macro_indicators.py (D1 산출: 39열 panel + S317 발화표)
├── chart_indicators.py (D2 산출: L2 enum + S317 60 룰)
├── stock_rs.py (D3 산출)
├── theme_rs.py (D4 산출: primary_theme/rank)
├── of_indicators.py (D5 산출: cvd_z/bvc/wick)
├── ea_indicators.py (D6 산출: ea_z 등)
├── score_compose.py (D7 산출: final_score+rank)
├── position_status.py (D8 산출: alpha/drawdown)
├── builders/ (Input Package 사전 조립기)
│ ├── build_d1_input.py
│ ├── build_d2_input.py
│ ├── build_d3_input.py
│ ├── build_d4_input.py
│ ├── build_d5_input.py
│ ├── build_d6_input.py
│ ├── build_d7_input.py
│ └── build_d8_input.py
├── validate.py (Pydantic 검증 + 실패 시 stop)
└── pipeline.py (entry point — main session에서 호출)
data/discover/
├── entries.parquet (진입 기록, append-only)
├── verdicts/{T0}/{atomic}.json (atomic verdict 로그)
├── daily_panel/{T0}.parquet (일별 통과 후보 panel)
└── reports/{T0}.md (최종 리포트)
6. 기존 자산 이관표 (제거 대상 + 이관 위치)¶
6.1 /rs_* 커맨드에서 제거할 발굴 블록¶
| 파일 | 제거 대상 블록 | 이관 위치 |
|---|---|---|
.claude/commands/rs_morning_open.md |
신규 후보 발굴 / theme 매핑 | /discover 호출로 대체 (참조만 유지) |
.claude/commands/rs_mid_morning.md |
candidate-pipeline 호출 | 제거 (모니터링만 남김) |
.claude/commands/rs_afternoon.md |
candidate-pipeline Phase 시작 | 제거 |
.claude/commands/rs_post_market.md |
candidate-pipeline + leader-opportunity | D8 postentry-monitor + /discover 분리 |
.claude/commands/rs_evening.md |
theme mapping (NC-6 일부) | 유지 (뉴스→테마 매핑은 evening 본업) |
6.2 스킬/에이전트 이관¶
| 기존 자산 | 처리 | 사유 |
|---|---|---|
.claude/skills/candidate-pipeline/SKILL.md |
deprecated → _archive/skills/ |
/discover로 대체 |
.claude/agents/postmarket/leader-opportunity.md |
이관 → discover/score-rank.md 보조 입력 | leader 선정 = D4 책임 |
.claude/agents/sector/leader-judge.md |
유지하되 D4와 역할 분리 | sector/leader-judge = 테마 차원 5대기준 (다른 use case) / D4 = v6 RS leader |
.claude/agents/postmarket/discovery-detector.md |
유지 | 이상움직임 탐지 ≠ v6 발굴, 별개 |
.claude/agents/postmarket/position-evaluator.md |
D8와 통합 | HOLD/EXIT 판정 로직 흡수 |
scripts/quant/themes/{theme_rs, theme_state_classifier, theme_selection, theme_leader_select, chart_state_score}.py |
이관 → scripts/discover/ |
5개 스크립트가 v6의 D2/D3/D4 산출 책임 |
6.3 데이터 이관¶
| 기존 위치 | 신규 위치 | 사유 |
|---|---|---|
data/backtest/sim_v6/{entries_v6, strategy_v6}.parquet |
data/discover/_history/sim_v6/ |
백테스트 기록 보존 (production 분리) |
data/backtest/discovery_walkforward/ |
data/discover/_history/walkforward/ |
동일 |
data/ats_main_v2.json |
유지 (공용 자산) | D4가 의존 |
data/backtest/e1/ea_panel_dart.parquet |
유지 (공용) | D6 의존 |
7. 출력 스키마¶
§3 각 atomic 절에 통합 — 별도 섹션 없음. 모든 출력은 공통 필수 키:
atomic(식별자)verdict(POSITIVE/NEGATIVE/NEUTRAL/UNKNOWN/UNAVAILABLE)confidence(HIGH/MED/LOW)reasoning(자연어 근거)tools_used(호출한 도구 목록 — Evidence Required 의무)- 도메인 수치 (코드 산출값을 그대로 인용)
8. 마이그레이션 단계 (실행 순서)¶
| 순서 | 작업 | 산출 |
|---|---|---|
| M1a | scripts/discover/schemas.py Pydantic 16 클래스 (D1~D8 In/Out) + 공통 enum 정의 |
schemas.py |
| M1b | scripts/discover/builders/build_d{1..8}_input.py 8개 — 코드 산출 결과 + raw 데이터 → Input Package 조립 + Pydantic 검증 |
builders/*.py |
| M1c | scripts/discover/ 8개 indicator 모듈 신규 (sim_v6 + quant/themes 이관) — pure 수치 산출 |
scripts/discover/*.py 8종 + pipeline.py + validate.py |
| M2 | .claude/agents/discover/ 8개 atomic 명세서 — 질문/도구 카탈로그/가이드/스키마 |
*-judge.md, *-selector.md, *-monitor.md 8종 |
| M3 | .claude/commands/discover.md 하네스 + verdict 분기 흐름 |
/discover 호출 가능 |
| M4 | 단독 실행 검증 — T0=2026-05-26 1시점 sim_v6 결과 대조 | 동일 종목 OR 일치 사유 |
| M5 | /rs_morning_open, _mid_morning, _afternoon, _post_market에서 발굴 블록 제거 |
diff |
| M6 | candidate-pipeline SKILL → _archive/skills/ 이동 + deprecation 마크 |
mv |
| M7 | data/backtest/sim_v6/ → data/discover/_history/sim_v6/ 이전 |
mv |
| M8 | topic_discovery_walkforward.md WBS Phase E3 완료 + _index.md 진입점 갱신 |
doc update |
9. 검증 성공 기준¶
- M4: T0=2026-05-26 단독 실행 결과 =
data/backtest/sim_v6/entries_v6.parquet의 2026-05-26 1행과 동일 종목 선정 OR 일치하지 않을 경우 verdict_chain에서 어느 단계가 달랐는지 명시 - M5:
/rs_morning_open호출 후 어느 시점에도 candidate-pipeline / theme-leader / stock pool 발굴 블록이 실행되지 않음 - M6: candidate-pipeline 스킬 호출 시도 시 deprecation 메시지
- M8:
_index.md"Today's Next Step" 갱신 — S326 완료, S327 명시
10. 미해결 결정 (PM 필요)¶
PM의 v2 방향(에이전트 자율 + 도구 무제약) 반영 — 일부 결정은 에이전트 가이드에 임계 룰 명시만 하고 최종 판단은 에이전트가.
- D1 매크로 임계: v6 베이스라인 룰(WALCL/SPY/GSPC/SOX/DEPOSIT) + S317 v2 강신호표를 둘 다 D1 가이드에 두고, D1 에이전트가 종합 verdict 결정. PM이 결정할 사항 — 모순 신호 발화 시 우선 순위? (★★ vs ★)
- OF 결손 시 처리: sim_v6 = skip / 본 설계 = weight 0.8. PM 결정 필요 (백테스트 재현성을 위해 skip 권장 vs production 운영 유연성을 위해 weight 0.8)
- D8 D+20 강제 hold 유지: 실거래에서도 백테스트와 동일하게 EXIT 룰 없음? OR drawdown < -25% / D1 NEGATIVE 급전환 시 EXIT 안전장치? (Risk: 급락 시 -30% 실현 vs 안전장치가 alpha 깎을 가능성)
- /discover 호출 빈도: 확정 = ad-hoc (
/discover수동 호출). 추가로 morning_open에서 자동 호출 trigger도 둘지? - 에이전트 호출 정책: D2~D5는 종목당 sub-agent 호출 (느림, 종목별 깊은 해석) vs main session 1회 호출 + 종목별 코드 반복 (빠름, 일괄 해석). 일별 200종 처리 시 후자 권장. PM 결정 필요
11. 참조¶
- v6 채택 근거:
data/backtest/sim_v6/v5_vs_v6.json - v6 코드:
scripts/backtest/sim_v6_6tools.py - 모듈 인벤토리:
docs/research/2026-05-26_S317_module_audit_v2.md - Phase A~E 결과:
topic_discovery_walkforward.md - 운영 룰 8가지:
_index.md"v6 채택 운영 룰" 섹션