Files
QuantEngineByItz/spec/risk/portfolio_exposure.yaml
T
kjh2064 aedabdd37b feat(quant-engine): v8.9 제안서 P0-P3 로드맵 채택 — 15개 의사결정 엔진 신규 구현
suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml의
implementation_todo_v8_9(P0~P4) 전체를 spec/tool/golden case 레벨로 구현.

- P0: PORTFOLIO_TRANSITION_UTILITY_V1, SELL_LOT_PARETO_SELECTOR_V1, FORECAST_SIMULATION_ENGINE_V1
- P1: SECTOR_EXPOSURE_GRAPH_V1/LEADER_LIFECYCLE_GATE_V1, EXECUTION_CAPACITY_LADDER_V1, MODEL_GOVERNANCE_KILL_SWITCH_V1
- P2: SCENARIO_SHOCK_MATRIX_V1, TRANSITION_SET_ENUMERATOR_V1, IMMUTABLE_DECISION_LEDGER_V1, EXECUTION_PLAN_COMPILER_V1
- P3: STATE_VECTOR_CONSTRUCTOR_V1, WALK_FORWARD_BOOTSTRAP_V1, TRANSITION_SET_ENUMERATOR_V1(MRC/CVaR 확장),
      REBALANCE_CADENCE_GATE_V1, WEEKLY_LEGACY_TRANSFER_PLAN_V1

기존 regime/cluster 연동 정책 수치(현금방어선, 반도체 cap)는 그대로 유지하고 신규 cap 필드만 추가.
spec/09_decision_flow.yaml과 runtime/active_artifact_manifest.yaml에 전 엔진 배선 완료.
governance/todo/v8_9_p{0,1,2,3}_adoption_plan.yaml에 각 단계 작업 추적 기록.

검증: validate_specs/validate_golden_coverage_100(100%)/validate_calibration_registry_v1/
validate_schema_model_generation_v1/validate_agents_shrink_v1 전부 PASS. golden test 53/53 PASS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 00:06:52 +09:00

