# source: https://raw.githubusercontent.com/witooh/else/b5585ade3130777fb3e82012fe50b069ffe3862f/user_data/strategies/TrendFollowerBTC/TrendFollowerBTC.py
"""
Github_witooh_else__TrendFollowerBTC__20260306_110129 v10 — Donchian Breakout with More Pairs (5 pairs)

Strategy: Return to v4 (best CAGR, Sharpe 0.38) but add 2 more pairs.
With 5 pairs instead of 3, we get ~433 trades (up from 260).
More trades = more Sharpe data points = better Sharpe estimation.

Additionally, more diverse pairs (different volatility profiles) should
smooth the daily return distribution and improve Sharpe.

Entry conditions (same as v4):
  - Price breaks above 20-bar Donchian high
  - Volume > 1.3x average 20-bar volume
  - BTC 1d Supertrend bullish (macro regime for ALL pairs)
  - RSI > 50 (momentum positive)

Exit conditions (same as v4):
  - Price falls below 10-bar Donchian low
  - Stoploss: -8% fixed

Capital: $3,000 wallet, unlimited stake, max 5 open trades (one per pair)
Pairs: BTC/USDT:USDT, ETH/USDT:USDT, SOL/USDT:USDT, BNB/USDT:USDT, XRP/USDT:USDT
"""

import sys
from pathlib import Path

import pandas as pd
import talib.abstract as ta
from freqtrade.strategy import IStrategy, merge_informative_pair

# Add shared indicators path
sys.path.insert(0, str(Path(__file__).parent.parent))
from indicators import calculate_supertrend


class Github_witooh_else__TrendFollowerBTC__20260306_110129(IStrategy):
    INTERFACE_VERSION = 3

    timeframe = "4h"
    startup_candle_count = 60

    can_short = False

    stoploss = -0.08
    trailing_stop = False
    use_custom_stoploss = False

    minimal_roi = {"0": 10.0}  # never hit by ROI

    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = False
    process_only_new_candles = True

    position_adjustment_enable = False

    # Donchian channels (v4 parameters)
    dc_entry_period: int = 20
    dc_exit_period: int = 10

    # Volume filter
    vol_sma_period: int = 20
    vol_ratio_threshold: float = 1.3

    # Macro
    st_daily_period: int = 10
    st_daily_mult: float = 3.0

    def informative_pairs(self):
        # BTC daily for macro filter for ALL pairs
        return [("BTC/USDT:USDT", "1d")]

    def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        # ── Donchian Channels ─────────────────────────────────────────
        dataframe["dc_high"] = dataframe["high"].shift(1).rolling(self.dc_entry_period).max()
        dataframe["dc_low"] = dataframe["low"].shift(1).rolling(self.dc_exit_period).min()

        # ── Volume filter ─────────────────────────────────────────────
        dataframe["vol_sma"] = dataframe["volume"].rolling(self.vol_sma_period).mean()

        # ── Momentum ─────────────────────────────────────────────────
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)

        # ── BTC 1d Macro Filter (used for ALL pairs) ─────────────────
        btc_1d = self.dp.get_pair_dataframe(pair="BTC/USDT:USDT", timeframe="1d")
        if btc_1d is not None and not btc_1d.empty:
            btc_1d = btc_1d.copy()
            st_daily, dir_daily = calculate_supertrend(
                btc_1d, self.st_daily_period, self.st_daily_mult
            )
            btc_1d["btc_daily_st_dir"] = dir_daily
            dataframe = merge_informative_pair(
                dataframe, btc_1d[["date", "btc_daily_st_dir"]], self.timeframe, "1d", ffill=True
            )
        else:
            dataframe["btc_daily_st_dir_1d"] = 1

        return dataframe

    def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        """
        Entry: Donchian breakout + volume + BTC macro bullish + RSI
        """
        conditions = (
            # Price breaks above N-bar Donchian high
            (dataframe["close"] > dataframe["dc_high"])
            # Volume confirms breakout
            & (dataframe["volume"] > dataframe["vol_sma"] * self.vol_ratio_threshold)
            # BTC macro: daily Supertrend bullish
            & (dataframe["btc_daily_st_dir_1d"] == 1)
            # RSI: momentum positive
            & (dataframe["rsi"] > 50)
            & (dataframe["dc_high"].notna())
            & (dataframe["volume"] > 0)
        )

        dataframe.loc[conditions, "enter_long"] = 1
        dataframe.loc[conditions, "enter_tag"] = "dc_breakout"

        return dataframe

    def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        """
        Exit: Price falls below N/2-bar Donchian low
        """
        exit_conditions = (
            (dataframe["close"] < dataframe["dc_low"])
            & (dataframe["dc_low"].notna())
            & (dataframe["volume"] > 0)
        )

        dataframe.loc[exit_conditions, "exit_long"] = 1
        dataframe.loc[exit_conditions, "exit_tag"] = "dc_low_exit"

        return dataframe
