# source: https://raw.githubusercontent.com/shatianming5/Agent_market/8dc940a702171d651cabe59aea11f778550390e4/workspace/strategies/auto_v403.py
from __future__ import annotations
import sys
from pathlib import Path
import numpy as np
from pandas import DataFrame
_ROOT = Path(__file__).resolve().parents[2]
if str(_ROOT / "src") not in sys.path:
    sys.path.insert(0, str(_ROOT / "src"))
    sys.path.insert(0, str(_ROOT))
from freqtrade.strategy import IStrategy


class Github_shatianming5_Agent_market__auto_v403__20260330_190736(IStrategy):
    INTERFACE_VERSION = 3

    timeframe = "1h"
    can_short = False
    process_only_new_candles = True
    startup_candle_count: int = 55

    minimal_roi = {"0": 0.0}
    stoploss = -0.03
    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = True

    @staticmethod
    def _rsi(close, period: int = 14):
        delta = close.diff()
        gain = delta.clip(lower=0.0)
        loss = (-delta).clip(lower=0.0)
        avg_gain = gain.ewm(alpha=1.0 / period, adjust=False).mean()
        avg_loss = loss.ewm(alpha=1.0 / period, adjust=False).mean()
        rs = avg_gain / (avg_loss + 1e-12)
        return 100.0 - (100.0 / (1.0 + rs))

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        if dataframe is None or dataframe.empty:
            return dataframe

        close = dataframe["close"].astype(float)
        volume = dataframe["volume"].astype(float)

        dataframe["ret1h"] = close.pct_change()
        dataframe["ret20"] = close / close.shift(20) - 1.0

        dataframe["rsi"] = self._rsi(close, 14)

        mid = close.rolling(20).mean()
        std = close.rolling(20).std(ddof=0)
        dataframe["bb_mid"] = mid
        dataframe["bb_upper"] = mid + 2.0 * std
        dataframe["bb_lower"] = mid - 2.0 * std
        dataframe["bb_width"] = (dataframe["bb_upper"] - dataframe["bb_lower"]) / (mid.replace(0.0, np.nan))

        vol_ma = volume.rolling(20).mean()
        dataframe["vol_ratio"] = volume / (vol_ma.replace(0.0, np.nan))

        ann_factor = float(np.sqrt(24.0 * 365.0))
        dataframe["ann_vol24"] = dataframe["ret1h"].rolling(24).std(ddof=0) * ann_factor

        rsi_min12 = dataframe["rsi"].rolling(12).min()
        dataframe["rsi_os_recent"] = (rsi_min12 < 35.0).astype(float)

        lb = 6
        price_ll = close < close.shift(lb)
        rsi_hl = dataframe["rsi"] > dataframe["rsi"].shift(lb)
        dataframe["rsi_div"] = (price_ll & rsi_hl).astype(float)

        for c in ("ret1h", "ret20", "rsi", "bb_mid", "bb_upper", "bb_lower", "bb_width", "vol_ratio", "ann_vol24", "rsi_os_recent", "rsi_div"):
            dataframe[c] = (
                dataframe[c]
                .replace([np.inf, -np.inf], np.nan)
                .ffill()
                .fillna(0.0)
            )
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        if dataframe is None or dataframe.empty:
            return dataframe

        rebound_skip = dataframe["ret20"] > 0.03
        oversold = (dataframe["close"] < dataframe["bb_lower"] * 1.01) & ((dataframe["rsi"] < 42.0) | (dataframe["rsi_os_recent"] > 0.0))
        div_ok = dataframe["rsi_div"] > 0.0
        vol_ok = dataframe["ann_vol24"] < 0.80
        liq_ok = dataframe["volume"] > 0
        volr_ok = dataframe["vol_ratio"] > 0.25

        enter = liq_ok & volr_ok & vol_ok & (~rebound_skip) & oversold & div_ok
        dataframe.loc[enter, "enter_long"] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        if dataframe is None or dataframe.empty:
            return dataframe

        liq_ok = dataframe["volume"] > 0
        low_vol = dataframe["ann_vol24"] < 0.45

        exit_low = low_vol & (dataframe["close"] > dataframe["bb_upper"])
        exit_high = (~low_vol) & (dataframe["close"] > dataframe["bb_mid"])

        exit_cond = liq_ok & (exit_low | exit_high)
        dataframe.loc[exit_cond, "exit_long"] = 1
        return dataframe