# source: https://raw.githubusercontent.com/xxxx443117/freqtrade-up/88d1f4f32c8708f5bfc54288df9a0d4ae84e60c2/strategies/BTCPredictionStrategy/BTCPredictionStrategy.py
# 导入所需库和模块
import talib.abstract as ta
from datetime import timedelta
from freqtrade.strategy import IStrategy, Trade
from pandas import DataFrame
from datetime import datetime

# 如果需要交叉信号检测，可以使用 qtpylib 辅助函数
from freqtrade.vendor.qtpylib import indicators as qtpylib

class Github_xxxx443117_freqtrade_up__BTCPredictionStrategy__20250609_054250(IStrategy):
    # 基础配置
    timeframe = '1m'               # 1分钟K线
    can_short = True              # 允许做空（用于卖出信号预测下跌）
    startup_candle_count = 50     # 初始所需K线数量，确保指标有足够数据
    minimal_roi = {}              # 不使用 ROI 即刻止盈退出:contentReference[oaicite:0]{index=0}
    stoploss = -1                 # 不使用常规止损（-100%），由自定义退出控制:contentReference[oaicite:1]{index=1}

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        计算所需技术指标：RSI、MACD（及信号线）、布林带、短期/长期均线。
        """
        # RSI 相对强弱指数
        dataframe['rsi'] = ta.RSI(dataframe['close'], timeperiod=14)
        # MACD 指标及其信号线和柱状图
        macd = ta.MACD(dataframe['close'], fastperiod=12, slowperiod=26, signalperiod=9)
        dataframe['macd'] = macd[0]        # MACD线
        dataframe['macd_signal'] = macd[1] # 信号线
        dataframe['macd_hist'] = macd[2]   # MACD柱状图

        # 布林带
        boll = ta.BBANDS(dataframe, timeperiod=20, nbdevup=2.0, nbdevdn=2.0)
        dataframe['bb_upper'] = boll['upperband']
        dataframe['bb_middle'] = boll['middleband']
        dataframe['bb_lower'] = boll['lowerband']
        # 指数移动平均线：短期(EMA5)和长期(EMA15)
        dataframe['ema_short'] = ta.EMA(dataframe['close'], timeperiod=5)
        dataframe['ema_long']  = ta.EMA(dataframe['close'], timeperiod=15)
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        定义交易信号：满足多指标共振条件时给出“买入”（看涨预测）或“卖出”（看跌预测）信号。
        """
        # 多指标看涨条件（buy信号）：
        buy_condition = (
            (dataframe['rsi'] < 24) &  # RSI低于30，超卖区域:contentReference[oaicite:2]{index=2}:contentReference[oaicite:3]{index=3}
            # (qtpylib.crossed_above(dataframe['macd'], dataframe['macd_signal'])) &  # MACD金叉信号:contentReference[oaicite:4]{index=4}:contentReference[oaicite:5]{index=5}
            (dataframe['close'] < dataframe['bb_lower']) &  # 收盘价跌破布林带下轨，极端超卖:contentReference[oaicite:6]{index=6}:contentReference[oaicite:7]{index=7}
            # (dataframe['ema_short'] > dataframe['ema_long']) &  # 短期均线在长期均线之上，短线趋势转强:contentReference[oaicite:8]{index=8}:contentReference[oaicite:9]{index=9}
            (dataframe['volume'] > 0)  # 保证有成交量
        )
        dataframe.loc[buy_condition, 'enter_long'] = 1  # 触发买入信号（预测未来涨）

        # 多指标看跌条件（sell信号）：
        sell_condition = (
            (dataframe['rsi'] > 76) &  # RSI高于70，超买区域
            # (qtpylib.crossed_below(dataframe['macd'], dataframe['macd_signal'])) &  # MACD死叉信号
            (dataframe['close'] > dataframe['bb_upper']) &  # 收盘价突破布林带上轨，极端超买
            # (dataframe['ema_short'] < dataframe['ema_long']) &  # 短期均线在长期均线之下，短线趋势转弱
            (dataframe['volume'] > 0)
        )
        dataframe.loc[sell_condition, 'enter_short'] = 1  # 触发卖出信号（预测未来跌）

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        定义离场信号。本策略主要通过自定义退出 (custom_exit) 控制平仓时间，
        因此这里不依赖技术指标发出常规离场信号，保持为空。
        """
        # 初始化退出信号列
        dataframe['exit_long'] = 0
        dataframe['exit_short'] = 0
        # （不基于任何指标条件，在 custom_exit 中处理强制平仓逻辑）
        return dataframe

    def custom_exit(self, pair: str, trade: Trade, current_time, current_rate: float,
                    current_profit: float, **kwargs):
        """
        自定义退出逻辑：如果交易已持仓达到或超过10分钟，则返回退出信号。
        这个方法每个循环都会针对每笔未平仓交易调用（频率约为每几秒一次），
        用于检查是否需要提前退出交易。
        """
        # 计算该笔交易已经持仓的时间 (当前时间 - 开仓时间)
        hold_duration = current_time - trade.open_date_utc  # 持仓时长 (datetime.timedelta)
        # 如果持仓时间超过或等于10分钟，则触发退出
        if hold_duration >= timedelta(minutes=10):
            return "timeout_10m"  # 返回一个标识字符串表示触发10分钟平仓
        # 否则不退出
        return None