5166750b53
2026-06-21 비판적 리뷰에서 spec/governance YAML이 코드 상태와 어긋난 채로 방치되던 3개 구체적 사례를 발견하고 정정했다. 근본 원인(동기화를 보장하는 장치 없음)에 대응하는 신규 CI 게이트도 함께 추가한다. - spec/aliases.yaml: deprecated alias 17건 제거(활성 참조 0건 확인 후, 2026-06-30 데드라인 전). role: deprecated_redirect인 spec/03_risk_policy.yaml, spec/04_strategy_rules.yaml 2개만 실삭제 — spec/06_exit_policy.yaml은 role: compatibility_index(영구유지 설계)였음을 재확인해 보존 - governance/gas_logic_migration_ledger_v1.yaml: 존재하지 않는 파일을 canonical 구현으로 인용하던 오류 2건 발견·정정, parity 테스트 부재로 GAS 코드 삭제 보류(F12/F13/F14) - spec/13_formula_registry.yaml: OVERHANG_PRESSURE_V1의 "-500000" 절대값 폴백을 avg_volume_5d 비례식으로 교체(EXPERT_PRIOR 등록) - tools/validate_specs.py: validate_spec_code_sync() 신규 — has_code_implementation/ code_path 필드가 있는 spec만 검사(점진적 롤아웃, 기존 PASS 상태 비파괴), 12개 파일 1차 태깅
156 lines
8.8 KiB
YAML
156 lines
8.8 KiB
YAML
meta:
|
|
title: "은퇴자산포트폴리오 — 포트폴리오 노출·현금 정책 분할 후보"
|
|
parent_file: "RetirementAssetPortfolio.yaml" # 2026-06-22 WBS-7.11: spec/03_risk_policy.yaml 삭제로 갱신
|
|
version: "2026-05-16-F9_secular_leader"
|
|
language: "ko-KR"
|
|
timezone: "Asia/Seoul"
|
|
role: "canonical"
|
|
migration_status: "canonical_split_active"
|
|
authority_rule: "이 split 파일이 해당 섹션의 canonical source다. parent_file은 legacy compatibility index다."
|
|
|
|
|
|
factor_risk_management:
|
|
factor_risk_limit:
|
|
purpose: >
|
|
포트폴리오 전체의 팩터 집중도를 수치로 통제한다.
|
|
개별 종목 리스크 게이트(Total_Heat, stop_loss)와 직교하는
|
|
포트폴리오 레벨 팩터 가드레일이다.
|
|
portfolio_beta:
|
|
formula_ref: "spec/13_formula_registry.yaml:formula_registry.formulas.PORTFOLIO_BETA_V1"
|
|
warning_threshold: 1.2
|
|
hard_cap: 1.3
|
|
action_warning: >
|
|
PORTFOLIO_BETA >= 1.2 → 보고서에 [팩터경보: 포트폴리오 베타 상승] 출력.
|
|
신규 위성 매수 시 고베타(Beta >= 1.5) 종목 추가 검토 신중.
|
|
action_hard_cap: >
|
|
PORTFOLIO_BETA >= 1.3 → 고베타(Beta >= 1.5) 신규 위성 매수 보류.
|
|
기존 고베타 위성은 RW 점수 우선 재점검.
|
|
missing_policy: "Beta 미확인 종목 제외 후 산출. 제외 비중 > 30% 시 PARTIAL 표기."
|
|
single_stock_beta:
|
|
high_beta_threshold: 1.5
|
|
treatment: >
|
|
Beta >= 1.5 종목은 trailing_stop ATR 배수 1.8배 적용
|
|
(take_profit.trailing_stop.high_beta_leader 준용).
|
|
very_high_beta_threshold: 2.0
|
|
action_very_high: >
|
|
Beta >= 2.0 위성은 최대 보유 기간 20거래일 이내로 제한.
|
|
time_stop.satellite 기준 단축 적용.
|
|
momentum_concentration:
|
|
definition: "직전 20거래일 수익률(Ret20D) 기준 상위 2개 종목의 포트폴리오 비중 합산"
|
|
warning_threshold: "상위 2종목 합산 비중 >= 50%"
|
|
hard_cap: "상위 2종목 합산 비중 >= 60%"
|
|
action_warning: "보고서에 [모멘텀 집중 경보] 출력. 신규 고모멘텀 종목 추가 자제."
|
|
action_hard_cap: "상위 종목 중 약한 쪽(RW 점수 높은 쪽)의 비중 5%p 축소 검토."
|
|
sector_beta_concentration:
|
|
definition: "단일 섹터에 Beta >= 1.5 종목이 2개 이상이고 합산 비중 >= 25%"
|
|
action: "해당 섹터 고베타 중 RW 점수 낮은 종목 먼저 비중 조정."
|
|
calculation_frequency: "주간 정기점검(수요일) 및 신규 매수 직전"
|
|
output_table:
|
|
columns: ["항목", "현재값", "경보임계치", "하드캡", "상태", "조치"]
|
|
rows:
|
|
- ["포트폴리오 베타", "[PORTFOLIO_BETA_V1]", "1.2", "1.3", "[OK/경보/차단]", ""]
|
|
- ["모멘텀 집중도(상위2종목비중)", "[산출]", "50%", "60%", "[OK/경보/차단]", ""]
|
|
- ["섹터 고베타 집중", "[산출]", "—", "25%", "[OK/차단]", ""]
|
|
prohibition:
|
|
- "PORTFOLIO_BETA 미산출 상태에서 고베타 신규 위성 추가 허용 금지"
|
|
- "Beta 미확인을 이유로 팩터 리스크 점검 전체를 생략 금지 (부분 산출 PARTIAL로 진행)"
|
|
- "팩터 과집중 경보를 이유로 core 주도주(삼성전자·SK하이닉스) 우선 축소 금지"
|
|
|
|
|
|
position_count_limit:
|
|
id: "PCL_PORTFOLIO_EXPOSURE_ENFORCEMENT"
|
|
canonical_ref: "spec/01_objective_profile.yaml:position_count_limit"
|
|
purpose: >
|
|
포트폴리오 노출 레이어에서 계좌별 종목 수 상한을 집행한다.
|
|
계좌 성격이 다르므로 통합 합산 한도는 두지 않는다.
|
|
연금저축은 ETF 전용 계좌 — 개별주 카운트 완전 제외.
|
|
counting_rule:
|
|
include: "개별주 직접 보유 (코어 + 위성)"
|
|
exclude: ["ETF", "국내상장 해외ETF", "MMF", "RP", "단기채 ETF", "현금성 상품"]
|
|
pension_scope: "연금저축 전체 제외 — ETF 전용 계좌"
|
|
enforcement:
|
|
PCL001_TAXABLE_HARD_BLOCK:
|
|
condition: "taxable_individual_count >= 10"
|
|
action: "ROTATE_REQUIRED (일반계좌)"
|
|
output: >
|
|
일반계좌 개별주 10종목 도달. 신규 매수 제안 시 교체 후보 1종목 이상 명시.
|
|
교체 후보 선정 기준: financial_health_score 최저 → RW 점수 최고 → 보유 기간 최장.
|
|
PCL002_TAXABLE_CAUTION:
|
|
condition: "taxable_individual_count == 9"
|
|
action: "CAUTION_FLAG (일반계좌)"
|
|
output: "일반계좌 9종목. 신규 매수 전 포트폴리오 전체 검토 권고."
|
|
PCL003_ISA_HARD_BLOCK:
|
|
condition: "isa_individual_count >= 4"
|
|
action: "ROTATE_REQUIRED (ISA)"
|
|
output: "ISA 개별주 4종목 도달. 신규 매수 시 교체 후보 명시."
|
|
PCL004_ISA_CAUTION:
|
|
condition: "isa_individual_count == 3"
|
|
action: "CAUTION_FLAG (ISA)"
|
|
output: "ISA 3종목. 추가 진입 전 검토 권고."
|
|
PCL005_SATELLITE_ROTATION_REVIEW:
|
|
condition: "satellite_count >= 3 AND new_buy_target_bucket == satellite"
|
|
action: "SATELLITE_ROTATION_REVIEW"
|
|
output: >
|
|
위성 3종목 이상 보유 중 추가 위성 진입 검토 시
|
|
financial_health_score 가장 낮은 기존 위성 종목을 교체 후보로 우선 표시.
|
|
output_table:
|
|
columns: ["계좌", "현재 개별주 수", "경보", "하드차단", "상태"]
|
|
rows:
|
|
- ["일반계좌", "[taxable_individual_count]", "9종목", "10종목 이상", "[PASS/CAUTION/ROTATE_REQUIRED]"]
|
|
- ["ISA", "[isa_individual_count]", "3종목", "4종목 이상", "[PASS/CAUTION/ROTATE_REQUIRED]"]
|
|
- ["연금저축", "카운트 제외", "—", "—", "ETF 전용"]
|
|
prohibition:
|
|
- "PCL 미집계 상태에서 신규 매수 수량 출력 금지"
|
|
- "ETF를 개별주 카운트에 포함해 한도 여유 있는 것처럼 계산 금지"
|
|
- "연금저축 ETF를 개별주로 오분류해 카운트 금지"
|
|
- "종목 수 초과를 이유로 손절 기준 미도달 종목 강제 매도 금지"
|
|
|
|
tactical_cash_buffer:
|
|
amount: "총자산의 5% 고정 (방어용 cash_floor와 완전 별개)"
|
|
purpose: "VIX 30 이상 돌파 또는 KOSPI 1일 -4% 이상 폭락 시에만 집행 가능한 긴급 실탄"
|
|
activation_trigger:
|
|
vix_shock: "VIX >= 30 돌파 확인 (macro 탭 VIX_Close 기준)"
|
|
kospi_crash: "KOSPI 전일 대비 Ret1D <= -4%"
|
|
execution_rule:
|
|
- "A등급 주도주 중 낙폭 과대 종목 한정"
|
|
- "1~2회 분할 지정가 투입"
|
|
- "cash_floor 충족 상태에서만 사용 가능"
|
|
prohibition:
|
|
- "일상적 물타기·평단 낮추기 용도 사용 금지"
|
|
- "B등급 이하 또는 관찰 중 종목 사용 금지"
|
|
- "activation_trigger 미발동 시 사용 금지"
|
|
- "cash_floor와 합산하여 운용 금지. 버퍼는 별도 현금 계선으로 관리."
|
|
|
|
executable_rules:
|
|
field_dictionary_ref: "spec/12_field_dictionary.yaml:field_dictionary"
|
|
formula_refs:
|
|
cash_ratios: "spec/13_formula_registry.yaml:formula_registry.formulas.CASH_RATIOS_V1"
|
|
portfolio_band_status: "spec/13_formula_registry.yaml:formula_registry.formulas.PORTFOLIO_BAND_STATUS_V1"
|
|
rules:
|
|
- id: "PE001_CASH_RATIOS"
|
|
inputs: ["immediate_cash", "settlement_cash", "reserved_order_amount", "planned_buy_amount", "sell_cash_proceeds_immediate", "total_asset"]
|
|
formula_ref: "CASH_RATIOS_V1"
|
|
output_fields: ["immediate_cash_ratio", "settlement_cash_ratio", "buy_power_cash", "buy_power_ratio", "post_trade_immediate_cash_ratio"]
|
|
on_missing: "NO_CASH_CHECK"
|
|
- id: "PE002_CASH_FLOOR_GATE"
|
|
inputs: ["post_trade_immediate_cash_ratio", "min_cash_ratio", "buy_power_ratio"]
|
|
rules:
|
|
- {if: "post_trade_immediate_cash_ratio < min_cash_ratio", action: "BUY_BLOCKED_TRIM_REQUIRED"}
|
|
- {if: "post_trade_immediate_cash_ratio >= min_cash_ratio", action: "CASH_GATE_PASS"}
|
|
output_field: "cash_floor_status"
|
|
on_missing: "BUY_BLOCKED_NO_CASH_CHECK"
|
|
- id: "PE003_TARGET_BUCKET_BAND"
|
|
inputs: ["current_weight_pct", "target_band_min_pct", "target_band_max_pct"]
|
|
formula_ref: "PORTFOLIO_BAND_STATUS_V1"
|
|
output_field: "portfolio_band_status"
|
|
on_missing: "DATA_MISSING_NO_ADD_TRIM_DECISION"
|
|
- id: "PE004_DUPLICATE_EXPOSURE"
|
|
inputs: ["same_sector_etf_weight_pct", "single_stock_sector_weight_pct", "etf_purity_ratio"]
|
|
derived_field:
|
|
duplicate_exposure_pct: "same_sector_etf_weight_pct * etf_purity_ratio + single_stock_sector_weight_pct"
|
|
rules:
|
|
- {if: "duplicate_exposure_pct >= 20", action: "ETF_STAGED_REDUCTION_REQUIRED"}
|
|
- {if: "duplicate_exposure_pct < 20", action: "DUPLICATE_EXPOSURE_PASS"}
|
|
output_field: "duplicate_exposure_status"
|
|
on_missing: "DATA_MISSING_REVIEW"
|