# source: https://raw.githubusercontent.com/huckhuck12/freqtrade-futures-lab/40a97470897a3ebfe2853eca7586a325598dc0f0/user_data/strategies/TrendEMAStopStrategy.py
from freqtrade.strategy import IStrategy
from pandas import DataFrame
import pandas as pd
import talib.abstract as ta
from datetime import datetime, timedelta
import numpy as np


class Github_huckhuck12_freqtrade_futures_lab__TrendEMAStopStrategy__20260122_145205(IStrategy):
    """
    趋势EMA止损策略

    核心逻辑：
    1. 趋势过滤：5EMA、20EMA、60EMA 排列 + ADX > 20
    2. 开仓：多头排列+RSI超卖做多；空头排列+RSI超买做空
    3. 止损止盈：2%止损、4%止盈（2:1盈亏比）
    4. 保本止损：盈利≥3%时移动止损至开仓价
    5. 风控：连续亏损5笔暂停
    """

    # ========== 基础参数 ==========
    timeframe = '5m'  # 5分钟K线，适合捕捉趋势
    max_open_trades = 3  # 最多同时持仓3个交易对
    startup_candle_count = 100  # 需要足够K线计算指标

    # 止盈止损设置
    minimal_roi = {
        "0": 0.20,  # ROI止盈20%，防止持仓太久
    }
    stoploss = -0.08  # 8%止损作为底线保护
    trailing_stop = False  # 不使用追踪止损

    # 订单类型
    order_types = {
        'entry': 'market',
        'exit': 'market',
        'stoploss': 'market',
        'stoploss_on_exchange': False
    }

    unfilledtimeout = {
        'entry': 60,
        'exit': 60,
        'unit': 'seconds'
    }

    # 杠杆配置
    leverage_config = {
        'BTC/USDT:USDT': 5.0,
        'ETH/USDT:USDT': 4.0,
        'SOL/USDT:USDT': 4.0,
        'XRP/USDT:USDT': 3.0,
        'DOGE/USDT:USDT': 3.0
    }

    # ========== 策略参数 ==========
    # 趋势过滤参数
    EMA_SHORT = 5
    EMA_MIDDLE = 20
    EMA_LONG = 60
    ADX_PERIOD = 14
    ADX_THRESHOLD = 20  # ADX > 20 表示趋势明确

    # RSI参数
    RSI_PERIOD = 14
    RSI_OVERSOLD = 35  # 超卖，做多信号
    RSI_OVERBOUGHT = 65  # 超买，做空信号

    # 止损止盈参数（点数，每个点10美元）
    STOP_LOSS_POINTS = 40
    TAKE_PROFIT_POINTS = 80
    BREAK_EVEN_POINTS = 50  # 盈利超过此点数时移动止损至开仓价

    # 风控参数
    MAX_CONSECUTIVE_LOSSES = 5  # 连续亏损5笔
    LOSS_PAUSE_HOURS = 1  # 暂停开仓1小时

    # ========== 风控状态 ==========
    def __init__(self, config: dict = {}):
        super().__init__(config)
        self.consecutive_losses = {}  # 每个交易对的连续亏损次数
        self.last_loss_time = {}  # 最后亏损时间
        self.trade_entry_prices = {}  # 记录每个交易的开仓价

    def informative_pairs(self) -> list:
        return []

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        df = dataframe.copy()

        # ========== 趋势指标 ==========
        # EMA组合
        df['ema_5'] = ta.EMA(df['close'], timeperiod=self.EMA_SHORT)
        df['ema_20'] = ta.EMA(df['close'], timeperiod=self.EMA_MIDDLE)
        df['ema_60'] = ta.EMA(df['close'], timeperiod=self.EMA_LONG)

        # ADX趋势强度
        df['adx'] = ta.ADX(df['high'], df['low'], df['close'], timeperiod=self.ADX_PERIOD)

        # RSI
        df['rsi'] = ta.RSI(df['close'], timeperiod=self.RSI_PERIOD)

        # ========== 趋势排列判断 ==========
        # 多头排列：5EMA > 20EMA > 60EMA
        df['bullish_trend'] = (df['ema_5'] > df['ema_20']) & (df['ema_20'] > df['ema_60'])

        # 空头排列：5EMA < 20EMA < 60EMA
        df['bearish_trend'] = (df['ema_5'] < df['ema_20']) & (df['ema_20'] < df['ema_60'])

        # 趋势明确：ADX > 阈值
        df['strong_trend'] = df['adx'] > self.ADX_THRESHOLD

        # RSI超买超卖
        df['rsi_oversold'] = df['rsi'] < self.RSI_OVERSOLD
        df['rsi_overbought'] = df['rsi'] > self.RSI_OVERBOUGHT

        return df

    def leverage(self, pair: str, current_time: datetime, current_rate: float,
                 current_profit: float = 0.0, min_stops: float = 0.0,
                 max_stops: float = 0.0, current_time_rows: DataFrame = None,
                 **kwargs) -> float:
        """返回固定杠杆配置"""
        return self.leverage_config.get(pair, 3.0)

    def check_risk_controls(self, pair: str, current_time: datetime, current_rate: float) -> bool:
        """检查风控条件，返回是否允许开仓"""

        # 检查连续亏损
        if pair in self.consecutive_losses and self.consecutive_losses[pair] >= self.MAX_CONSECUTIVE_LOSSES:
            last_loss_time = self.last_loss_time.get(pair)
            if last_loss_time:
                pause_end_time = last_loss_time + timedelta(hours=self.LOSS_PAUSE_HOURS)
                if current_time < pause_end_time:
                    return False
                else:
                    self.consecutive_losses[pair] = 0

        return True

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        df = dataframe.copy()
        df['enter_long'] = 0
        df['enter_short'] = 0

        if len(df) < self.startup_candle_count:
            return df

        # ========== 多头开仓信号 ==========
        long_conditions = (
            # 趋势过滤
            df['bullish_trend'] &  # 多头排列
            df['strong_trend'] &  # 趋势明确
            # RSI超卖（适合做多）
            df['rsi_oversold']
        )

        df.loc[long_conditions, 'enter_long'] = 1

        # ========== 空头开仓信号 ==========
        short_conditions = (
            # 趋势过滤
            df['bearish_trend'] &  # 空头排列
            df['strong_trend'] &  # 趋势明确
            # RSI超买（适合做空）
            df['rsi_overbought']
        )

        df.loc[short_conditions, 'enter_short'] = 1

        return df

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        df = dataframe.copy()
        df['exit_long'] = 0
        df['exit_short'] = 0

        # 基础退出逻辑（由custom_exit处理）
        return df

    def custom_entry(self, pair: str, current_time: datetime, current_rate: float,
                     **kwargs) -> bool:
        """自定义开仓风控检查"""

        # 检查风控条件
        if not self.check_risk_controls(pair, current_time, current_rate):
            return False

        return True

    def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float,
                           time_in_force: str, current_time: datetime, **kwargs) -> bool:
        """开仓确认时记录开仓价格"""
        self.trade_entry_prices[pair] = rate
        return True

    def custom_exit(self, pair: str, current_time: datetime, current_rate: float,
                    current_profit: float, **kwargs) -> bool:
        """
        自定义退出逻辑

        止损止盈规则：
        1. 固定止损：2%
        2. 固定止盈：4%
        3. 保本止损：盈利≥3%时移动止损至开仓价
        """

        # 获取开仓价格
        entry_price = self.trade_entry_prices.get(pair)
        if entry_price is None:
            return False

        # 获取交易方向（从kwargs获取）
        is_short = kwargs.get('is_short', False)

        # 调整后的止盈止损百分比
        STOP_LOSS_PCT = 0.02  # 2%止损
        TAKE_PROFIT_PCT = 0.04  # 4%止盈
        BREAK_EVEN_PCT = 0.03  # 3%保本

        if is_short:
            # 空单止损：价格上涨2%
            if current_profit < -STOP_LOSS_PCT:
                self.record_loss(pair, current_time)
                return True

            # 空单止盈：价格下跌4%
            if current_profit > TAKE_PROFIT_PCT:
                return True

            # 空单保本止损：盈利≥3%且价格回到开仓价附近
            if current_profit > BREAK_EVEN_PCT and current_profit < 0.01:
                # 如果价格回到开仓价附近（±0.5%），触发保本止损
                if abs(current_profit) < 0.005:
                    return True
        else:
            # 多单止损：价格下跌2%
            if current_profit < -STOP_LOSS_PCT:
                self.record_loss(pair, current_time)
                return True

            # 多单止盈：价格上涨4%
            if current_profit > TAKE_PROFIT_PCT:
                return True

            # 多单保本止损：盈利≥3%且价格回到开仓价附近
            if current_profit > BREAK_EVEN_PCT and current_profit < 0.01:
                # 如果价格回到开仓价附近（±0.5%），触发保本止损
                if abs(current_profit) < 0.005:
                    return True

        return False

    def record_loss(self, pair: str, current_time: datetime):
        """记录亏损，用于连续亏损风控"""
        if pair not in self.consecutive_losses:
            self.consecutive_losses[pair] = 0

        self.consecutive_losses[pair] += 1
        self.last_loss_time[pair] = current_time

    def confirm_trade_exit(self, pair: str, order_type: str, amount: float, rate: float,
                          time_in_force: str, exit_reason: str, current_time: datetime,
                          **kwargs) -> bool:
        """平仓确认时清理状态"""
        if pair in self.trade_entry_prices:
            del self.trade_entry_prices[pair]
        return True
