#!/usr/bin/env python3
"""
SignalGenerator 基类
所有策略信号生成器必须继承此基类，实现标准接口
"""
from abc import ABC, abstractmethod


class BaseSignalGenerator(ABC):
    """
    信号生成器基类

    实现规范：
      1. analyze() 只读 df（K线数据），不感知账户/持仓/配置
      2. 返回标准 Signal dict（带 schema_version + trace_id）
      3. get_params_schema() 供 Hyperopt 调用
    """

    SCHEMA_VERSION = "2.1.0"

    @abstractmethod
    def analyze(self, bars: list, params: dict) -> dict:
        """
        分析市场并生成信号

        输入：
            bars: list[dict], K线数据
                  [{"time", "open", "high", "low", "close", "tick_volume"}, ...]
            params: dict, 策略参数
                  {
                      "ema_short": 9,
                      "ema_long": 21,
                      "ema50": 50,
                      "rsi_period": 14,
                      "macd_fast": 12,
                      "macd_slow": 26,
                      "atr_period": 14,
                      ...
                  }

        输出：标准 Signal dict
            {
                "schema_version": "2.1.0",
                "trace_id": str,
                "strategy_id": str,        # 例如 "ema_macd_v2"
                "model_version": None,     # 有ML时为模型版本，无则为None
                "timestamp": str,
                "payload": {
                    "action": "BUY" | "SELL" | "HOLD",
                    "confidence": float,    # 0.0 ~ 1.0
                    "reason": str,
                    "indicators": dict,
                    # 以下字段仅在 action != "HOLD" 时有效
                    "side": "BUY" | "SELL",
                    "entry": float,
                    "sl": float,
                    "tp": float,
                }
            }
        """
        pass

    @abstractmethod
    def get_params_schema(self) -> dict:
        """
        返回参数定义，供 Hyperopt 调用

        输出：
            dict: 参数名 -> 参数定义
            {
                "ema_short": {"type": "int", "default": 9, "range": [5, 20]},
                "ema_long": {"type": "int", "default": 21, "range": [15, 50]},
                ...
            }
        """
        pass

    def get_strategy_id(self) -> str:
        """返回策略标识符，子类覆盖"""
        return self.__class__.__name__
