meta: title: "은퇴자산포트폴리오 — 손절 정책" parent_file: "spec/06_exit_policy.yaml" version: "2026-05-15-F12_split" language: "ko-KR" timezone: "Asia/Seoul" role: "canonical" migration_status: "canonical_split_active" # ───────────────────────────────────────────────────────────────────────────── # 매도 신호 전체 우선순위 계층 (P1-B / 2026-05-17 추가) # calcSellDecision_()이 이 순서로 평가한다. 상위 조건이 성립하면 하위 조건 무시. # ───────────────────────────────────────────────────────────────────────────── sell_signal_priority: purpose: > 여러 매도 신호가 동시에 발생할 때 어느 신호를 최우선으로 처리할지 결정한다. 신호 충돌 시 "undefined behavior" 방지가 목적. levels: 1_hard_stop: condition: "timingAction == STOP_OR_TIME_EXIT_READY OR rw_partial >= 4" action: "EXIT_100 — 전량 즉시 청산" gas_field: "Sell_Action=EXIT_100, Sell_Reason=STOP_OR_TIME_EXIT_READY|RW_EXIT_STRONG" 2_risk_off_regime: condition: "REGIME_PRELIM == RISK_OFF OR RISK_OFF_CANDIDATE (포지션 보유 시)" action: "REGIME_TRIM_50 — 50% 단계 축소" gas_field: "Sell_Action=REGIME_TRIM_50, Sell_Reason=REGIME_RISK_OFF|REGIME_RISK_OFF_CANDIDATE" note: "hard_stop이 없는 경우에만 적용. 전량 청산이 아닌 단계적 축소." # ── REGIME_TRIM_50 발동 시 sell_priority_engine 의무 실행 ──────────────── # spec: spec/risk/portfolio_exposure.yaml:sell_priority_engine # REGIME_TRIM_50은 '포트폴리오 레벨' 신호 — 어떤 종목에 적용할지는 sell_priority_engine이 결정한다. # 개별 종목 내부 신호(level 3~7)로 대상 종목을 임의 선택하는 것은 이 신호의 용도를 오용하는 것. mandatory_next_step: rule: > REGIME_TRIM_50 발동 즉시 sell_priority_engine을 실행하고 sell_priority_decision_table을 출력한 후 상위 tier 종목에만 TRIM 적용. sell_priority_order: "①하드스탑 → ②매도신호 → ③중복ETF → ④손실위성 → ⑥익절후보 → ⑨코어주도주(마지막)" gas_endpoint: "?view=sell_priority (runSellPriority() 함수)" prohibition: - "sell_priority_decision_table 없이 TRIM 대상 종목을 직접 지정 금지" - "상승추세 중인 반도체 주도주(SK하이닉스·삼성전자)를 REGIME_TRIM_50 1차 대상으로 선정 금지" - "ETF 중복노출 종목이 있는데 코어주도주를 먼저 TRIM하는 행위 금지" 2b_rw2b_fast_track: # [2026-05-18_ADVANCED_EXIT_V2] 5D 조기약세 fast track condition: "RW2b_5d_rapid_weakness == 1 AND rw_partial_excluding_rw2b >= 1" action: "TRIM_50 — 50% 선제 부분 청산 (fast_track)" gas_field: "Sell_Action=TRIM_50, Sell_Reason=RW2B_FAST_TRACK" priority_note: "2번(RISK_OFF)과 3번(rw_partial>=3) 사이 삽입. RISK_OFF 없을 때만 발동." 3_rw_signals: condition: "rw_partial >= 3 OR timingExitScore >= 75" action: "TRIM_70 — 70% 부분 청산" gas_field: "Sell_Action=TRIM_70, Sell_Reason=RW_EXIT|TIMING_EXIT_SCORE" 4_trailing_stop: condition: "trailingStopPrice 이탈 OR (rw_partial >= 2) OR (rw_partial >= 1 AND timingExitScore >= 50)" action: "TRIM_50 — 50% 부분 청산. rw_partial=0 + 기술지표만으로는 TRIM_50 불가 → EXIT_REVIEW 강등." gas_field: "Sell_Action=TRIM_50" 5_take_profit_ladder: condition: "Profit_Pct >= 10 (TP1/TP2 도달)" action: "TAKE_PROFIT_TIER1 — 25% 익절" gas_field: "Sell_Action=TAKE_PROFIT_TIER1|PROFIT_TRIM_*" 6_time_stop: condition: "Days_To_Time_Stop <= 0" action: "TIME_EXIT_100 — time stop 만료 전량 청산" gas_field: "Sell_Action=TIME_EXIT_100, Sell_Reason=TIME_STOP_EXPIRED" 7_scheduled_review: condition: "분기 정기점검 (수동 검토)" action: "사람이 결정. 자동 신호 없음." prohibition: - "우선순위 높은 신호 무시하고 낮은 신호로 재해석 금지" - "신호 충돌 시 '관망'으로 모호하게 처리 금지 — 항상 최고 우선순위 신호 적용" # ───────────────────────────────────────────────────────────────────────────── # timingExitScore 산출 공식 (calcTimingDecision_ 내 exitScore) — 2026-05-17 v2 # ───────────────────────────────────────────────────────────────────────────── timing_exit_score_formula: version: "v2-2026-05-17" purpose: > 매도 타이밍 강도 점수. 0~100 범위. thresholds: 50=EXIT_REVIEW, 75=STOP_OR_TIME_EXIT_READY. v1 대비 변경: RW 가중치 상향(20→25), 기술지표 가중치 하향(18→10). 이유: 기술지표(RSI, 이격도, MA20) 단독 신호의 오신호율(30~40%)을 억제하고 수급 기반 RW(상대약세)의 실증적 신뢰도를 반영. components: rw_partial: weight: 25 # 구: 20. 수급 기반 — 외국인·기관 이탈 확인, 신뢰도 높음 max: 100 # rwPartial × 25, cap=100 example: "RW=2 → 50pt (EXIT_REVIEW 단독 도달)" exit_signal_tokens: weight: 10 # 구: 18. 기술지표(VOL_EXHAUSTION/MA20_BREAK/DISPARITY_TOP/RSI_OVERBOUGHT) — 노이즈 多 note: "RW=0 + 기술신호 4개 = 40pt → 임계값 미달. RW=1 이상 있어야 TRIM_50 발동." time_stop_near: condition: "daysToTimeStop >= 0 AND <= 7" points: 20 # 구: 25 profit_protect_zone: condition: "profitPct >= 10" points: 15 # 구: 10. 실현 이익 보호 중요도 상향. thresholds: EXIT_REVIEW: 50 STOP_OR_TIME_EXIT_READY: 75 sell_price_formula: v2: "close - ATR20 × 0.3 (변동성 비례 보호 하한). ATR 없으면 close × 0.995 폴백." v1_deprecated: "close × 0.998 (0.2% — 변동성 무시, 사실상 시가 매도)" trailing_stop_breach: "trailingStop 가격 직접 사용. min(trailingStop, close×0.998) 적용 금지." stop_loss: principle: "손절가·손절수량·잔여수량·재진입 조건을 함께 제시" priority_matrix: # [proposal_75 / 2026-05-15] 복수 손절 조건 동시 발동 시 최종 HTS 지정가 결정 purpose: "동일 종목에 trailing_stop·MA20·relative_weakness_exit·time_stop 4개 조건이 동시 발동 시 최종 손절가 결정 규칙" priority_order: "1_time_stop": "보유기간 초과 → 매도 시간 강제. 가격보다 시간 우선." "2_relative_weakness_exit": "RW >= 4 상대약세 → 70~100% 청산 목표가" "3_trailing_stop": "고점 대비 trailing_stop% 하락가" "4_MA20_break": "종가 MA20 하향 이탈가" final_price_rule: "복수 조건 동시 충족 시 → max(time_stop_price, RW_exit_price, trailing_stop_price, MA20_price) 중 가장 높은(보수적인) 값을 최종 손절가로 설정" quantity_rule: "최종 손절가 결정 후, 청산 수량은 상위 우선순위 조건의 청산 비율 적용 (time_stop: 100%, RW>=4: 70~100%, RW=3: 30~50%)" output_requirement: "블록4 플레이북에 [손절조건] 열에 발동 조건명과 최종가 계산 근거 명시" prohibition: - "복수 조건 중 더 완화된(낮은) 손절가 선택 금지" - "조건 간 충돌을 이유로 손절 전면 보류 금지" core: # [P131] ATR 기준 우선. % 기준은 ATR 미확인 시 fallback # [Q2 / 2026-05-15] "1.5~2.0배" 범위 표현이 HTS 입력 시 어느 값인지 모호해 # LLM이 2.0배 적용 또는 임의 중간값 산출하는 착오 방지. hts_entry_formula를 canonical로 고정. primary_rule: "HTS 입력 canonical: max(진입가 × 0.92, 진입가 − ATR20 × 1.5). 1.5배 고정." extended_rule: "ATR20_Pct >= 8%(고변동성 종목)인 경우에만 ATR20 × 2.0배 허용. 이 경우 hts_entry_formula에서 1.5 → 2.0으로 교체." atr_pct_definition: "ATR20_Pct = ATR20 / 현재가 × 100. 8% 기준은 일별 평균 변동폭이 주가의 8%를 초과함을 의미." fallback_rule: "ATR20 미산출 시에만 매수가 -8% 단일 고정값 (DATA_MISSING 표시)" hts_entry_formula: "max(진입가 × 0.92, 진입가 − ATR20 × 1.5)" quantity_rule: "트리거 발생 시 50% 손절, 종가 회복 실패 시 잔여 50%" prohibition: - "ATR20 미확인 시 -7~-10% 범위 임의 선택 금지. -8% 고정 또는 DATA_MISSING." - "ATR 기준 손절가와 % 기준이 다르면 더 높은 값(보수적) 채택." - "ATR20_Pct < 8%인 일반 종목에 2.0배 적용 금지. extended_rule 조건 미충족 시 1.5배만." satellite: # [P131] 위성 ATR 기준 primary_rule: "20일 ATR 2.0배 이탈 기준" fallback_rule: "ATR20 미산출 시 매수가 -12% 고정" quantity_rule: "트리거 발생 시 70%, 종가 회복 실패 시 잔여 30%" emergency: "60일선 이탈·실적쇼크·회계·거래정지 리스크는 전량 가능" legacy_position_protocol: # [P147] 사후 뒷북 손절 방지 — 기존 포지션 처리 원칙 detection_rule: # [R5] 레거시 포지션 식별 기준 primary: "capture_read_ledger 판독 결과에서 해당 종목의 stop_price 필드가 0이거나 누락" secondary: "performance_evidence 로그에 진입 당시 손절가 기록이 없는 포지션" output_tag: "[레거시포지션] 표기 필수. 신규 ATR 손절가 자동 할당 금지." condition: "진입 당시 손절가가 미설정된 기존 포지션" prohibition: "사후 ATR 손절 기계 적용 금지. 20일선 이탈·수급 악화·time_stop 기준 중 하나로만 청산." damaged_position: condition: "현재 손실률 -10% 이상" action: "시장가 투매 금지. 반등 매도(1차 30~50%) / time_stop 청산 / 논리 훼손 손절 중 택1." xref: "stop_loss.gap_down.principle, stop_loss.time_stop" gap_down: principle: "손절가 아래 갭하락 시 09:00~09:15 전량 시장가 매도 금지. 첫 15~30분 저가·거래대금·회복 여부 기록." sea_timing_integration: # [2026-05-19_ALPHA_SHIELD_APEX_V2] SEA001 rule: > 장중 갭하락 또는 급락 시 즉시 투매 금지. SEA_TIMING_V1 공식을 호출하여 현재가가 VWAP을 하향 돌파하거나 15분 RSI가 과매도(30 미만) 구간에서 반등하는 'Exit Window'를 찾아 분할 매도한다. action: "VWAP 하향 돌파 확인 시 TRIM 실행. RSI < 30 구간에서는 반등 시까지 유예." high_beta_exception: "고베타 위성은 -5% 이상 갭하락 + 거래대금 300% 이상 폭증 동시 확인 시 50% 우선 축소 가능." flow: "외국인·기관 5D 동반 순매도 경고, 20D 수급 이탈 축소" time_stop: direction_absent_definition: "20일선 ±2% 박스권 + 거래대금 감소가 10거래일 이상 지속" core: "60거래일 경과 시 thesis 재검증. 유지 근거 없으면 50% 이상 청산 검토." satellite: "30거래일 방향성 없음이면 30% 축소 검토, 60거래일이면 잔여 청산 검토." prohibition: "데이터로 확인된 thesis 개선 없이 time_stop 연기 금지." reentry: basic_condition: "20일선 회복 + 거래대금 증가 + 수급 회복 + 기대수익비 2:1 이상 회복" cooling_off: default: "최소 5거래일 — 일반 기술적 손절(손절가 하회, 수급 이상 없음)" flow_exit: "10거래일 — 수급 이탈 손절(Flow_OK=N 판정). 재진입 시 Flow_OK=Y 재확인 필수." system_risk_exit: "거래일 제한 없음 — unified_engine Tier 발동 후 손절. VIX < 25 AND KOSPI 20일선 회복 확인 시에만 재진입 허용." double_stop: "60거래일 Watch-only — 동일 종목 30거래일 내 2회 손절" cooling_priority_rule: "손절 원인이 복합적이면 더 긴 쿨다운 적용. system_risk_exit > double_stop > flow_exit > default 순." prohibition: "손절 다음 날 반등 또는 손실만회 목적 재매수 금지." output_examples: "_reference: output_format.unified_example_row_set # [R6] 통합 예시 집합 참조" executable_rules: field_dictionary_ref: "spec/12_field_dictionary.yaml:field_dictionary" formula_refs: stop_price_core: "spec/13_formula_registry.yaml:formula_registry.formulas.STOP_PRICE_CORE_V1" trailing_stop_price: "spec/13_formula_registry.yaml:formula_registry.formulas.TRAILING_STOP_PRICE_V1" rules: - id: "SL001_CORE_STOP_PRICE" applies_to: "core" inputs: ["entry_price", "atr20", "current_price"] formula_ref: "STOP_PRICE_CORE_V1" output_fields: ["stop_price", "stop_quantity"] quantity_rule: "floor(quantity * 0.50)" on_missing: "NO_STOP_PRICE_OR_DATA_MISSING_FALLBACK" - id: "SL002_SATELLITE_STOP_PRICE" applies_to: "satellite" inputs: ["entry_price", "atr20", "quantity"] expression: "entry_price - atr20 * 2.0" fallback_expression: "entry_price * 0.88" output_fields: ["stop_price", "stop_quantity"] quantity_rule: "floor(quantity * 0.70)" on_missing: "fallback_expression with DATA_MISSING tag" - id: "SL003_PRIORITY_MATRIX" applies_to: "all_positions" inputs: ["time_stop_price", "relative_weakness_exit_price", "trailing_stop_price", "ma20_break_price"] expression: "max(available_trigger_prices)" output_field: "final_stop_price" quantity_source: "highest_priority_trigger" on_missing: "ignore missing trigger price; if all missing then NO_STOP_PRICE" - id: "SL004_REENTRY_COOLDOWN" applies_to: "stopped_out_position" inputs: ["exit_reason", "last_exit_date", "current_trade_date"] rules: - {if: "exit_reason == 'system_risk_exit'", min_wait_trading_days: 0, extra_condition: "VIX < 25 AND KOSPI close > KOSPI_MA20"} - {if: "exit_reason == 'double_stop'", min_wait_trading_days: 60} - {if: "exit_reason == 'flow_exit'", min_wait_trading_days: 10} - {if: "exit_reason == 'default'", min_wait_trading_days: 5} output_field: "reentry_allowed" on_fail: "WATCH_ONLY" # [proposal_53 / 2026-05-15] 상대강도 약화 매도 규칙 — relative_weakness_exit relative_weakness_exit: purpose: > 손실 발생 여부와 무관하게 상대강도 약화 시 선제 교체 매도. 기회비용 손실을 방지하고 강한 종목·섹터로 자금을 이동한다. applicable_to: "위성(satellite) 포지션 전체. 코어는 asymmetric_winner_rule 우선." check_frequency: "주간 정기점검(수요일) + 월간 전체 검토" weakness_signals: RW1_sector_rank_drop: # [proposal_71 / 2026-05-15] 주간 독립 판정 명시 formula: "sector_flow.Rotation_Score 순위가 2주 연속 3순위 이상 하락" score: 1 check_frequency: "주간 정기점검(수요일)마다 실행. 월별 Tier 갱신 주기와 독립적으로 판정." data_source: "sector_priority_ranking.Rotation_Score — 매주 수요일 기준 섹터 순위 비교." RW2_relative_underperformance: formula: "Ret10D_종목 - Ret10D_주도섹터ETF <= -5%p" score: 1 RW2b_5d_rapid_weakness: # [2026-05-18_ADVANCED_EXIT_V2] 5D 조기 상대약세 경보 formula: "Ret5D_종목 - Ret5D_주도섹터ETF <= -5%p (5거래일 단기 상대 열위)" score: 1 purpose: > RW2(10D 기준)보다 2배 빠른 조기경보. 단기 자본 회전 기회비용 손실을 선제 포착한다. 섹터가 상승 중임에도 종목만 뒤처질 때 즉각 감지. data_source: "Ret5D_Stock (당일 기준 5거래일 수익률), Ret5D_주도섹터ETF (대표 섹터 Proxy ETF)" fast_track_exit: condition: "RW2b_score == 1 AND (RW1 OR RW3 OR RW4) 중 1개 이상 = 1 (합계 >= 2)" action: "TRIM_50 — 일반 RW>=3 조건 충족 전에도 조기 부분 청산" rationale: > 5D 급격한 상대 약세 + 다른 수급/섹터 신호 1개면 추세 이탈 초기 국면. RW>=4(70~100%) 기다리지 않고 50% 선제 정리로 기회비용 차단. prohibition: - "RW2b 단독(1개)으로 fast_track 발동 금지 — 반드시 다른 RW 신호 1개 이상 필요" - "fast_track 발동 시 당일 동일 섹터 다른 종목 즉시 매수 금지" note: "RW2(10D)와 RW2b(5D) 동시 발동 시 score 중복 합산 금지 — max(RW2, RW2b)=1 적용" RW3_flow_deterioration: formula: "Frg_5D < 0 AND Inst_5D < 0 (2주 연속 동반 순매도)" score: 1 RW4_volume_fade: formula: "AvgTradeValue_5D_M <= AvgTradeValue_20D_M × 0.60" meaning: "거래대금 20일 평균 대비 60% 미만으로 감소 (관심 소멸)" score: 1 RW5_ma_breach: formula: "Close < MA20 AND Close < MA60 (20일선·60일선 동시 하회)" score: 1 exit_rule: four_or_more: "RW1+RW2+RW3+RW4+RW5 >= 4 → 70~100% 청산. 지정가 분할." three: "합계 == 3 → 50% 부분 청산 검토. 다음 점검일까지 재확인." two_or_less: "합계 <= 2 → 유지" fast_track_note: > # [2026-05-18_ADVANCED_EXIT_V2] RW2b_5d_rapid_weakness가 포함된 합계 >= 2 시 fast_track_exit.TRIM_50 발동. RW2b 없이 일반 RW 합계 <= 2는 기존대로 유지. output_table: columns: ["종목명", "RW1", "RW2", "RW3", "RW4", "RW5", "합계", "판정", "청산비율(%)", "이동대상"] pyramiding_interaction: # [proposal_66 / 2026-05-15] RW >= 4와 pyramiding 증액분 청산 순서 purpose: > RW 신호 합계 >= 4 발동 시 pyramiding 증액분을 먼저 청산한 후 나머지 70% 기준을 달성하는 순서를 고정한다. execution_sequence: step_1_pyramiding_first: condition: "RW >= 4 AND 해당 종목에 pyramiding 증액분 보유" action: "pyramiding 2차 증액분 → 1차 증액분 순으로 전량 우선 청산 (지정가 분할, 역순)" rationale: "가장 늦게 진입한 수량이 가장 먼저 나온다 (단계 역순 원칙)" step_2_check_70pct: condition: "증액분 청산 후 총 청산률 70% 도달 여부 확인" if_below_70: action: "stage_2 확인매수 수량도 추가 청산. 총 청산 70% 충족 시 중단." if_above_70: action: "증액분만으로 70% 충족. stage_1·2 잔여 수량 유지." step_3_no_pyramiding: condition: "RW >= 4 AND pyramiding 증액분 없음" action: "기존 exit_rule 그대로 적용 (70~100% 청산)" prohibition: - "단계 역순을 무시하고 평단가 최저 수량부터 먼저 청산 금지" pyramiding_exit_quantity_formula: # [proposal_78 / 2026-05-15] pyramiding 물량 × RW 청산 수량 정확 계산 purpose: "pyramiding 단계별 물량(원물량+1차+2차)과 RW 부분청산 비율 적용 시 정확한 수량 계산 공식" formula: step_1: "총보유량 = 원물량(A) + 1차증액(B) + 2차증액(C)" step_2: "청산목표주 = floor(총보유량 × 청산비율) [정수 절사 필수]" step_3: "청산 순서: C(2차증액) 우선 → B(1차증액) → A(원물량) 역순" step_4: "누적 청산주 >= 청산목표주 도달 시 중단. 잔여는 다음 단계에서 계속 보유." rate_by_rw: RW_3: "청산비율 30~50% (원칙: 40%). stage_1 탐색 종목은 50% 우선 적용." RW_4plus: "청산비율 70~100% (원칙: 80%). 단, A_core 등급 종목은 70% 상한." example: holdings: "원물량 50주(A) + 1차증액 30주(B) + 2차증액 20주(C) = 총 100주" RW_3_40pct: "목표 40주. C 20주 전량 → B에서 20주. 합계 40주 청산." RW_4_80pct: "목표 80주. C 20주 → B 30주 → A에서 30주. 합계 80주 청산." output_requirement: "블록4 플레이북에 [단계별 청산 수량] 테이블 출력 필수" prohibition: - "청산 순서 역으로(A 먼저) 청산 금지" - "소수점 청산 수량 산출 금지 — floor 정수 처리 필수" prohibition: - "수익 중 종목이라도 RW >= 4이면 청산 강행 (수익 보호 명목 청산 연기 금지)" - "청산 자금을 당일 즉시 다른 종목 매수에 투입 금지 (take_profit.redeployment_rule 준수)" # ── [2026-05-18_FINANCIAL_HEALTH_V1] 재무 Thesis 훼손 매도 트리거 ────────── # 수급·기술 신호와 독립적으로 재무 펀더멘털이 악화될 때 발동. # 특히 중장기(30~60거래일) 보유 코어·위성 모두 해당. fundamental_thesis_break: purpose: > 진입 당시의 투자 thesis(실적 성장, 수익성 유지)가 재무 데이터로 부정될 때 수급 강세 여부와 무관하게 청산 또는 비중 축소를 강제한다. "주가는 오르는데 재무는 무너지고 있다"는 함정을 방지한다. check_frequency: "분기 실적 발표 직후 + 월간 전체 검토" applicable_to: "코어·위성 모두 적용. ETF는 해당 없음." triggers: FTB1_roe_collapse: condition: > roe_pct 전분기 대비 50% 이상 급락 (예: ROE 20%→8% = 60% 하락) AND 현재 ROE < 10% severity: "HIGH" action: "TRIM_50 — 비중 50% 축소. 다음 분기 발표까지 재확인." rationale: "ROE 급락은 수익성 구조 훼손 신호. 수급 강세로 가려질 수 있음." FTB2_margin_to_loss: condition: "operating_margin_pct 양수→음수 전환 (영업이익 흑자→적자)" severity: "HIGH" action: "EXIT_70 — 70% 즉시 청산. 영업적자 종목 보유 원칙 위반." rationale: > 영업적자 전환은 thesis_break 가장 강한 신호. stock_model.reject 조건 '적자 지속+테마성 급등'의 조기 포착. FTB3_debt_spike: condition: > debt_to_equity가 전기 대비 2배 이상 급증 AND 현재 debt_to_equity > 200% (금융업 제외) severity: "MEDIUM" action: "TRIM_30 — 30% 비중 축소. 자금 조달 구조 점검 필요." rationale: "부채 급증은 희석·유동성 위기 선행 지표." FTB4_fcf_chronic_negative: condition: "FCF_B < 0 연속 2분기 이상 AND debt_to_equity > 150%" severity: "MEDIUM" action: "EXIT_REVIEW — 다음 점검일까지 thesis 재검토. 수급 이상 없으면 TRIM_30." rationale: "FCF 만성 음수 + 고부채 = 현금 고갈 위험." interaction_with_rw: rule: > FTB 트리거 + RW 신호 동시 발동 시 둘 중 더 강한 청산 비율 적용. FTB2(영업적자 EXIT_70)가 RW3(TRIM_50)보다 강하면 EXIT_70 실행. data_vintage_rule: rule: > 분기 실적 발표일로부터 90일 이상 경과한 재무 데이터는 STALE 취급. FTB 트리거 발동 전 재무 데이터 최신성 확인 필수. stale_action: "FTB 적용 보류. DATA_STALE_FTB 태그 출력 후 다음 발표일 이후 재확인." missing_policy: financial_data_missing: > 재무 데이터 미제공 시 FTB 트리거 적용 금지. 단, FTB 적용 불가 이유를 보고서에 명시: "[FTB불가: 재무데이터 미확인]" prohibition: - "재무 데이터 미확인 상태에서 FTB 이유로 임의 청산 금지" - "FTB 트리거 없이 재무 '우려'만으로 전량 시장가 청산 금지" - "영업이익이 있는 종목에 FTB2(적자 전환) 적용 금지" - "1회성 특별손실(일회성 비용)을 영업적자로 오판하여 FTB2 발동 금지" output_table_columns: ["종목명", "FTB_트리거", "현재ROE(%)", "영업이익률(%)", "D/E", "FCF방향", "심각도", "조치", "데이터최신성"]