"""
ATR策略模块 - 基于平均真实波幅(ATR)的动态止损止盈策略
"""
import logging
from typing import Optional, Dict, Tuple
try:
    from . import config
    from .indicators import TechnicalIndicators
except ImportError:
    import config
    from indicators import TechnicalIndicators

logger = logging.getLogger(__name__)


class ATRStrategy:
    """ATR策略类 - 基于ATR的动态止损止盈计算"""
    
    def __init__(self):
        """初始化ATR策略"""
        self.use_atr = config.TRADING_CONFIG.get('USE_ATR_STOP_LOSS', True)
        self.atr_sl_multiplier = config.TRADING_CONFIG.get('ATR_STOP_LOSS_MULTIPLIER', 2.5)  # 默认2.5，放宽止损提升胜率
        self.atr_tp_multiplier = config.TRADING_CONFIG.get('ATR_TAKE_PROFIT_MULTIPLIER', 1.5)
        self.risk_reward_ratio = config.TRADING_CONFIG.get('RISK_REWARD_RATIO', 1.5)
        self.atr_period = config.TRADING_CONFIG.get('ATR_PERIOD', 14)
        
        # 动态调整ATR倍数的参数
        self.use_dynamic_atr_multiplier = config.TRADING_CONFIG.get('USE_DYNAMIC_ATR_MULTIPLIER', False)
        self.atr_multiplier_min = config.TRADING_CONFIG.get('ATR_MULTIPLIER_MIN', 1.5)
        self.atr_multiplier_max = config.TRADING_CONFIG.get('ATR_MULTIPLIER_MAX', 2.5)

    def _refresh_from_config(self) -> None:
        """
        动态刷新配置（重要：配置页修改后希望立即生效）。
        之前这些参数只在 __init__ 时读取，会导致“改了配置但策略仍按旧值运行”。
        """
        try:
            cfg = getattr(config, "TRADING_CONFIG", {}) or {}
            self.use_atr = bool(cfg.get('USE_ATR_STOP_LOSS', True))
            self.atr_sl_multiplier = float(cfg.get('ATR_STOP_LOSS_MULTIPLIER', 2.5))  # 默认2.5，放宽止损提升胜率
            self.atr_tp_multiplier = float(cfg.get('ATR_TAKE_PROFIT_MULTIPLIER', 1.5))
            self.risk_reward_ratio = float(cfg.get('RISK_REWARD_RATIO', 1.5))
            self.atr_period = int(cfg.get('ATR_PERIOD', 14))
            self.use_dynamic_atr_multiplier = bool(cfg.get('USE_DYNAMIC_ATR_MULTIPLIER', False))
            self.atr_multiplier_min = float(cfg.get('ATR_MULTIPLIER_MIN', 1.5))
            self.atr_multiplier_max = float(cfg.get('ATR_MULTIPLIER_MAX', 2.5))
        except Exception:
            # 刷新失败则继续使用旧值（不影响下单流程）
            return
    
    def calculate_stop_loss(
        self,
        entry_price: float,
        side: str,
        atr: Optional[float] = None,
        atr_percent: Optional[float] = None,
        volatility: Optional[float] = None
    ) -> Tuple[Optional[float], Optional[float], Dict]:
        """
        计算基于ATR的止损价格
        
        Args:
            entry_price: 入场价格
            side: 方向 'BUY' 或 'SELL'
            atr: ATR绝对值（可选，如果提供则直接使用）
            atr_percent: ATR百分比（可选，如果提供则直接使用，否则从atr计算）
            volatility: 市场波动率（可选，用于动态调整ATR倍数）
            
        Returns:
            (止损价格, 止损距离, 详细信息字典)
        """
        self._refresh_from_config()
        if not self.use_atr:
            return None, None, {}
        
        # 如果没有提供ATR，无法计算
        if atr is None and atr_percent is None:
            logger.debug("ATR不可用，无法计算ATR止损")
            return None, None, {}
        
        # 计算ATR百分比（如果未提供）
        if atr_percent is None and atr is not None and entry_price > 0:
            atr_percent = atr / entry_price
        
        if atr_percent is None or atr_percent <= 0:
            logger.debug("ATR百分比无效，无法计算ATR止损")
            return None, None, {}
        
        # 动态调整ATR倍数（根据市场波动率）
        if self.use_dynamic_atr_multiplier and volatility is not None:
            # 波动率越高，ATR倍数越大（更宽松的止损）
            # 波动率范围假设：0.01-0.10 (1%-10%)
            volatility_factor = min(max((volatility - 0.01) / 0.09, 0), 1)  # 归一化到0-1
            dynamic_multiplier = (
                self.atr_multiplier_min + 
                (self.atr_multiplier_max - self.atr_multiplier_min) * volatility_factor
            )
            atr_multiplier = dynamic_multiplier
            logger.debug(f"动态ATR倍数: 波动率={volatility:.4f}, 倍数={atr_multiplier:.2f}")
        else:
            atr_multiplier = self.atr_sl_multiplier
        
        # 计算止损距离（基于ATR百分比）
        stop_distance_percent = atr_percent * atr_multiplier
        
        # 计算止损价格
        if side == 'BUY':  # 做多，止损价低于入场价
            stop_loss_price = entry_price * (1 - stop_distance_percent)
            stop_distance = entry_price - stop_loss_price
        else:  # 做空，止损价高于入场价
            stop_loss_price = entry_price * (1 + stop_distance_percent)
            stop_distance = stop_loss_price - entry_price
        
        details = {
            'atr': atr,
            'atr_percent': atr_percent,
            'atr_multiplier': atr_multiplier,
            'stop_distance_percent': stop_distance_percent,
            'stop_distance': stop_distance,
            'method': 'ATR动态止损'
        }
        
        # 格式化ATR显示
        atr_display = f"{atr:.4f}" if atr is not None and atr > 0 else "N/A"
        
        logger.info(
            f"ATR止损计算 ({side}): "
            f"ATR={atr_display}, "
            f"ATR%={atr_percent*100:.2f}%, "
            f"倍数={atr_multiplier:.2f}, "
            f"止损距离={stop_distance_percent*100:.2f}%, "
            f"止损价={stop_loss_price:.4f}"
        )
        
        return stop_loss_price, stop_distance, details
    
    def calculate_take_profit(
        self,
        entry_price: float,
        side: str,
        stop_distance: Optional[float] = None,
        atr: Optional[float] = None,
        atr_percent: Optional[float] = None,
        use_risk_reward_ratio: bool = True
    ) -> Tuple[Optional[float], Optional[float], Dict]:
        """
        计算基于ATR的止盈价格
        
        Args:
            entry_price: 入场价格
            side: 方向 'BUY' 或 'SELL'
            stop_distance: 止损距离（价格差，可选，如果提供则基于盈亏比计算）
            atr: ATR绝对值（可选）
            atr_percent: ATR百分比（可选）
            use_risk_reward_ratio: 是否使用盈亏比（True：基于止损距离×盈亏比，False：基于ATR倍数）
            
        Returns:
            (止盈价格, 止盈距离, 详细信息字典)
        """
        self._refresh_from_config()
        if not self.use_atr:
            return None, None, {}
        
        # 方法1：基于止损距离和盈亏比计算（优先）
        if use_risk_reward_ratio and stop_distance is not None and stop_distance > 0:
            take_profit_distance = stop_distance * self.risk_reward_ratio
            
            if side == 'BUY':  # 做多，止盈价高于入场价
                take_profit_price = entry_price + take_profit_distance
            else:  # 做空，止盈价低于入场价
                take_profit_price = entry_price - take_profit_distance
            
            details = {
                'stop_distance': stop_distance,
                'risk_reward_ratio': self.risk_reward_ratio,
                'take_profit_distance': take_profit_distance,
                'method': 'ATR止损距离×盈亏比'
            }
            
            logger.info(
                f"ATR止盈计算 ({side}, 基于盈亏比): "
                f"止损距离={stop_distance:.4f}, "
                f"盈亏比={self.risk_reward_ratio:.1f}, "
                f"止盈距离={take_profit_distance:.4f}, "
                f"止盈价={take_profit_price:.4f}"
            )
            
            return take_profit_price, take_profit_distance, details
        
        # 方法2：基于ATR倍数计算（备选）
        if atr is None and atr_percent is None:
            logger.debug("ATR不可用，无法计算ATR止盈")
            return None, None, {}
        
        # 计算ATR百分比（如果未提供）
        if atr_percent is None and atr is not None and entry_price > 0:
            atr_percent = atr / entry_price
        
        if atr_percent is None or atr_percent <= 0:
            logger.debug("ATR百分比无效，无法计算ATR止盈")
            return None, None, {}
        
        # 计算止盈距离（基于ATR百分比）
        take_profit_distance_percent = atr_percent * self.atr_tp_multiplier
        
        # 计算止盈价格
        if side == 'BUY':  # 做多，止盈价高于入场价
            take_profit_price = entry_price * (1 + take_profit_distance_percent)
            take_profit_distance = take_profit_price - entry_price
        else:  # 做空，止盈价低于入场价
            take_profit_price = entry_price * (1 - take_profit_distance_percent)
            take_profit_distance = entry_price - take_profit_price
        
        details = {
            'atr': atr,
            'atr_percent': atr_percent,
            'atr_multiplier': self.atr_tp_multiplier,
            'take_profit_distance_percent': take_profit_distance_percent,
            'take_profit_distance': take_profit_distance,
            'method': 'ATR倍数止盈'
        }
        
        # 格式化ATR显示
        atr_display = f"{atr:.4f}" if atr is not None and atr > 0 else "N/A"
        
        logger.info(
            f"ATR止盈计算 ({side}, 基于ATR倍数): "
            f"ATR={atr_display}, "
            f"ATR%={atr_percent*100:.2f}%, "
            f"倍数={self.atr_tp_multiplier:.2f}, "
            f"止盈距离={take_profit_distance_percent*100:.2f}%, "
            f"止盈价={take_profit_price:.4f}"
        )
        
        return take_profit_price, take_profit_distance, details
    
    def calculate_atr_levels(
        self,
        entry_price: float,
        side: str,
        atr: Optional[float] = None,
        atr_percent: Optional[float] = None,
        volatility: Optional[float] = None
    ) -> Dict:
        """
        计算完整的ATR止损止盈方案
        
        Args:
            entry_price: 入场价格
            side: 方向 'BUY' 或 'SELL'
            atr: ATR绝对值（可选）
            atr_percent: ATR百分比（可选）
            volatility: 市场波动率（可选）
            
        Returns:
            包含止损、止盈等信息的字典
        """
        result = {
            'use_atr': self.use_atr,
            'entry_price': entry_price,
            'side': side,
            'stop_loss_price': None,
            'stop_loss_distance': None,
            'take_profit_price': None,
            'take_profit_distance': None,
            'risk_reward_ratio': None,
            'details': {}
        }
        
        if not self.use_atr:
            return result
        
        # 计算止损
        stop_loss_price, stop_distance, stop_details = self.calculate_stop_loss(
            entry_price, side, atr, atr_percent, volatility
        )
        
        if stop_loss_price is None:
            return result
        
        result['stop_loss_price'] = stop_loss_price
        result['stop_loss_distance'] = stop_distance
        result['details']['stop_loss'] = stop_details
        
        # 计算止盈（基于止损距离和盈亏比）
        take_profit_price, take_profit_distance, tp_details = self.calculate_take_profit(
            entry_price, side, stop_distance, atr, atr_percent, use_risk_reward_ratio=True
        )
        
        if take_profit_price is not None:
            result['take_profit_price'] = take_profit_price
            result['take_profit_distance'] = take_profit_distance
            result['risk_reward_ratio'] = (
                take_profit_distance / stop_distance if stop_distance > 0 else None
            )
            result['details']['take_profit'] = tp_details
        
        return result
    
    @staticmethod
    def calculate_atr_from_klines(
        klines: list,
        period: int = 14
    ) -> Tuple[Optional[float], Optional[float], Optional[float]]:
        """
        从K线数据计算ATR和ATR百分比
        
        Args:
            klines: K线数据列表，格式为 [open, high, low, close, ...]
            period: ATR计算周期，默认14
            
        Returns:
            (ATR绝对值, ATR百分比, 当前价格)
        """
        if not klines or len(klines) < period + 1:
            return None, None, None
        
        try:
            high_prices = [float(k[2]) for k in klines]  # high
            low_prices = [float(k[3]) for k in klines]   # low
            close_prices = [float(k[4]) for k in klines]  # close
            
            current_price = close_prices[-1] if close_prices else None
            
            atr = TechnicalIndicators.calculate_atr(high_prices, low_prices, close_prices, period)
            
            if atr is None or current_price is None or current_price <= 0:
                return None, None, None
            
            atr_percent = atr / current_price
            
            return atr, atr_percent, current_price
            
        except (IndexError, ValueError, TypeError) as e:
            logger.debug(f"从K线计算ATR失败: {e}")
            return None, None, None