490 lines
30 KiB
YAML
Raw 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/03_risk_policy.yaml"
version: "2026-05-18-F10_score_clamp_d2_fix"
language: "ko-KR"
timezone: "Asia/Seoul"
role: "canonical"
migration_status: "canonical_split_active"
authority_rule: "이 split 파일이 해당 섹션의 canonical source다. parent_file은 legacy compatibility index다."
portfolio_exposure_framework:
principle: "비중 한도는 파산확률 제어 장치. 시장지배 주도주는 벤치마크와 비교해 판단."
exposure_layers:
direct_core_leaders: ["삼성전자", "SK하이닉스"]
duplicate_beta: ["KODEX 반도체", "동일 섹터 ETF"]
tactical_satellites: ["방산", "조선", "전력설비", "건설", "플랜트/EPC", "로보틱스", "기타 고베타"]
cash: ["현금", "MMF", "RP", "단기채 ETF"]
valid_trim_reasons:
- "벤치마크 대비 초과비중이 허용밴드를 초과하고 가격 추세가 훼손됨"
- "직접보유와 ETF가 같은 팩터를 중복 보유해 실질노출이 상한 초과"
- "포트폴리오 현금이 최소 방어현금 이하이고 신규 기회 또는 손실방어 자금이 필요"
- "외국인·기관 5D/20D 수급 동반 이탈 + 거래대금 동반 장대음봉"
sell_priority_engine:
purpose: >
여러 보유 종목·ETF가 동시에 SELL/TRIM/ROTATE 후보가 되었을 때
어떤 주문을 먼저 실행할지 결정하는 포트폴리오 단위 우선순위 규칙.
stop_loss.sell_signal_priority는 종목 내부 매도 신호 우선순위이고,
이 엔진은 계좌·현금·중복노출·상대약세를 종합한 후보 간 정렬 기준이다.
activation_any:
- "cash_floor.trim_required_when 충족"
- "duplicate_exposure_rule 발동"
- "동일 리포트에서 SELL/TRIM/ROTATE 후보가 2개 이상"
- "risk_off 또는 event_week 현금 상향 필요"
- "보유주 진단에서 축소/교체 후보가 2개 이상"
required_inputs:
- "capture_read_ledger.current_holding_quantity"
- "average_cost"
- "current_price"
- "unrealized_return_pct"
- "current_weight_pct"
- "target_weight_pct 또는 target_band"
- "duplicate_exposure_status"
- "cash_floor_status"
- "rw_partial 또는 relative_weakness_exit 합계"
- "liquidity_status 또는 AvgTradeValue_5D_M"
- "account_type"
- "tax_cost_estimate 또는 세금 미확인 표시"
hard_precedence:
1: "법적·거래정지·상장폐지·회계 리스크 또는 stop_loss.emergency — 수량 확인 시 최우선"
2: "hard stop 손절, trailing_stop 이탈, time_stop 만료, RW>=4 — stop_loss.sell_signal_priority 적용"
3: "cash_floor 미달 또는 policy_event_week_escalation 현금 상향 — 현금 확보 목적 매도 우선"
4: "중복노출 상한 초과 — duplicate_exposure_rule.funding_order 적용"
5: "보유주 진단 교체/축소 후보 — current_holdings_score 낮은 순"
6: "익절·리밸런싱 후보 — 세후 비용 대비 이탈폭 큰 순"
7: "단순 수익 실현 — 다른 우선순위가 없을 때만"
candidate_scoring:
purpose: "동일 hard_precedence 단계 안에서 후보를 정렬하는 보조 점수. 점수가 높을수록 먼저 매도."
score_range: "0~100"
clamp: "Sell_Priority_Score = min(max(formula_result, 0), 100)"
clamp_rationale: >
컴포넌트 합산 시 이론상 최대 122점 초과 가능(예: hard_stop 50 + 중복ETF 20 + 상대약세 20 + ...).
100 초과 점수는 LLM 임의 가중치 개입 증거로 오인되므로 반드시 min(result, 100) clamp 적용.
clamp 발동 시 출력에 "[CLAMP 발동: raw={raw_score} → 100]" 표기 필수.
formula: >
Sell_Priority_Score = min(max(
hard_precedence_points
+ duplicate_exposure_points
+ cash_relief_points
+ weakness_points
+ overweight_points
+ liquidity_points
- tax_penalty_points
- core_quality_protection_points
, 0), 100)
components:
hard_precedence_points:
emergency_or_hard_stop: 50
cash_floor_trim_required: 40
duplicate_exposure_required: 30
holding_diagnosis_rotate_or_trim: 20
take_profit_rebalance: 10
duplicate_exposure_points:
same_sector_etf: 20
lower_quality_duplicate: 15
no_duplicate: 0
cash_relief_points:
expected_net_cash_pct_ge_3: 15
expected_net_cash_pct_1_to_3: 10
expected_net_cash_pct_lt_1: 3
weakness_points:
rw_ge_4_or_rs_laggard: 35 # RS_RATIO_V1: rs_ratio < 0.80 (시장 대비 20%+ 약세)
rw_3_or_momentum_decel: 25
rw_2: 8
flow_5d_20d_negative: 15
price_below_ma20_ma60: 10
weakness_formula_refs: # [2026-05-19_ALPHA_SHIELD_V1] X3 rs_laggard 공식 확정
rs_laggard:
formula_id: "RS_RATIO_V1"
definition: "rs_ratio = stock_5d_return / kospi_5d_return < 0.80"
rs_leader_protection: "rs_ratio >= 1.20 -> sell_priority 후순위 보호"
canonical_ref: "spec/13_formula_registry.yaml:formula_registry.formulas.RS_RATIO_V1"
overweight_points:
above_target_by_5p_or_more: 12
above_target_by_2_to_5p: 6
within_band: 0
liquidity_points:
avg_trade_value_sufficient: 5
low_liquidity: -10
tax_penalty_points:
high_tax_or_fee_drag: 10
unknown_tax_cost: 3
tax_loss_harvest_available: -5
core_quality_protection_points:
direct_core_leader_in_valid_uptrend: 20
A_core_or_CSCs_ge_85: 12
satellite_or_etf: 0
tie_breakers:
1: "더 높은 hard_precedence 단계"
2: "Sell_Priority_Score 높은 후보"
3: "cash_floor 개선 효과가 큰 후보"
4: "중복노출 해소 효과가 큰 후보"
5: "current_holdings_score 낮은 후보"
6: "세후 비용이 낮은 후보"
7: "유동성이 충분해 지정가 체결 가능성이 높은 후보"
account_priority:
principle: "계좌별 세금·한도·출금 가능성을 고려하되, hard stop 손절을 세금 이유로 지연하지 않는다."
taxable_account: "세금비용이 크면 동일 우선순위 내에서 후순위. 단, 손절·hard stop은 예외."
isa: "비과세/분리과세 한도와 납입 여력 확인 후 리밸런싱 후보 우선 가능."
pension: "장기 코어·해외ETF 성격은 보호. 위성·중복 ETF만 우선 축소."
output_required:
table: "sell_priority_decision_table"
columns: ["우선순위", "계좌", "종목명", "현재보유수량", "매도가능검산", "매도유형", "우선순위단계", "Sell_Priority_Score", "예상순현금", "세금/비용", "execution_style", "immediate_sell_qty", "rebound_wait_qty", "max_daily_qty", "매도사유", "보류사유", "다음확인사항"]
smart_cash_raise_execution: # [2026-05-20_APEX_V1] 현금확보 매도 품질 하네스
purpose: >
현금 부족 해소 목적의 매도를 단순 우선순위 정렬에서 끝내지 않고,
과매도 반등 대기·분산 위험 즉시 감축·수익보호 감축·체결 품질 제한까지 연결한다.
formula_refs:
cash_raise_plan: "spec/13b_harness_formulas.yaml:SMART_CASH_RAISE_PLAN_V1"
rebound_trigger: "spec/13b_harness_formulas.yaml:REBOUND_SELL_TRIGGER_V1"
sell_quantity_allocator: "spec/13b_harness_formulas.yaml:SELL_QUANTITY_ALLOCATOR_V1"
execution_quality: "spec/13b_harness_formulas.yaml:EXECUTION_QUALITY_GUARD_V1"
execution_styles:
URGENT_LIQUIDITY_TRIM:
trigger: "cash_floor_status=HARD_BLOCK AND rsi14>=35 AND bb_position>=20"
rule: "sell_priority rank 순서대로 immediate_sell_qty 배정. 단일 종목 일괄 전량 금지."
OVERSOLD_REBOUND_SELL:
trigger: "rsi14<35 OR bb_position<20 OR close < ma20 - 8%"
rule: "즉시 매도는 cap 이하. 잔여는 rebound_wait_qty로 분리하고 REBOUND_SELL_TRIGGER_V1 충족 시 실행."
DISTRIBUTION_EXIT:
trigger: "distribution_risk_score>=70"
rule: "반등 대기보다 감축 우선. 단 시장가 전량 매도와 불리한 추격 정정 금지."
PROFIT_PROTECT_TRIM:
trigger: "profit_preservation_state IN [PROFIT_LOCK_20, PROFIT_LOCK_30]"
rule: "수익 포지션 일부 이익잠금. secular_leader_gate_active=true이면 하네스 defer 상태 우선."
quantity_policy:
allocator: "SELL_QUANTITY_ALLOCATOR_V1"
immediate_qty_cap_default_pct: 25
max_daily_qty_default_pct: 50
rebound_wait_required_when: "execution_style=OVERSOLD_REBOUND_SELL"
prohibition:
- "현금 부족을 이유로 과매도 후보를 전량 즉시 매도 금지"
- "rebound_wait_qty를 LLM이 immediate_sell_qty로 이동 금지"
- "execution_quality_status != PASS인 행을 HTS 주문표 PASS로 출력 금지"
- "코어 주도주 직접보유는 tier 1~8 후보 소진 전 현금확보 1순위 금지"
prohibition:
- "보유수량 미확인 상태에서 Sell_Priority_Score가 높아도 매도수량 숫자 출력 금지"
- "세금 최적화를 이유로 hard stop·cash_floor hard stop 매도를 지연 금지"
- "주도주 직접보유를 중복 ETF보다 먼저 매도하려면 hard stop 또는 명확한 thesis 훼손 근거 필요"
- "매도 우선순위를 산문으로만 설명하고 표를 생략 금지"
- "sell_priority_decision_table 없이 복수 매도 후보 중 특정 종목 수량을 확정 금지"
# ── 현재 시장 국면 주도 섹터 종목 TRIM 방어 규칙 ────────────────────────────
# 배경: REGIME_TRIM_50 등 현금 확보 목적 매도 시 sell_priority_engine을 거치지 않으면
# 시장 주도 섹터 직접보유 종목(SK하이닉스 등)이 잘못 1순위로 선택되는 오류 발생.
regime_leading_sector_protection:
rule: >
현재 market_regime_state가 LEADER_CONCENTRATION 또는 SECULAR_LEADER_RISK_ON이고
sector_flow Rotation_Rank 1~2위 섹터의 직접보유 종목은
현금 확보 목적 매도(REGIME_TRIM_50·cash_floor_raise)에서 sell_priority tier=9(마지막) 고정.
override_conditions_all_required:
- "해당 종목에 hard_stop(EXIT_100·TRAILING_STOP_BREACH) 발동"
- "OR thesis 훼손 명시: 실적 하향·외국인+기관 20D 동반 순매도·MA20+MA60 동시 이탈"
- "OR tier 1~8 후보가 모두 소진되어 남은 선택지가 없음"
gas_check: >
runSellPriority() 결과에서 해당 종목이 tier=9로 표시되는지 확인.
tier=9가 아닌 상위 순위로 나타나면 calcSellPriorityScore_() 입력 데이터 오류.
prohibition:
- "현재 장 주도 섹터(반도체·AI전력 등) 직접보유를 '수익이 있어서' 이유로 1차 매도 선정 금지"
- "ETF 중복노출(KODEX 반도체·TIGER AI전력기기) 미확인 상태에서 코어주도주 TRIM 금지"
- "sell_priority_table 출력 전 '주도주를 먼저 팔자'는 판단 표현 금지"
duplicate_exposure_rule:
calculation: "반도체 실질노출 = 삼성전자 직접비중 + SK하이닉스 직접비중 + 반도체 ETF × ETF 반도체 순도"
funding_order: ["①중복 섹터 ETF", "②20D 수급 이탈·20일선 하회 위성", "③동일 섹터 내 후순위", "④시장지배 코어 직접보유 (마지막)"]
leader_quality_switch: # [proposal_86 / 2026-05-16] ETF→반도체 주도주 직접 전환 가속
purpose: >
SECULAR_LEADER_RISK_ON 국면에서 반도체 ETF 성과가 직접 주도주 대비 열위일 때
ETF 비중을 감축하고 직접 주도주로 노출 품질을 높인다.
etf_staged_reduction(proposal_58)과 병행 가능. 이 규칙이 우선 발동 트리거 역할.
trigger_required_all:
- "market_regime_state == SECULAR_LEADER_RISK_ON"
- "same_sector_etf_weight_pct > 0 (반도체 ETF 보유 중)"
- "삼성전자 OR SK하이닉스 중 1개 이상이 SECULAR_LEADER_RISK_ON 조건 통과"
- "ETF Ret10D <= 직접 주도주(삼성전자 OR SK하이닉스) Ret10D - 3%p"
action:
step_1: "ETF 30~50% 감축 검토 (etf_staged_reduction.step_1과 동일 규칙 적용)"
step_2: "감축 대금은 동일일 즉시 전량 투입 금지. 2거래일 이내 대기."
step_3: "2거래일 이내 주도주 staged_entry_v2 stage_1 OR stage_2 조건 충족 시 전환 매수 실행"
prohibition:
- "ETF 매도대금으로 anti_climax_buy_gate 미통과 주도주 추격매수 금지"
- "ETF 감축 후 semiconductor_total_cap 초과 직접매수 금지"
- "SECULAR_LEADER_RISK_ON 비활성 시 이 규칙 적용 금지 — etf_staged_reduction만 사용"
- "ETF 성과 비교 데이터 미확인 시 트리거 발동 금지"
output_table:
columns:
- "ETF종목명"
- "ETF_Ret10D(%)"
- "직접주도주_Ret10D(%)"
- "차이(%p)"
- "감축검토수량"
- "전환대상주도주"
- "전환실행예정일"
etf_staged_reduction: # [proposal_58 / 2026-05-15] ETF-개별주 중복 노출 단계적 감축
purpose: >
ETF-개별주 중복 노출 발생 시 즉각 전량 청산이 아닌 단계적 감축으로
추세 지속 기회비용 손실과 중복 리스크를 동시에 관리한다.
trigger: >
duplicate_exposure_rule 발동 조건 충족:
동일 섹터 ETF + 개별주 동시 보유 비중이 총자산 대비 20%p 이상
step_1_immediate_reduction:
action: "ETF 보유수량의 50% 즉시 매도 (지정가, 당일 장중)"
rationale: "중복 노출 절반 즉시 해소. 개별주로의 집중 시작."
order_type: "지정가 — 전일종가 -0.5% 이하 호가 우선. 시장가 금지."
prohibition:
- "패닉 시장가 전량 매도 금지"
- "ETF를 매도하기 전 개별주 비중이 총자산 15% 미만인 경우 step_1 연기 가능"
step_2_sector_trend_check:
timing: "step_1 실행 후 2~5거래일 대기"
conditions:
continue_reduction:
description: "잔여 50% 추가 매도 진행 조건"
criteria:
- "sector_flow.Rotation_Score 해당 섹터 순위가 3위 이하로 하락"
- "주도섹터 ETF(대표지수) 대비 해당 ETF Ret10D <= -3%p"
- "daily_leader_scan에서 해당 섹터 C5=0 (섹터 주도 상실)"
action: "잔여 50% 매도. 섹터 ETF 포지션 완전 청산."
hold_remainder:
description: "잔여 50% 유지 조건"
criteria:
- "sector_flow.Rotation_Score 해당 섹터 순위 1~2위 유지"
- "Ret10D_ETF >= 주도섹터ETF Ret10D -2%p 이내"
- "daily_leader_scan에서 해당 섹터 C5=1 유지"
action: >
잔여 50% 30거래일 추가 보유. 30거래일 후 step_2 재점검.
개별주 비중이 총자산 25% 이상 확대된 시점에 자동 매도 전환.
step_3_full_exit_trigger:
description: "단계 관계없이 즉시 전량 매도하는 비상 조건"
conditions:
- "해당 ETF ATR20_Status=DATA_MISSING AND 2거래일 이상 지속"
- "섹터 crash_intraday_protocol tier_B 이상 발동"
- "weekly_circuit_breaker.circuit_break 발동"
- "portfolio_hard_stop_procedure 발동"
action: "전량 지정가 분할 매도. 1거래일 내 완료."
output_table:
columns:
- "ETF종목명"
- "현재보유수량"
- "1단계매도수량"
- "잔여수량"
- "섹터추세판정"
- "2단계처리방향"
- "완전청산예상일"
prohibition:
- "step_1 실행 없이 step_2로 바로 진행 금지 — 50% 우선 감축은 필수"
- "ETF 매도 후 동일 섹터 다른 ETF 즉시 매수로 대체 금지 (중복 재발)"
- "개별주 미확보 상태에서 ETF 전량 청산 금지 — 섹터 노출 완전 소멸 방지"
target_allocation_structure: # [proposal_55 / 2026-05-15] 3-버킷 목표 운영 구조
purpose: >
포트폴리오 운영 목표 비중을 3개 버킷으로 명시.
실제 비중이 목표 밴드를 벗어나면 리밸런싱 신호 발생.
각 버킷은 기존 규칙(special_exception·cash_floor·sector_cap)에 우선하지 않는다.
목표 구조는 방향성 지침이며, 기존 risk_block이 항상 우선한다.
buckets:
core_bucket:
label: "코어 (Core)"
target_pct: 65
band: "60~72%"
definition: >
CSCS >= 70 종목 또는 special_exception 대상.
삼성전자·SK하이닉스·방산·조선 대장주·전력기기 주도주.
60거래일 이상 보유 목표.
rebalancing_trigger:
trim: "코어 합산 비중 > 72% → 초과분 부분 익절 검토 (take_profit.rebalancing_trim 준용)"
add: "코어 합산 비중 < 60% AND orbit_state != unrealistic → A등급 코어 추가매수 검토"
prohibition:
- "코어 버킷 확대를 이유로 위성·현금 버킷 한도 이하로 압박 금지"
tactical_satellite_bucket:
label: "전술 위성 (Tactical Satellite)"
target_pct: 20
band: "10~25%"
definition: >
CSCS < 70 종목. staged_entry_v2 탐색매수→확인매수→주력편입 대상.
평균 보유 목표 20~60거래일.
이 버킷이 수익률 엔진이다. 목표 구조 내에서 최대 25%까지 허용.
rebalancing_trigger:
trim: "위성 합산 비중 > 25% → relative_weakness_exit 점수 높은 종목부터 감축"
add: "위성 합산 비중 < 10% AND daily_leader_scan 탐색 후보 존재 → 탐색매수 1건 검토"
concentration_rule: "단일 위성 종목 최대 7% (stock_model.core_satellite_rule.max_weight 준수)"
cash_fc_bucket:
label: "현금 + 탐색 실패 허용 예산 (Cash + FC)"
target_pct: 15
band: "10~22% (MRS 연동 가변)"
definition: >
즉시 인출 가능 현금 + D+2 추정현금성자산.
MRS 기반 목표현금(market_risk_score_based_cash) + FC 예산(explore_loss_budget) 합산.
강한 상승장(MRS=0): 하한 10%. 리스크 이벤트(MRS=8~10): 상한 22%.
fc_reserve:
formula: "FC_reserve = 총자산 × 0.025 (월 탐색 실패 허용 예산)"
note: "FC_reserve는 현금 버킷 내 별도 슬롯. 탐색매수 손절 시 FC_reserve에서 차감."
rebalancing_trigger:
raise: "현금 < 10% OR MRS 기반 목표현금 > 현재 즉시현금 → 위성 부분 매도 또는 코어 익절"
deploy: "현금 > 22% AND orbit_state=achievable → 탐색매수·확인매수 적극 집행"
orbit_adjustment_rule: # [proposal_72 / 2026-05-15] orbit_monthly_tracker 오프셋 결과 하한 clamp
purpose: "orbit_monthly_tracker의 cash_floor 하한 조정 오프셋이 현금 버킷을 10% 미만으로 밀어내는 것을 방지."
clamp_rule: "최종 현금 목표 = max(orbit_adjusted_target, dynamic_cash_floor)"
dynamic_cash_floor: # [proposal_85 / 2026-05-16] SECULAR_LEADER_RISK_ON 시 clamp 하한 7%
secular_leader_risk_on: "7% — SECULAR_LEADER_RISK_ON 조건 전부 충족 시만 적용"
normal: "10% — 기본값"
event_week_or_overheated: "12~15%"
risk_off: "15~25%"
secular_leader_risk_on_required_all:
- "market_regime_state == SECULAR_LEADER_RISK_ON"
- "MRS <= 3"
- "Total_Heat < 7%"
secular_leader_risk_on_note: >
normal.min_cash_ratio = 7%(cash_floor.regime_numbers.normal)와 동일한 수준.
즉 SECULAR_LEADER_RISK_ON에서도 기존 normal 하한(7%)을 벗어나지 않는다.
이 완화는 orbit_clamp 10%와 normal min 7% 사이의 3%p 공간을 해소하는 것.
calculation_sequence:
step_1: "orbit_monthly_tracker.adjustment_rules에 따라 orbit_offset(±%p) 계산"
step_2: "MRS 기반 목표현금(market_risk_score_based_cash) + orbit_offset = orbit_adjusted_target"
step_3: "SECULAR_LEADER_RISK_ON 조건 충족 시 dynamic_cash_floor = 7%, 미충족 시 10%"
step_4: "orbit_adjusted_target < dynamic_cash_floor → dynamic_cash_floor로 강제 clamp"
prohibition:
- "D+2 추정현금성자산을 즉시현금 cash_floor 충족으로 간주 금지"
- "SECULAR_LEADER_RISK_ON 해제 즉시 clamp 하한 10%로 복귀 (중간값 유지 금지)"
note: "clamp 발동 시 블록 5(현금 룰 판정) 출력에 [CLAMP 발동: orbit_offset 일부 무시, floor=X%] 표기 필수."
bucket_rebalancing_workflow:
step_1: "매주 수요일 정기점검: 3개 버킷 현재 비중 산출"
step_2: "MRS 산출 → cash_fc_bucket 목표 조정"
step_3: "각 버킷 벗어남 확인 → 리밸런싱 우선순위 결정"
step_4: "리밸런싱 방향: trim 우선(위험 낮추기) → add 이후(기회 포착)"
priority:
1: "cash_fc_bucket.raise가 최우선 (risk_block 준수)"
2: "tactical_satellite_bucket.trim 두 번째"
3: "core_bucket 조정 마지막"
output_table:
columns:
- "버킷"
- "목표비중(%)"
- "현재비중(%)"
- "목표밴드"
- "이탈여부"
- "리밸런싱 방향"
- "즉시실행 필요"
prohibition:
- "목표 구조를 이유로 master_prohibitions·cash_floor·risk_block 완화 금지"
- "코어 65% 목표를 채우기 위해 위험 코어 종목을 무리하게 매수 금지"
- "위성 20% 목표를 채우기 위해 anti_climax_buy_gate·minimalist_buy_gate 통과 없이 진입 금지"
orbit_state_override_rule: # [proposal_70 / 2026-05-15] orbit_state가 target_allocation_structure add 트리거보다 항상 우선
purpose: "orbit_state_action_map이 target_allocation_structure의 add 트리거보다 항상 우선함을 명시."
override_rule:
unrealistic:
condition: "orbit_state = unrealistic"
action: "target_allocation_structure의 모든 add 트리거 무시. orbit_state_action_map.unrealistic 규칙(A등급 1건/월)이 최종 제한."
stretch:
condition: "orbit_state = stretch"
action: "tactical_satellite_bucket.add 트리거 발동 시에도 orbit_state_action_map.stretch 기준(A등급만, 주 최대 3건) 내에서만 실행."
achievable:
condition: "orbit_state = achievable"
action: "target_allocation_structure 버킷 트리거 정상 발동. override 없음."
priority_order:
"1": "orbit_state_action_map (최상위)"
"2": "target_allocation_structure (하위 지침)"
prohibition:
- "orbit_state=unrealistic 상태에서 버킷 add 트리거만으로 신규 매수 집행 금지"
- "orbit_state 확인 없이 버킷 트리거 실행 금지"
# ── [2026-05-21_CLA_HARNESS_V1] 반도체 클러스터 상태 분리 ───────────────────
cluster_states:
purpose: >
CLA(CONCENTRATED_LEADER_ADVANCE) 레짐 발동 시 반도체 클러스터의 기존보유 유지(HOLD)와
신규추가매수(BUY)를 분리해 엔진의 '리더 팔고 위성 추가매수' 오판을 구조적으로 차단한다.
CLUSTER_OPEN:
description: "기본 상태 (CLA 레짐 비발동). 반도체 O2 섹터 기본 25% 상한 적용."
trigger: "market_regime != CLA"
new_buy_allowed: true
cap_pct: 25
harness_field: cluster_state
harness_value: "CLUSTER_OPEN"
CLUSTER_HOLD_ONLY:
description: >
CLA 레짐 발동 시 클러스터 상태. 기존 보유분 HOLD는 허용.
신규 BUY는 RAG_V1=PASS AND cluster_combined_pct < 60% 조건 모두 충족 시만 허용.
O2 25% 상한 임시 해제 — CLA 해제 시 즉시 복귀.
trigger: "market_regime == CLA"
hold_allowed: true
new_buy_conditions:
- rag_v1: PASS
- cluster_combined_pct_max: 60
new_buy_blocked_action: HOLD
cap_pct: 60
harness_field: cluster_state
harness_value: "CLUSTER_HOLD_ONLY"
regime_based_o2_rule:
rule: >
O2 반도체 섹터 상한은 cluster_state=CLUSTER_OPEN 에서 기본 25%,
SECULAR_LEADER_RISK_ON 에서 35%, cluster_state=CLUSTER_HOLD_ONLY 에서 60%까지 적용한다.
cluster_state=CLUSTER_HOLD_ONLY 에서는 기존 보유분이 25% 초과해도 강제매도 없음.
신규 추가매수는 RAG_V1 통과 + 60% 상한 적용.
original_o2: "spec/03_risk_policy.yaml:semiconductor_total_cap"
cla_override: "CLA 발동 시 O2 적용 범위를 CLUSTER_OPEN 상태로 한정"
prohibition:
- "CLA 레짐에서 코어 반도체 직접보유를 현금확보 1순위로 선정 금지"
- "cluster_state 필드 없이 반도체 종목 SELL 판단 금지"
- "CLUSTER_HOLD_ONLY 상태를 LLM이 임의로 CLUSTER_OPEN으로 변경 금지"
# ── [P0-1.1 / governance/todo/v8_9_p0_adoption_plan.yaml] v8.9 제안 신규 cap 필드 ──
# 배경: v8.9 제안서(suggest/quant_investment_engine_v8_9...)는 단일종목·top3 cap을 제시했으나
# 기존 spec에는 이름 지정 예외(삼성전자/SK하이닉스 spec/05_position_sizing.yaml,
# 반도체 클러스터 spec/10_portfolio_rules.yaml)만 있고 "이름 없는 일반 종목"의
# 기본 상한과 top3 합산 상한이 없었다. 기존 이름 지정 예외를 덮어쓰지 않고
# 비어있던 두 칸만 채운다.
concentration_caps_v8_9_supplement:
note: >
이 항목은 기존 regime/cluster_state 연동 cash_floor·반도체 cap을 대체하지 않는다.
spec/05_position_sizing.yaml의 삼성전자(soft 45%/hard 48%)·SK하이닉스(soft 22%/hard 25%)
named exception과 spec/risk/portfolio_exposure.yaml:target_allocation_structure.
tactical_satellite_bucket.concentration_rule(단일 위성 7%)이 항상 우선한다.
default_single_stock_cap_pct:
applies_when: "named exception(삼성전자·SK하이닉스 등 spec/05_position_sizing.yaml) 또는 위성 7% 규칙이 없는 종목"
soft_cap_pct: 15
hard_cap_pct: 20
over_cap_action: "no_additional_buy; evaluate partial_trim_or_core_ETF_transition_after_tax_cost"
top3_combined_cap_pct:
definition: "포트폴리오 내 비중 상위 3개 종목(직접보유, named exception 포함)의 합산 비중"
soft_cap_pct: 50
hard_cap_pct: 65
over_cap_action: "no_additional_buy_increasing_concentration; transition_optimizer가 신규 매수 후보를 hard_constraint_fail로 거부"
source_proposal: suggest/quant_investment_engine_v8_9_portfolio_optimizer_canonical_refactored.yaml:portfolio_policy_v8_9.concentration_limits
cash_floor: # ── 구조 수정: duplicate_exposure_rule 자식(4칸) → portfolio_exposure_framework 직속(2칸) (2026-05-14)
normal: "총자산 7~10%"
overheated_or_event_week: "총자산 10~15%"
risk_off: "총자산 15~25%"
rule: >
cash_floor는 immediate_cash + eligible_settlement_cash_d2 (즉시현금 + D+2 정산예정현금)을 현금 방어선으로 준수하되, 계좌 범위와 제한을 엄격히 적용한다.
일반계좌의 D+2 현금은 cash_defense_eligible=true로 인정하며 일반계좌의 immediate_cash와 합산하여 방어선으로 취급한다.
ISA/연금저축 계좌의 D+2 및 즉시현금은 일반계좌 신규매수 재원으로 합산하는 것을 금지한다.
cash_shortfall 계산 로그에는 immediate_cash, settlement_cash_d2, restricted_cash를 명확히 분리 출력한다.
settlement_rule: "일반계좌의 즉시현금 + D+2 정산현금을 유동성 방어선(cash_floor) 및 매수 가능 자금의 원장으로 인정한다."
buying_power_rule: "매수가능현금 = (일반계좌 즉시현금 + D+2 정산현금) - 예약된 주문금액."
numeric_definitions:
settlement_cash_ratio: "D+2 정산현금 / 총자산 × 100"
total_cash_ratio: "D+2 정산현금 / 총자산 × 100"
buy_power_ratio: "(D+2 정산현금 - 예약된 주문금액) / 총자산 × 100"
post_trade_total_cash_ratio: "(D+2 정산현금 - 신규매수예상금액 + 매도대금정산분) / 총자산 × 100"
regime_numbers:
normal:
min_cash_ratio: 7
target_cash_ratio: 10
overheated_or_event_week:
min_cash_ratio: 10
target_cash_ratio: 15
risk_off:
min_cash_ratio: 15
target_cash_ratio: 25
rebalancing_formula:
buy_allowed_when: "buy_power_ratio >= target_cash_ratio + rebalancing_buy_ratio AND post_trade_total_cash_ratio >= min_cash_ratio"
trim_required_when: "post_trade_total_cash_ratio < min_cash_ratio OR buy_power_ratio < rebalancing_buy_ratio"
policy_event_week_escalation:
base_condition: "미중 정상회담·FOMC·CPI/PCE·고용·금통위·지정학 이벤트가 해당 주에 예정됨"
raise_to_12pct_if_any: ["USD/KRW 1450원 초과", "VIX 18 초과", "KOSPI/KOSDAQ 장중 고점 대비 -2% 이상", "SOXX -4% 이상 하락", "외국인 KOSPI 일간 순매도 1조원 이상 또는 5D 누적 순매도"]
raise_to_15pct_if_any: ["USD/KRW 1500원 돌파", "VIX 25 이상", "정책 이벤트 결과가 관세·희토류·반도체 규제·호르무즈 중 2개 이상 악화", "KOSPI 20일선 종가 이탈"]
execution_priority: ["중복 ETF", "손실 중 약한 위성", "유동성 낮은 테마 ETF", "코어 직접보유"]
required_output: ["현재 즉시현금비중", "D+2 추정현금성자산", "매수가능현금", "목표 즉시현금비중", "리밸런싱 후 최소 즉시현금비중", "추가 필요 현금", "매도 후보별 예상 순현금", "실행 후 즉시현금비중"]
# ── [2026-05-18_ROUTING_OPTIMIZATION_V1] 팩터 과집중 수치 임계치 ─────────────
# 배경: 포트폴리오.yaml 원칙에 "고베타·고모멘텀 과집중 차단"이 추가됐으나
# "얼마가 과한 것인가?"에 대한 수치 기준이 없어 AI가 주관적 판단에 의존.