ee3e799de1
주요 변경: - tools/build_rebalance_engine_v1.py: REBALANCE_ENGINE_V1 신규 * account_snapshot 직접 합산(_build_snap_position_map) → 소수주 분리 행 병합 * 레짐 소스 macro.REGIME_PRELIM 최우선 (GAS 와 동일) - src/gas_adapter_parts/gdf_06_rebalance.gs: runRebalanceSheet_() 신규 * Logger.log / getSpreadsheet_() 로 run_all 연동 수정 - src/gas_adapter_parts/gdc_01_fetch_fundamentals.gs * _mergePositionRecord_(): 소수주 중복 행 합산 신규 * parseInt → parseFloat (qty, availQty) - src/gas_adapter_parts/gdf_01_price_metrics.gs * 미보유 종목 SELL_READY → WATCH_EXIT_SIGNAL - spec/41_release_dag.yaml: build_rebalance_sheet 노드 추가 (step_count 63) - spec/51_formula_lifecycle_registry.yaml: REBALANCE_ENGINE_V1 등록 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
196 lines
13 KiB
YAML
196 lines
13 KiB
YAML
meta:
|
||
title: "은퇴자산포트폴리오 — 핵심 진입 게이트"
|
||
parent_file: "spec/strategy/entry_gates.yaml"
|
||
version: "2026-05-15-F11_entry_split"
|
||
language: "ko-KR"
|
||
timezone: "Asia/Seoul"
|
||
role: "canonical"
|
||
migration_status: "canonical_split_active"
|
||
|
||
entry_timing_guardrails:
|
||
principle: "좋은 종목도 비싸게 사면 수익이 나빠지지만, 강한 장세의 돌파를 놓치는 것도 손실이다. 진입은 추격이 아니라 단계화다."
|
||
regime_based_entry:
|
||
risk_on: "추세·수급·거래대금이 동시에 강하면 돌파 시범진입 허용"
|
||
leader_concentration: "top2_rotation_sum>=100 AND top1_rotation_score>=55 AND top1_alert_score>=2 AND leader_sector_flag=1 AND KOSPI_Ret20D>0 AND VIX_Close<25"
|
||
neutral: "돌파 단독이면 대기, 눌림 확인 후 진입"
|
||
risk_off: "돌파 추격 금지, 지지 확인 전 본진입 금지"
|
||
numeric_gates:
|
||
breakout_pilot:
|
||
required: ["Price_Status=PRICE_OK", "Flow_OK=Y", "Flow_Rows>=20", "20일선 위", "DART_Risk 없음"]
|
||
optimal_algorithm_formula: "Score = ((Close/MA20)-1)*100 + (Val_Surge_Pct/10) + (Net_Inst_Frg_5D_Ratio)"
|
||
formula_gate: "Score > 15 일 때만 시범진입 허용. 미만이면 뇌동매매 방지를 위해 대기."
|
||
calibration_note: # [P132] Score > 15 근거 및 재교정 기준
|
||
score_ranges: {price_dev: "1~3 (1~3% 이탈)", val_surge: "0~10 (거래대금 0~100% 급증)", net_flow: "1~5 (기관+외국인 순매수)"}
|
||
recalibration: "30건 후 손절률 > 50% 또는 평균수익 < 5% 시 임계치 20으로 상향 검토"
|
||
term_definitions: # [proposal_105 / 2026-05-15] 미정의 항 명시 — Score 게이트 정상화
|
||
Net_Inst_Frg_5D_Ratio: >
|
||
(Inst_5D_sh + Frg_5D_sh) / AvgVolume_5D_shares.
|
||
분자: 주식 수(shares) 단위 5D 순매수 합산.
|
||
분모: AvgVolume_5D_shares — 최근 5거래일 평균 거래량(주식 수). AvgTradeValue_5D_M(억원) 혼용 금지.
|
||
Flow_OK=Y 이고 Flow_Rows>=5 일 때만 계산.
|
||
DATA_MISSING 또는 Flow_Rows<5 이면 0으로 처리(보수적 기본값).
|
||
단위: 무차원 비율(소수). 예) Inst_5D=500K주, Frg_5D=300K주, AvgVolume_5D=10M주 → 0.080
|
||
minimalist_buy_gate:
|
||
rule: "과적합(Over-optimization) 방지를 위해, 진입 판단은 1)가격 추세(20일선) 2)외국인/기관 수급 3)유동성(거래대금) 3대 핵심 지표만으로 결정한다. 기타 보조지표 충돌 시 핵심 3지표를 최우선으로 한다."
|
||
formula_id: "minimalist_v1" # [proposal_111 / 2026-05-15] 수치 임계치 고정 — 일관성 확보
|
||
three_core_indicators:
|
||
indicator_1_price_trend:
|
||
formula: "Close > MA20"
|
||
pass: "종가가 20일선 위에서 마감"
|
||
fail: "종가가 20일선 아래 → 진입 금지"
|
||
data_source: "data_feed 탭 Close·MA20 또는 Naver 직접 조회"
|
||
indicator_2_supply_demand:
|
||
formula: "Frg_5D + Inst_5D > 0 AND Flow_OK=Y AND Flow_Rows >= 5"
|
||
pass: "외국인·기관 합산 5D 순매수 양수"
|
||
fail: "합산 음수 또는 Flow_OK=N → 진입 금지"
|
||
data_source: "quant_feed_contract.investor_flow_rules"
|
||
indicator_3_liquidity:
|
||
formula: "AvgTradeValue_5D_M >= 50"
|
||
pass: "5D 평균거래대금 50억원 이상"
|
||
fail: "50억원 미만 또는 DATA_MISSING → 진입 금지"
|
||
data_source: "data_feed 탭 AvgTradeValue_5D_M 또는 KRX 거래대금"
|
||
gate_logic:
|
||
all_pass: "3개 모두 pass → minimalist_gate 통과, 상위 gating 계속"
|
||
any_fail: "1개라도 fail → 진입 보류. 사유 표기."
|
||
data_missing_treatment: "핵심 필드 DATA_MISSING이면 해당 지표 fail로 보수 처리."
|
||
integration_rule:
|
||
- "minimalist_buy_gate 통과 후 ATR수량·Expected_Edge·sector_model.grade 상위 gating 계속."
|
||
- "미통과 종목에 RSI·MACD·볼린저 등 보조지표 적용 금지."
|
||
- "이 게이트는 A등급 승격의 필요조건. 충분조건은 상위 gating."
|
||
occams_razor_alignment: # [P133] minimalist_gate와 occams_razor는 다른 목적
|
||
note: "minimalist_buy_gate 3지표(추세/수급/유동성)는 진입 가부 판단 게이트. occams_razor_filter는 타이밍 정밀도 보조. 목적이 달라 동일 지표가 아님 — 두 단계를 순서대로 적용."
|
||
override_prohibition: "이 3개 외 보조지표를 '더 중요하다'는 이유로 대체 금지."
|
||
occams_razor_filter:
|
||
rule: "신규 매수(A등급 승격) 판단 시 융합할 수 있는 조건은 최대 3개로 제한한다. 초과된 조건은 뇌동매매 방지를 위해 기계적으로 무시한다."
|
||
preferred: ["최근 5거래일 상승률이 섹터 평균 이상", "Val_Surge_Pct 0~25", "종가가 고가 근처 마감"]
|
||
tranche: "계획 수량의 20~30%"
|
||
breakout_block:
|
||
trigger: ["Val_Surge_Pct 40 이상", "장대양봉 연속", "거래대금 급폭발", "5거래일 연속 급등"]
|
||
action: "본진입 금지. 시범진입도 10~20%로 축소하거나 관찰로 전환."
|
||
pullback_buy:
|
||
required: ["20일선 또는 5일선 부근", "거래대금 감소 또는 안정", "Flow_OK=Y", "20D 수급 유지"]
|
||
tranche: "계획 수량의 40~60%"
|
||
leader_concentration:
|
||
numeric_definitions:
|
||
top2_rotation_sum: "sector_flow 상위 2개 Rotation_Score 합"
|
||
top1_rotation_score: "sector_flow 상위 1개 Rotation_Score"
|
||
top1_alert_score:
|
||
INFLOW_STRONG: 3
|
||
INFLOW_MODERATE: 2
|
||
NEUTRAL: 1
|
||
OUTFLOW_CAUTION: 0
|
||
OUTFLOW_ALERT: -1
|
||
leader_sector_flag:
|
||
# [Q5 / 2026-05-15] "주도 섹터"의 판정 주체와 기준 미명시로 LLM이 임의 판단하는 할루시네이션 방지.
|
||
formula: "sector_flow 탭에서 Rotation_Score 1위 섹터명이 아래 approved_list 중 하나이면 1, 아니면 0"
|
||
approved_list: ["반도체", "AI전력", "전력기기", "발전/전력"]
|
||
data_source: "sector_flow 탭 Rotation_Score 컬럼 기준 1위 행의 섹터명"
|
||
missing_rule: "sector_flow 탭 미제공 또는 Rotation_Score 미확인 시 leader_sector_flag=0 (보수적 기본값)"
|
||
disambiguation: "'AI전력'은 AI 인프라·전력기기·전력 설비 관련 섹터를 의미. 항공·우주·방산과 혼동 금지."
|
||
gate: "top2_rotation_sum>=100 AND top1_rotation_score>=55 AND top1_alert_score>=2 AND leader_sector_flag=1 AND KOSPI_Ret20D>0 AND VIX_Close<25"
|
||
pilot_tranche: "20~30%"
|
||
add_on_tranche: "40~60%"
|
||
stop_gate: "Val_Surge_Pct>=40 OR DART_Risk!=없음 OR Flow_OK!=Y"
|
||
expected_edge_floor: # [P95] 기대우위 하한선 — 비용 차감 후 최소 손익비 미만 진입 차단
|
||
purpose: "기대우위가 하한선 미만이면 신규 진입을 금지하고 관찰만 유지한다."
|
||
formula: "Expected_Edge = (target_price - entry_price) / (entry_price - stop_price) × bayesian_confidence_multiplier - execution_cost_rate"
|
||
threshold:
|
||
floor: "Expected_Edge >= 1.5 → 진입 허용. 미만이면 관찰 전환."
|
||
prohibition:
|
||
- "Expected_Edge 미산출 시 A등급 즉시매수 금지"
|
||
- "손절가 미설정 상태에서 Expected_Edge 산출 금지 (분모 = 0이 되어 연산 불능)"
|
||
confirmation_rule:
|
||
breakout_only: "신고가·박스 돌파 첫날은 전량 매수 금지. 다만 risk_on이면 계획 수량의 20~30% 시범진입은 허용."
|
||
add_on_rule: "돌파 다음날 종가 유지 또는 2~3거래일 내 눌림 후 지지 확인이 있어야 본진입 허용."
|
||
pullback_rule: "20일선 또는 5일선 부근 눌림에서 거래대금이 줄고 수급이 유지될 때 우선 매수."
|
||
quality_filter: "종가가 고가 근처에서 마감하고, 장중 밀림을 다시 회복하며, 20D 수급이 양호해야 돌파 신뢰도 상향."
|
||
overextension_rule:
|
||
too_hot: "최근 급등 후 거래대금이 과도하게 폭발하고 장대양봉이 연속되면 본진입 보류."
|
||
chase_limit: "최근 5거래일 상승률이 섹터 평균을 크게 초과하면 추격매수 대신 관찰 또는 소액 시범진입만 허용."
|
||
acceptable_extension: "다만 섹터 주도주가 20일선 위에서 1차 돌파 후 0~3% 연속 확장하는 구간은 risk_on에 한해 허용."
|
||
timing_mode_policy:
|
||
principle: >
|
||
선행형은 작은 초기 포지션을 빠르게 잡아 기회를 확보하는 방식이고,
|
||
후행형은 확인 후 진입·반등 확인 후 축소·추세 훼손 후 정리하는 방식이다.
|
||
둘 중 하나만 고집하지 말고, 시장 국면과 데이터 완성도에 따라 전환한다.
|
||
lead_when:
|
||
regime: ["risk_on", "leader_concentration"]
|
||
required: ["Price_Status=PRICE_OK", "Flow_OK=Y", "Flow_Rows>=20", "20일선 위", "DART_Risk 없음"]
|
||
use_case:
|
||
- "신고가 직전 또는 1차 돌파 구간의 시범진입"
|
||
- "주도 섹터 내 대장주 초기 편입"
|
||
size_rule:
|
||
pilot_tranche: "계획 수량의 20~30%만"
|
||
add_on: "돌파 유지·눌림 지지 확인 후 나머지 70~80%"
|
||
prohibition:
|
||
- "대량 일괄매수 금지"
|
||
- "선행형 신호를 이유로 손절가·수량 미확정 상태에서 진입 금지"
|
||
lag_when:
|
||
regime: ["neutral", "risk_off", "data_partial", "high_volatility"]
|
||
required: ["20일선 재확인", "수급 유지 확인", "거래대금 급감 없음"]
|
||
use_case:
|
||
- "반등 확인 후 축소"
|
||
- "손실 포지션 정리"
|
||
- "섹터 이탈 종목의 시간 손절"
|
||
size_rule:
|
||
entry_tranche: "계획 수량의 40~60% 또는 반등 확인 후 분할"
|
||
exit_rule: "손실 포지션은 후행형으로 줄이고, 강한 종목은 반등 시 축소"
|
||
prohibition:
|
||
- "저점 추격 투매 금지"
|
||
- "후행형이 필요할 때 선행형 돌파 추격 금지"
|
||
hybrid_when:
|
||
regime: ["neutral with strong setup", "risk_on but data_mixed"]
|
||
rule: "시범진입은 선행형, 본진입/축소는 후행형으로 분리"
|
||
output_requirement: "보고서에 선행/후행 중 어느 모드인지 반드시 명시"
|
||
scoring_gate:
|
||
lead_score_formula: "(price_strength + flow_strength + liquidity_strength) - volatility_penalty - data_miss_penalty"
|
||
lead_threshold: "lead_score >= 3 → 선행형 허용"
|
||
lag_threshold: "lead_score < 3 → 후행형 우선"
|
||
note: "lead_score는 진입 타이밍 보조지표이며, 기대수익비·손절가·수량 산출을 대체하지 않는다."
|
||
|
||
# [2026-05-17] 지정가 산출 공식 — limit_price_formula
|
||
# 매수 지정가를 시나리오별로 명확히 정의해 LLM이 임의 가격을 생성하지 않도록 한다.
|
||
limit_price_formula:
|
||
authority_note: "지정가 계산은 아래 시나리오 중 진입 유형에 따라 하나를 선택. 불명확 시 pullback_limit 우선."
|
||
data_inputs: ["Close", "Ask (매도1호가)", "MA20", "ATR20"]
|
||
missing_rule: "Ask 미제공 또는 Spread_Status=WIDE 이면 Close 기반 공식으로 fallback."
|
||
|
||
scenarios:
|
||
breakout_pilot:
|
||
entry_context: "breakout_pilot 또는 leader_concentration 시범진입"
|
||
formula: "limit_price = Ask if Ask available else Close * 1.005"
|
||
note: "매도1호가 체결 우선. Ask 없으면 종가 +0.5% (2~3틱) 위 지정가."
|
||
max_chase_limit: "Close * 1.010 초과 지정가 금지 — 추격매수 방지"
|
||
|
||
pullback_buy:
|
||
entry_context: "pullback_buy (눌림 매수) 또는 MA20 지지 확인 후 진입"
|
||
formula: "limit_price = Close * 1.002 (종가 +0.2%, 시가 이하 눌림 체결 목표)"
|
||
note: "눌림 구간에서 종가보다 낮은 가격도 허용. 체결 못하면 다음 날 재판단."
|
||
tighter_option: "limit_price = MA20 * 1.003 (MA20선 +0.3% — 지지 부근 매수)"
|
||
|
||
staged_add_on:
|
||
entry_context: "본진입 2·3차 분할 매수 (breakout 유지 확인 후)"
|
||
formula: "limit_price_2nd = entry_price_1st * (1 + 0.005~0.010)"
|
||
note: "1차 평단 대비 0.5~1.0% 위. 추가 급등 구간(Val_Surge_Pct>=40)에서는 추가 금지."
|
||
|
||
stop_price_formula:
|
||
formula: "stop_price = entry_price - ATR20 * stop_atr_multiplier"
|
||
stop_atr_multiplier:
|
||
default: 1.5
|
||
tight: 1.0
|
||
wide: 2.0
|
||
canonical_ref: "spec/05_position_sizing.yaml:position_sizing.volatility_targeting"
|
||
note: "stop_price는 entry_price 확정 직후 계산. ATR20 미제공 시 매수수량 산출 금지 (HF002)."
|
||
|
||
expected_edge_calculation:
|
||
formula: "Expected_Edge = (target_price - entry_price) / (entry_price - stop_price) * bayesian_confidence_multiplier - execution_cost_rate"
|
||
inputs:
|
||
target_price: "data_feed 탭 Target_Price (Naver 컨센서스 우선, Yahoo 폴백)"
|
||
entry_price: "limit_price (위 시나리오 중 선택)"
|
||
stop_price: "stop_price_formula 결과"
|
||
bayesian_confidence_multiplier: "spec/05_position_sizing.yaml 참조 (기본 1.0)"
|
||
execution_cost_rate: "0.003 (왕복 거래비용 0.3% — 증권사 수수료+세금)"
|
||
floor: "Expected_Edge >= 1.5 → 진입 허용. 미만이면 관찰 전환 (RA003)."
|
||
|
||
# [proposal_47 / 2026-05-15] 일간 주도주 조기탐지 레이어 — daily_leader_scan
|