#!/usr/bin/env python3
"""
build_p3_01_stop_loss_taxonomy.py
────────────────────────────────────────────────────────────────────────
P3_01: 손절 체계 재정의 — ABSOLUTE_RISK_STOP vs RELATIVE_ALERT 분리

문제 진단:
  기존: "시장대비 10% 빠지면 매도" → 목적 불명확
  실제: (1) 절대 리스크 스탑 + (2) 상대성과 경보 혼합

해결:
  1. ABSOLUTE_RISK_STOP_V1: ATR 기반 절대 하방 캡
  2. RELATIVE_UNDERPERFORMANCE_ALERT_V1: 강도 약화 신호 (로테이션용)

출력:
  - Temp/p3_01_stop_taxonomy_spec.json
  - Temp/p3_01_implementation_plan.json
"""

from __future__ import annotations

import json
import sys
from pathlib import Path
from datetime import datetime

ROOT = Path(__file__).resolve().parent.parent

OUTPUT_SPEC = ROOT / "Temp" / "p3_01_stop_taxonomy_spec.json"
OUTPUT_PLAN = ROOT / "Temp" / "p3_01_implementation_plan.json"

if sys.stdout.encoding and sys.stdout.encoding.lower() not in ("utf-8", "utf8"):
    sys.stdout = open(sys.stdout.fileno(), mode="w", encoding="utf-8", buffering=1)


def build_stop_taxonomy() -> dict:
    """손절 체계 정의."""
    spec = {
        "schema_version": "stop_loss_taxonomy_v1",
        "generated_at": datetime.now().isoformat(),
        "root_cause": "절대 리스크(자본보호)와 상대강도(기회비용)를 혼합 → 손절 논리 불명확",
        "diagnosis": {
            "issue_1": "절대 스탑 없이 상대 로테이션만 사용 → 시장 폭락 시 -30% 출혈 가능",
            "issue_2": "지정가와 수량 규칙 없음 → HTS 입력 불가능 (HS007)",
            "issue_3": "비호가 가격 사용 → TICK_NORMALIZER 통과 실패 (HS008)",
            "issue_4": "상대성과만으로 전량 청산 → 기회비용 최악 (회복 불가)"
        },
        "taxonomy": {
            "ABSOLUTE_RISK_STOP_V1": {
                "purpose": "자본 하방 보호 (항상 1순위)",
                "target": "손실을 ATR/퍼센트 캡으로 제한",
                "formula_core": "max(entry*0.92, entry - ATR20*1.5)",
                "formula_core_note": "ATR20_Pct >= 8%면 *2.0으로 확대",
                "formula_satellite": "entry - ATR20*2.0",
                "formula_satellite_fallback": "entry*0.88",
                "order_method": "지정가 (갭하락 시 09:00~09:15 시장가 금지)",
                "quantity_rule": "3단계: 50% 즉시 + 50% 나머지",
                "sample_prices": {
                    "entry": 100000,
                    "atr20": 2000,
                    "core_stop": 98000,
                    "core_stop_pct": "-2.0%",
                    "satellite_stop": 96000,
                    "satellite_stop_pct": "-4.0%"
                },
                "implementation": "spec/exit/stop_loss.yaml:ABSOLUTE_RISK_STOP_V1"
            },
            "RELATIVE_UNDERPERFORMANCE_ALERT_V1": {
                "purpose": "기회비용 관리 (로테이션) — 손절매 아님",
                "target": "강도 약화 신호 포착 → 신규 매수 차단 or 일부 trim",
                "formula": "excess_ret_20d <= min(-10, rel_threshold_pct)",
                "excess_ret_20d": "ret_stock_20d - beta_adj * ret_market_20d",
                "rel_threshold_pct": "-clip(1.5 * sigma20_pct, 6, 18)",
                "confirmation": "2영업일 연속 종가 확인 (단발 노이즈 차단)",
                "action_ladder": {
                    "WATCH": "alert만 충족 → 신규매수 금지, 보유 유지",
                    "TRIM_30": "alert + [수급이탈|섹터순위하락|MA20이탈] 중 1개 → 30% 지정가",
                    "TRIM_50": "alert + 확인조건 2개↑ OR 절손 <=-20% → 50% 분할매도",
                    "EXIT_100": "하드스탑|회계위험|거래정지 → 전량 하네스 지정방식"
                },
                "sample_trigger": {
                    "stock_ret_20d": "0%",
                    "market_ret_20d": "5%",
                    "excess_ret": "-5% (시장 수익 미달)",
                    "beta_adj_threshold": "-10% (기준)",
                    "trigger": "YES"
                },
                "implementation": "spec/exit/stop_loss.yaml:RELATIVE_UNDERPERFORMANCE_ALERT_V1"
            },
            "FUNDAMENTAL_THESIS_BREAK_V1": {
                "purpose": "재무 위험 (ROE 붕괴, FCF 악화 등)",
                "independent": "절대/상대 스탑과 독립 평가",
                "implementation": "spec/exit/stop_loss.yaml:FUNDAMENTAL_THESIS_BREAK_V1"
            }
        },
        "mandatory_fields": {
            "stop_trigger": "[price, qty, order_method, reason] 4필드 강제",
            "price_normalization": "TICK_NORMALIZER_V1 통과 필수 (HS008)",
            "multi_condition": "다중조건 접속사 금지: '또는', '실패 시' (HS007)",
            "single_relative_exit_100": "상대성과만으로 EXIT_100 금지"
        }
    }
    return spec


