Files
QuantEngineByItz/spec/strategy/entry_core.yaml
kjh2064 ee3e799de1 feat: 리밸런싱 엔진 V1 + GAS 버그 수정 (2026-06-13)
주요 변경:
- 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>
2026-06-13 13:20:14 +09:00

196 lines
13 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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