# source: https://raw.githubusercontent.com/shatianming5/Agent_market/487b93170d1291655acc04636d2e8eadc42e6da4/workspace/strategies/auto_v3.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_v3__20260330_143404(IStrategy):
    timeframe = "1h"
    can_short = False

    process_only_new_candles = True
    startup_candle_count = 240

    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = False

    minimal_roi = {"0": 0.012, "48": 0.006, "120": 0}
    stoploss = -0.08

    @staticmethod
    def _ema(s: DataFrame, span: int):
        return s.ewm(span=span, adjust=False).mean()

    @staticmethod
    def _rsi(close: DataFrame, period: int = 14):
        delta = close.diff()
        up = delta.clip(lower=0.0)
        down = (-delta).clip(lower=0.0)
        alpha = 1.0 / float(period)
        roll_up = up.ewm(alpha=alpha, adjust=False).mean()
        roll_down = down.ewm(alpha=alpha, adjust=False).mean()
        rs = roll_up / (roll_down.replace(0.0, np.nan))
        rsi = 100.0 - (100.0 / (1.0 + rs))
        return rsi.fillna(50.0)

    @staticmethod
    def _atr(df: DataFrame, period: int = 14):
        high = df["high"]
        low = df["low"]
        close = df["close"]
        prev_close = close.shift(1)
        tr = np.maximum(high - low, np.maximum((high - prev_close).abs(), (low - prev_close).abs()))
        return tr.ewm(alpha=1.0 / float(period), adjust=False).mean()

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        close = dataframe["close"]
        vol = dataframe["volume"]

        dataframe["ret_1h"] = close.pct_change().fillna(0.0)
        dataframe["ema20"] = self._ema(close, 20)
        dataframe["ema50"] = self._ema(close, 50)
        dataframe["ema100"] = self._ema(close, 100)
        dataframe["ema200"] = self._ema(close, 200)

        ema200 = dataframe["ema200"]
        dataframe["ema200_slope"] = (ema200 - ema200.shift(24)) / ema200.replace(0.0, np.nan)
        dataframe["rsi14"] = self._rsi(close, 14)
        dataframe["atr14"] = self._atr(dataframe, 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)

        vma = vol.rolling(20).mean()
        dataframe["volume_ratio"] = (vol / vma.replace(0.0, np.nan)).fillna(1.0)

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["enter_long"] = 0
        dataframe["enter_tag"] = ""

        close = dataframe["close"]
        rsi = dataframe["rsi14"]
        atr = dataframe["atr14"]
        ema20 = dataframe["ema20"]
        ema200 = dataframe["ema200"]
        slope = dataframe["ema200_slope"]
        vr = dataframe["volume_ratio"]

        volume_ok = vr > 0.55
        regime_ok = (slope > -0.0045) & (close > ema200 * 0.93)
        regime_soft = close > ema200 * 0.90

        cond_bb = (rsi < 43.0) & (close <= dataframe["bb_lower"] * 1.002)
        cond_kelt = (rsi < 48.0) & (close < (ema20 - 0.85 * atr))
        cond_dump = (dataframe["ret_1h"] < -0.012) & (rsi < 50.0) & (vr > 1.2) & regime_soft

        enter = volume_ok & ((regime_ok & (cond_bb | cond_kelt)) | cond_dump)
        dataframe.loc[enter, "enter_long"] = 1
        dataframe.loc[enter & cond_dump, "enter_tag"] = "dump_rebound"
        dataframe.loc[enter & ~cond_dump & cond_bb, "enter_tag"] = "bb_oversold"
        dataframe.loc[enter & ~cond_dump & ~cond_bb, "enter_tag"] = "atr_pullback"

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["exit_long"] = 0
        dataframe["exit_tag"] = ""

        close = dataframe["close"]
        rsi = dataframe["rsi14"]
        atr = dataframe["atr14"]
        ema20 = dataframe["ema20"]
        ema50 = dataframe["ema50"]
        bb_mid = dataframe["bb_mid"]
        bb_upper = dataframe["bb_upper"]

        cross_mid_up = (close > bb_mid) & (close.shift(1) <= bb_mid.shift(1))

        take_profit = ((rsi > 55.0) & (close > ema20)) | (cross_mid_up & (rsi > 50.0)) | ((close > bb_upper * 0.998) & (rsi > 60.0))
        stop_guard = ((close < ema50) & (rsi < 40.0)) | (close < (ema20 - 1.5 * atr))

        exit_sig = take_profit | stop_guard
        dataframe.loc[exit_sig, "exit_long"] = 1
        dataframe.loc[stop_guard, "exit_tag"] = "risk_off"
        dataframe.loc[exit_sig & ~stop_guard, "exit_tag"] = "reversion_exit"

        return dataframe