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방향", "심각도", "조치", "데이터최신성"]

