# source: https://raw.githubusercontent.com/learn-dumboo24/adaptive-trend-strategy/7d031b1589e3c32870501c6f01c441d05a3a8071/strategies/AdaptiveTrendStrategy.py
"""
Github_learn_dumboo24_adaptive_trend_strategy__AdaptiveTrendStrategy__20260512_160735 — daily-timeframe trend follower designed to beat BTC+ETH HODL.

Edge sources:
  1. Avoid bear drawdowns — exit on trend reversal, sit in stables
  2. Capture full bull legs — wide trailing stop, no premature TP
  3. Multi-asset rotation — only hold strongest of {BTC, ETH, SOL}
  4. Risk-adjusted entries — confirmed trend + volume + ADX

Why daily timeframe:
  - Eliminates noise (95% of 15m moves are noise)
  - Few trades → low fees
  - Captures real trends — most crypto returns come from <20% of days
"""
from datetime import datetime
from functools import reduce

import numpy as np
import pandas as pd
import talib.abstract as ta
from pandas import DataFrame

from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter


class Github_learn_dumboo24_adaptive_trend_strategy__AdaptiveTrendStrategy__20260512_160735(IStrategy):
    INTERFACE_VERSION = 3

    timeframe = "1d"
    can_short = False
    process_only_new_candles = True

    # Loose stops — only major bear regime should exit
    stoploss = -0.50                # 50% — basically disabled, let exit signal handle it
    minimal_roi = {"0": 100}        # 100% TP — disabled, hold winners
    trailing_stop = False           # let it ride

    use_exit_signal = True
    exit_profit_only = False

    startup_candle_count: int = 250

    # ---- Hyperopt-able tunables ----
    ema_fast      = IntParameter(20, 60, default=50, space="buy")
    ema_slow      = IntParameter(150, 250, default=200, space="buy")
    adx_min       = IntParameter(15, 35, default=20, space="buy")
    rsi_max_entry = IntParameter(60, 80, default=70, space="buy")
    vol_mult      = DecimalParameter(1.0, 2.5, default=1.2, space="buy", decimals=2)

    def populate_indicators(self, df: DataFrame, metadata: dict) -> DataFrame:
        df["ema_fast"]   = ta.EMA(df, timeperiod=self.ema_fast.value)
        df["ema_slow"]   = ta.EMA(df, timeperiod=self.ema_slow.value)
        df["rsi"]        = ta.RSI(df, timeperiod=14)
        df["adx"]        = ta.ADX(df, timeperiod=14)
        df["atr"]        = ta.ATR(df, timeperiod=14)

        # Trend strength = how far price above slow EMA, normalized by ATR
        df["trend_str"]  = (df["close"] - df["ema_slow"]) / df["atr"]

        # Volume regime
        df["vol_sma_20"] = ta.SMA(df["volume"], timeperiod=20)
        df["vol_ratio"]  = df["volume"] / df["vol_sma_20"]

        # MACD for confirmation
        macd = ta.MACD(df, fastperiod=12, slowperiod=26, signalperiod=9)
        df["macd"]        = macd["macd"]
        df["macd_signal"] = macd["macdsignal"]

        # Higher-high / higher-low structure (last 10 candles)
        df["hh_10"] = df["high"].rolling(10).max()
        df["ll_10"] = df["low"].rolling(10).min()
        df["hh_break"] = (df["close"] > df["hh_10"].shift(1)).astype(int)

        return df

    def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
        # Two entry types stack together (max_open_trades>1 handles per-pair sizing):
        # 1. Regime entry: price reclaims 200 EMA (bear → bull transition)
        regime_in = (
            (df["close"] > df["ema_slow"]) &
            (df["close"].shift(1) <= df["ema_slow"].shift(1))
        )
        # 2. Bull-pullback entry: while in bull regime, buy when price dips to fast EMA and bounces
        # Captures continuation moves without waiting for full bear-to-bull cycle
        bull_dip = (
            (df["close"] > df["ema_slow"]) &                           # bull regime
            (df["ema_fast"] > df["ema_slow"]) &                        # uptrend confirmed
            (df["low"].shift(1) <= df["ema_fast"].shift(1) * 1.02) &   # touched fast EMA recently
            (df["close"] > df["ema_fast"]) &                           # back above
            (df["close"] > df["close"].shift(1))                        # green candle
        )
        df.loc[regime_in,    ["enter_long", "enter_tag"]] = (1, "regime_in")
        df.loc[bull_dip,     ["enter_long", "enter_tag"]] = (1, "bull_dip")
        return df

    def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
        # Exit only on confirmed regime break — close below 200 EMA
        # Holds through bull pullbacks, exits sustained bear
        df.loc[
            df["close"] < df["ema_slow"],
            "exit_long"
        ] = 1
        return df
