# source: https://raw.githubusercontent.com/xxxx443117/freqtrade-up/9821eb0834160dbd0a1d0d288b0eb590ad2f3862/strategies/SupportResistanceStrategy/SupportResistanceStrategy.py
# 导入Freqtrade策略基类和所需函数
from freqtrade.strategy import IStrategy, merge_informative_pair, stoploss_from_open
from pandas import DataFrame
import numpy as np

class Github_xxxx443117_freqtrade_up__SupportResistanceStrategy__20250705_101410(IStrategy):
    """
    支撑阻力策略：
    基于支撑/阻力位进行交易，当价格突破支撑/阻力位时，进行交易。
    """
    # 支撑位
    # 使用15分钟周期
    timeframe = '15m'

    # 使用1小时周期
    timeframe = '1h'
    # 允许做空
    can_short: bool = True
    # 设置固定止损为1%（注意Freqtrade用负值表示，例如-0.01相当于价格波动-1%）
    stoploss = -0.03
    # 不使用默认的ROI获利了结
    minimal_roi = {"0": 1e10}  # 设定一个极大值以形同无穷大，表示不主动止盈，仅依靠止损或反转信号退出

    def leverage(self, pair: str, current_time, current_rate,
                proposed_leverage, max_leverage, entry_tag, side,
                **kwargs) -> float:
        """
        为每笔新交易自定义杠杆。此方法仅在期货模式下调用。

        :param pair: 当前分析的交易对
        :param current_time: 当前日期时间的日期对象
        :param current_rate: 根据退出定价设置计算得出的汇率。
        :param proposed_leverage: 机器人提议的杠杆。
        :param max_leverage: 在此交易对上允许的最大杠杆
        :param entry_tag: 可选的入场标识（buy_tag），如果与买入信号一起提供。
        :param side: 'long' 或 'short' - 表示建议交易的方向
        :return: 杠杆金额，介于1.0和max_leverage之间。
        """
        return 3.0
    # 静态定义市值前20主流币种（USDT计价）列表，用于交易对过滤
    top20_pairs = [
        "BTC/USDT", "ETH/USDT", "BNB/USDT", "XRP/USDT", "ADA/USDT",
        "DOGE/USDT", "SOL/USDT", "TRX/USDT", "MATIC/USDT", "DOT/USDT",
        "LTC/USDT", "SHIB/USDT", "AVAX/USDT", "UNI/USDT", "LINK/USDT",
        "XLM/USDT", "BCH/USDT", "TON/USDT", "XMR/USDT", "ATOM/USDT"
    ]

    # 用于检测支撑/阻力的波段窗口大小（比如5表示前后各5根K线）
    pivot_window = 30

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        计算策略所需的指标和辅助列。这里实现自动支撑/阻力检测。
        """
        # 初始化支撑/阻力列为NaN
        dataframe['pivot_high'] = 0
        dataframe['pivot_low'] = 0
        dataframe['resistance_level'] = np.nan
        dataframe['support_level'] = np.nan

        # 将dataframe的索引转换为range方便使用iloc遍历
        highs = dataframe['high'].values
        lows = dataframe['low'].values

        # 波段极值检测：迭代寻找局部高点和低点
        length = len(dataframe)
        w = self.pivot_window
        for i in range(w, length - w):
            # 局部高点判定：当前high等于窗口[i-w, i+w]内最高值
            if highs[i] == np.max(highs[i-w:i+w+1]):
                dataframe.at[dataframe.index[i], 'pivot_high'] = 1
            # 局部低点判定：当前low等于窗口[i-w, i+w]内最低值
            if lows[i] == np.min(lows[i-w:i+w+1]):
                dataframe.at[dataframe.index[i], 'pivot_low'] = 1

        # 识别最新支撑/阻力价位：始终记录最后一个pivot点价位作为当前水平
        last_support = np.nan
        last_resistance = np.nan
        for i in range(length):
            if dataframe.at[dataframe.index[i], 'pivot_low'] == 1:
                last_support = lows[i]
            if dataframe.at[dataframe.index[i], 'pivot_high'] == 1:
                last_resistance = highs[i]
            dataframe.at[dataframe.index[i], 'support_level'] = last_support
            dataframe.at[dataframe.index[i], 'resistance_level'] = last_resistance

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        基于检测到的支撑/阻力和价格关系，生成进场信号。
        """
        # 若当前交易对不在允许列表，则不产生任何信号
        # if metadata['pair'] not in self.top20_pairs:
        #     dataframe['enter_long'] = 0
        #     dataframe['enter_short'] = 0
        #     return dataframe

        # 初始化信号列
        dataframe['enter_long'] = 0
        dataframe['enter_short'] = 0

        # 条件：价格回到支撑位（当前收盘价进入支撑价±约0.5%范围，而且前一根K线高于支撑位）
        support_cond = (
            (dataframe['support_level'] > 0) &  # 存在有效支撑
            (dataframe['close'] <= dataframe['support_level'] * 1.005) & 
            (dataframe['close'] >= dataframe['support_level'] * 0.99) & 
            (dataframe['close'].shift(1) > dataframe['support_level'] * 1.005)
        )
        # 条件：价格上破阻力位（当前收盘价大于阻力位，而且上一根K线收盘不高于阻力位）
        resistance_cond = (
            (dataframe['resistance_level'] > 0) &  # 存在有效阻力
            (dataframe['close'] > dataframe['resistance_level']) & 
            (dataframe['close'].shift(1) <= dataframe['resistance_level'])
        )

        # 满足支撑条件则触发做多
        dataframe.loc[support_cond, 'enter_long'] = 1
        # 满足阻力突破条件则触发做空
        dataframe.loc[resistance_cond, 'enter_short'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        生成平仓信号，用于在出现反向条件时及时退出当前持仓。
        """
        dataframe['exit_long'] = 0
        dataframe['exit_short'] = 0

        # 若价格上破阻力（做空条件出现），则退出多单
        exit_long_cond = (
            (dataframe['resistance_level'] > 0) &
            (dataframe['close'] > dataframe['resistance_level']) &
            (dataframe['close'].shift(1) <= dataframe['resistance_level'])
        )
        # 若价格回踩支撑（做多条件出现），则退出空单
        exit_short_cond = (
            (dataframe['support_level'] > 0) &
            (dataframe['close'] <= dataframe['support_level'] * 1.005) &
            (dataframe['close'].shift(1) > dataframe['support_level'] * 1.005)
        )

        dataframe.loc[exit_long_cond, 'exit_long'] = 1
        dataframe.loc[exit_short_cond, 'exit_short'] = 1

        return dataframe