def build_implementation_plan() -> dict:
    """구현 계획."""
    plan = {
        "phase": "P3_01_STOP_LOSS_TAXONOMY_FIX",
        "priority": "P0",
        "files_to_update": [
            "spec/exit/stop_loss.yaml",
            "spec/13_formula_registry.yaml",
            "gas_data_feed.gs (함수 3개 신규)",
            "tools/validate_stop_loss_policy_v1.py (신규)"
        ],
        "tasks": [
            {
                "task_id": "P3_01_A",
                "title": "stop_loss.yaml 리팩토링",
                "steps": [
                    "ABSOLUTE_RISK_STOP_V1 섹션 신규 생성",
                    "RELATIVE_UNDERPERFORMANCE_ALERT_V1 섹션 신규 생성",
                    "기존 '시장대비 N%' 문구 → ALERT로 강등",
                    "모든 트리거에 [price, qty, method, reason] 4필드 명시"
                ],
                "acceptance": {
                    "stop_policy_ambiguous_phrase_count": 0,
                    "stop_action_has_price_qty_method_reason": True,
                    "relative_only_full_liquidation_count": 0
                }
            },
            {
                "task_id": "P3_01_B",
                "title": "formula_registry에 3개 공식 등록",
                "steps": [
                    "ABSOLUTE_RISK_STOP_V1 formula_id 등록",
                    "RELATIVE_UNDERPERFORMANCE_ALERT_V1 formula_id 등록",
                    "FUNDAMENTAL_THESIS_BREAK_V1 formula_id 등록",
                    "execution_order에 포함 (active=true)"
                ],
                "acceptance": {
                    "formula_count": 3,
                    "execution_order_included": True
                }
            },
            {
                "task_id": "P3_01_C",
                "title": "GAS 함수 구현",
                "functions": [
                    "calcAbsoluteRiskStopV1_(): entry, atr20, pct → stop_price",
                    "calcRelativeUnderperfAlertV1_(): ret_stock, ret_market → alert_flag",
                    "calcStopActionLadderV1_(): alert + conditions → action (WATCH/TRIM/EXIT)"
                ],
                "file": "gas_data_feed.gs",
                "acceptance": {
                    "function_count": 3,
                    "gated_to_datasheet": True
                }
            },
            {
                "task_id": "P3_01_D",
                "title": "검증 도구 구현",
                "file": "tools/validate_stop_loss_policy_v1.py",
                "checks": [
                    "gap_down 프로토콜: 09:00~09:15 시장가 투매 금지",
                    "TICK_NORMALIZER_V1: 모든 지정가 통과",
                    "multi-condition: 접속사 금지",
                    "single-relative EXIT_100: 금지"
                ],
                "acceptance": {
                    "validation_pass": True,
                    "violations": 0
                }
            }
        ],
        "risk_mitigation": [
            "기존 '시장대비 N%' 로직은 ALERT로만 사용 (전량 청산 금지)",
            "ABSOLUTE_RISK_STOP은 매우 항상 1순위 (코어 손절)",
            "상대성과는 신규 매수만 차단 (보유 포지션은 허용)"
        ],
        "rollout": {
            "phase_1": "spec/exit/stop_loss.yaml 리팩토링 + formula_registry 등록",
            "phase_2": "GAS 함수 구현 + 데이터 전송",
            "phase_3": "analysis_prompt.md 업데이트 (LLM 지침)",
            "phase_4": "실전 신호 검증 (3건 이상)"
        }
    }
    return plan


def main() -> int:
    print("=" * 80)
    print("  P3_01: 손절 체계 재정의 — ABSOLUTE vs RELATIVE 분리")
    print("=" * 80)

    # 스펙 생성
    spec = build_stop_taxonomy()
    OUTPUT_SPEC.write_text(
        json.dumps(spec, ensure_ascii=False, indent=2),
        encoding="utf-8"
    )
    print(f"\n✓ 손절 분류 스펙 저장: {OUTPUT_SPEC.name}")
    print(f"  분류: {len(spec['taxonomy'])}개 (ABSOLUTE, RELATIVE, FUNDAMENTAL)")

    # 구현 계획
    plan = build_implementation_plan()
    OUTPUT_PLAN.write_text(
        json.dumps(plan, ensure_ascii=False, indent=2),
        encoding="utf-8"
    )
    print(f"✓ 구현 계획 저장: {OUTPUT_PLAN.name}")
    print(f"  파일 업데이트: {len(plan['files_to_update'])}")
    print(f"  태스크: {len(plan['tasks'])}")

    # 진단 요약
    print(f"\n[문제 진단]")
    for i, issue in enumerate(spec['diagnosis'].values(), 1):
        print(f"  {i}. {issue}")

    print(f"\n[3가지 손절 메커니즘]")
    for name, detail in spec['taxonomy'].items():
        print(f"  • {name}")
        print(f"    → {detail['purpose']}")

    print(f"\n[다음 액션]")
    for task in plan['tasks'][:2]:
        print(f"  {task['task_id']}: {task['title']}")

    return 0


if __name__ == "__main__":
    sys.exit(main())
