# source: https://raw.githubusercontent.com/willy50414z/binance/5b07824df69fb43e4e8b0e91b2e2b6529151a80c/com/willy/binance/freqtrade/strategy/AMRS(ATR-Driven%20Mean%20Reversion%20Short/AMRS4_1Strategy.py
import logging
import pandas as pd
import talib.abstract as ta
from freqtrade.strategy import IStrategy
from pandas import DataFrame
import numpy as np

logger = logging.getLogger(__name__)


class Github_willy50414z_binance__AMRS4_1Strategy__20260301_155655(IStrategy):
    INTERFACE_VERSION = 3

    timeframe = "15m"
    can_short = True
    process_only_new_candles = True
    startup_candle_count = 120

    # --- 交易行為控制 ---
    minimal_roi = {"0": 10.0}
    stoploss = -0.25

    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = True

    # 均線長度參數
    ma7_len = 7
    ma25_len = 25
    ma99_len = 99

    # 出場與過濾參數
    exit_confirm_candles = 3
    lookback_candles = 10
    min_candle_body = 400  # 實體棒最小點數要求
    ma7_touch_tolerance = 0.999

    @staticmethod
    def _streak_true(cond: pd.Series) -> pd.Series:
        cond = cond.fillna(False).astype(bool)
        grp = (~cond).cumsum()
        return cond.groupby(grp).cumsum().astype(int)

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # 1. 計算均線
        dataframe["ma7"] = ta.SMA(dataframe, timeperiod=self.ma7_len)
        dataframe["ma25"] = ta.SMA(dataframe, timeperiod=self.ma25_len)
        dataframe["ma99"] = ta.SMA(dataframe, timeperiod=self.ma99_len)

        # 2. 計算斜率
        dataframe["ma7_slope"] = dataframe["ma7"].diff()
        dataframe["ma25_slope"] = dataframe["ma25"].diff()

        # 3. 前10根K棒實體最低值
        dataframe['body_min'] = np.minimum(dataframe['open'], dataframe['close'])
        dataframe['ten_candle_low'] = dataframe['body_min'].shift(1).rolling(window=self.lookback_candles).min()

        # 4. 當前 K 棒實體大小 (Open - Close)
        dataframe['body_size'] = dataframe['open'] - dataframe['close']

        # 5. Signal 2 輔助判斷
        dataframe["prev_high"] = dataframe["high"].shift(1)
        dataframe["prev_close"] = dataframe["close"].shift(1)
        dataframe["signal2_prev_touch_ma7"] = dataframe["prev_high"] >= (
                    dataframe["ma7"].shift(1) * self.ma7_touch_tolerance)
        dataframe["signal2_prev_close_below_ma7"] = dataframe["prev_close"] < dataframe["ma7"].shift(1)

        # 6. Signal 3 輔助判斷
        dataframe["close_gt_ma7"] = dataframe["close"] > dataframe["ma7"]
        dataframe["consecutive_closes_above_ma7"] = self._streak_true(dataframe["close_gt_ma7"])

        return dataframe

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

        # 【核心過濾條件】
        # 1. 基本趨勢：Price < MA99, MA7 < MA25, Slopes < 0
        # 2. 動能破底：Close < 前10根實體最低點
        # 3. 長黑K確認：實體(Open-Close) > 400 點
        strict_short_filter = (
                (dataframe["close"] < dataframe["ma99"]) &
                (dataframe["ma7"] < dataframe["ma25"]) &
                (dataframe["ma7_slope"] < 0) &
                (dataframe["ma25_slope"] < 0) &
                (dataframe["close"] < dataframe["ten_candle_low"]) &
                (dataframe["body_size"] >= self.min_candle_body) &  # 新增：長黑K條件
                (dataframe["volume"] > 0)
        )

        # Signal 1: 剛由上往下跌破 MA7 且符合長黑K
        signal1 = (
                strict_short_filter &
                (dataframe["close"] < dataframe["ma7"]) &
                (dataframe["close"].shift(1) >= dataframe["ma7"].shift(1))
        )

        # Signal 2: 反彈至 MA7 附近失敗且以長黑K殺出
        signal2 = (
                strict_short_filter &
                (dataframe["close"] < dataframe["ma7"]) &
                dataframe["signal2_prev_touch_ma7"] &
                dataframe["signal2_prev_close_below_ma7"]
        )

        dataframe.loc[signal1, "enter_short"] = 1
        dataframe.loc[signal1, "enter_tag"] = "s1_long_bear_breakout"

        dataframe.loc[signal2, "enter_short"] = 1
        dataframe.loc[signal2, "enter_tag"] = "s2_long_bear_rebound"

        return dataframe

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

        # Signal 3: 連續 3 根站上 MA7
        signal3 = dataframe["consecutive_closes_above_ma7"] >= self.exit_confirm_candles

        # Signal 4: 強制止損，站上 MA25
        signal4 = dataframe["close"] > dataframe["ma25"]

        dataframe.loc[signal3, "exit_short"] = 1
        dataframe.loc[signal3, "exit_tag"] = "signal3_ma7_streak"

        dataframe.loc[signal4, "exit_short"] = 1
        dataframe.loc[signal4, "exit_tag"] = "signal4_ma25_hard_exit"

        return dataframe