# source: https://raw.githubusercontent.com/willy50414z/binance/58f423a97a9066d56a9c580e29a31ad007165df2/com/willy/binance/freqtrade/strategy/AMRS(ATR-Driven%20Mean%20Reversion%20Short/AMRS_v13_ExtractorStrategy.py
import logging
import pandas as pd
import talib.abstract as ta
from freqtrade.strategy import IStrategy, merge_informative_pair
from pandas import DataFrame
import numpy as np
from datetime import datetime, timedelta

logger = logging.getLogger(__name__)


class Github_willy50414z_binance__AMRS_v13_ExtractorStrategy__20260303_105924(IStrategy):
    """
    AMRS v13 - 利潤萃取者模式
    優化重點：
    1. 延續 V12 高品質進場 (Volume 2.5x, RSI > 35, Macro ADX > 25)
    2. 優化追蹤止損 (0.8% 觸發)，更早鎖定利潤。
    3. 加入 ATR 動態止盈與持倉保護期，減少手續費損耗。
    """
    INTERFACE_VERSION = 3

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

    # --- 交易性能參數 ---
    # 稍微放寬 ROI，讓 Custom Exit 與 Trailing Stop 主導離場
    minimal_roi = {
        "0": 0.20,  # 20% 硬性止盈
        "360": 0.05,  # 6小時後 5% 止盈
        "1440": 0.015  # 24小時後 1.5% 止盈 (確保高於手續費)
    }

    # 止損維持在 3%，給予波動空間但保護本金
    stoploss = -0.03

    # 追蹤止損：鎖定 0.8% 以上的利潤
    trailing_stop = True
    trailing_stop_positive = 0.001
    trailing_stop_positive_offset = 0.008  # 獲利達 0.8% 開啟 (原 1.5%)
    trailing_only_offset_is_reached = True

    def informative_pairs(self):
        return [(self.config['stake_currency'], '1d')]

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # --- 1. 日線指標 (1D) ---
        informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1d')
        informative['ma25_day'] = ta.SMA(informative, timeperiod=25)
        informative['day_slope'] = informative['ma25_day'].diff(3)
        informative['adx'] = ta.ADX(informative)
        informative['minus_di'] = ta.MINUS_DI(informative)
        informative['plus_di'] = ta.PLUS_DI(informative)

        dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '1d', ffill=True)

        # --- 2. 短線指標 (15m) ---
        dataframe['ma7'] = ta.SMA(dataframe, timeperiod=7)
        dataframe['ma25'] = ta.SMA(dataframe, timeperiod=25)
        dataframe['ma99'] = ta.SMA(dataframe, timeperiod=99)
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)

        # 乖離率與成交量
        dataframe['volume_mean'] = dataframe['volume'].rolling(window=30).mean()

        # 離場確認邏輯 (MA7 確認)
        dataframe['ma7_cross_above'] = (dataframe['close'] > dataframe['ma7']).astype(int)
        dataframe['streak_ma7'] = dataframe['ma7_cross_above'].rolling(window=5).sum()

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        進場邏輯：沿用 V12 高品質進場
        """
        # 1. 強度過濾：日線強勢趨勢
        macro_trend = (
                (dataframe['day_slope_1d'] < 0) &
                (dataframe['adx_1d'] > 25) &
                (dataframe['minus_di_1d'] > dataframe['plus_di_1d'])
        )

        # 2. 爆量條件：2.5 倍平均成交量
        volume_spike = (dataframe['volume'] > dataframe['volume_mean'] * 2.5)

        # 3. 空間過濾：RSI > 35 避開底部追空
        space_filter = (dataframe['rsi'] > 35)

        # 4. 價格結構
        price_structure = (
                (dataframe['close'] < dataframe['ma99']) &
                (dataframe['close'] < dataframe['ma25'])
        )

        dataframe.loc[
            macro_trend & volume_spike & space_filter & price_structure,
            ["enter_short", "enter_tag"]
        ] = (1, "v13_sniper_entry")

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # 技術指標離場：MA7 站穩
        dataframe.loc[
            (dataframe["streak_ma7"] >= 5),
            "exit_short"
        ] = 1
        return dataframe

    def custom_exit(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
                    current_profit: float, **kwargs):
        """
        自定義離場邏輯：動態鎖定利潤與摩擦保護
        """
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
        last_candle = dataframe.iloc[-1]

        # 計算持倉分鐘數
        trade_duration = (current_time - trade.open_date_utc).total_seconds() / 60

        # --- 邏輯 A: ATR 動態爆發止盈 ---
        # 如果當前獲利超過 3 倍 ATR 的波動率，代表出現超跌噴發，直接落袋為安
        atr_threshold = (last_candle['atr'] / current_rate) * 3.0
        if current_profit > atr_threshold and current_profit > 0.01:
            return "v13_atr_profit_burst"

        # --- 邏輯 B: 持倉保護期 (抗洗盤) ---
        # 前 60 分鐘內，除非獲利 > 0.8% 或 虧損 > 2%，否則不允許因為 MA7 指標離場
        if trade_duration < 60:
            if 0.008 > current_profit > -0.02:
                return None

        # --- 邏輯 C: 摩擦成本牆 (保護平均獲利) ---
        # 如果利潤低於 0.3% (扣掉手續費沒剩多少)，且持倉還不到 5 小時，拒絕因指標離場
        # 這會強制策略「等待」更大的波動，而不只是頻繁進出幫交易所打工
        if current_profit < 0.003 and trade_duration < 300:
            return None

        # --- 邏輯 D: 快速止盈鎖定 ---
        if current_profit > 0.04:
            return "v13_high_profit_protect"

        return None