# source: https://raw.githubusercontent.com/Jericho6688/ft_userdata/21ea2bd2d2e94420a4cd757f89ef1a8b484f9c02/user_data/strategies/bias.py
# flake8: noqa: F401
# isort: skip_file
# --- Do not remove these imports ---
import numpy as np
import pandas as pd
from datetime import datetime, timedelta, timezone
from pandas import DataFrame
from typing import Dict, Optional, Union, Tuple

from freqtrade.strategy import (
    IStrategy,
    Trade,
    Order,
    PairLocks,
    informative,  # @informative decorator
    # Hyperopt Parameters
    BooleanParameter,
    CategoricalParameter,
    DecimalParameter,
    IntParameter,
    RealParameter,
    # timeframe helpers
    timeframe_to_minutes,
    timeframe_to_next_date,
    timeframe_to_prev_date,
    # Strategy helper functions
    merge_informative_pair,
    stoploss_from_absolute,
    stoploss_from_open,
)

# --------------------------------
# Add your lib to import here
import talib.abstract as ta
from technical import qtpylib


class Github_Jericho6688_ft_userdata__bias__20250528_091046(IStrategy):
    """
    乖离率 (Bias Ratio, BIA) 指标的多空双向期货策略
    """

    INTERFACE_VERSION = 3
    can_short: bool = True
    timeframe = "5m"

    minimal_roi = {
        "4": -1,
        "0": 0.04,
    }
    stoploss = -0.10

    process_only_new_candles = True
    use_exit_signal = False  # 简化策略，不使用额外的退出信号
    exit_profit_only = False
    ignore_roi_if_entry_signal = False

    startup_candle_count: int = 20  # BIA 需要至少 20 根 K 线

    # Hyperparameters
    bia_period = IntParameter(low=10, high=30, default=20, space="buy", optimize=True, load=True)
    bia_oversold = DecimalParameter(low=-5.0, high=-1.0, default=-2.0, decimals=1, space="buy", optimize=True, load=True)
    bia_overbought = DecimalParameter(low=1.0, high=5.0, default=2.0, decimals=1, space="buy", optimize=True, load=True)

    def informative_pairs(self):
        return []

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        计算 BIA 指标
        """
        dataframe['sma'] = ta.SMA(dataframe, timeperiod=self.bia_period.value)
        dataframe['bia'] = (dataframe['close'] - dataframe['sma']) / dataframe['sma'] * 100
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        定义入场信号：
        - BIA 低于超卖线时，做多
        - BIA 高于超买线时，做空
        """
        dataframe.loc[
            (
                (dataframe['bia'] < self.bia_oversold.value) &
                (dataframe['volume'] > 0)  # 确保有交易量
            ),
            ['enter_long', 'enter_tag']
        ] = (1, 'BIA_Oversold')

        dataframe.loc[
            (
                (dataframe['bia'] > self.bia_overbought.value) &
                (dataframe['volume'] > 0)  # 确保有交易量
            ),
            ['enter_short', 'enter_tag']
        ] = (1, 'BIA_Overbought')

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        为了简化策略，这里不设置额外的出场信号，完全依赖 minimal_roi 和 stoploss
        """
        return dataframe

    def leverage(self, pair: str, current_time: datetime, current_rate: float,
                 proposed_leverage: float, max_leverage: float, side: str,
                 **kwargs) -> float:
        """
        Customize leverage for each new trade. This method is only called in futures mode.

        :param pair: Pair that's currently analyzed
        :param current_time: datetime object, containing the current datetime
        :param current_rate: Rate, calculated based on pricing settings in exit_pricing.
        :param proposed_leverage: A leverage proposed by the bot.
        :param max_leverage: Max leverage allowed on this pair
        :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal.
        :param side: 'long' or 'short' - indicating the direction of the proposed trade
        :return: A leverage amount, which is between 1.0 and max_leverage.
        """
        return 5.0