# source: https://raw.githubusercontent.com/DOUGLASGUEDESATRIA/OSIRIS_TRADE/fe3c09567f3798d1cad6d7a306fa4f6131d91e17/user_data/strategies/OsirisFunnelStrategy.py
"""
OSIRIS FUNNEL STRATEGY v2.0 — Grid-Optimized for 1 Year BTC
=============================================================
Entry logic from exhaustive funnel analysis:
  Base: EMA9 cross close on 5m
  Filter 1: MACD histogram aligned
  Filter 2: 1H RSI aligned >50/<50
  Filter 3: ADX(14) > 25 (trending market)

Exit: Fixed SL=2.5%, TP=3.0% (RR=1.2:1) via stoploss + ROI.
  - No custom_stoploss (avoids ATR re-evaluation drift)
  - No trailing stop
  - No exit signals

1Y Backtest (2025-03-20 to 2026-03-20, BTC/USDT futures):
  174 trades, 50.6% WR, +3.14%, PF=1.15, DD=2.36%
  7/12 months profitable, survived -20% market decline
"""

import logging
import numpy as np
from pandas import DataFrame
from typing import Optional

from freqtrade.strategy import IStrategy, merge_informative_pair
from freqtrade.persistence import Trade
import talib.abstract as ta

logger = logging.getLogger(__name__)


class Github_DOUGLASGUEDESATRIA_OSIRIS_TRADE__OsirisFunnelStrategy__20260329_060843(IStrategy):
    INTERFACE_VERSION = 3
    can_short = True
    timeframe = "5m"

    # TP via ROI: 3.0% — 1Y grid-search winner
    # SL=2.5%, TP=3.0% → 50.6% WR, +$31.4/Y, DD=2.4%, PF=1.15 (174 trades)
    minimal_roi = {}

    # Fixed stoploss: -2.5%
    stoploss = -0.0400

    # Trailing: COMPLETELY DISABLED
    trailing_stop = True
    trailing_stop_positive = 0.0100
    trailing_stop_positive_offset = 0.0200
    trailing_only_offset_is_reached = True

    # NO custom stoploss — use fixed stoploss for deterministic behavior
    use_custom_stoploss = False

    # No exit signal — only ROI (TP) and stoploss (SL)
    use_exit_signal = False

    startup_candle_count = 200
    process_only_new_candles = True

    # ADX threshold
    adx_threshold = 25

    def informative_pairs(self):
        pairs = self.dp.current_whitelist()
        informative = []
        for pair in pairs:
            informative.append((pair, "1h"))
        return informative

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # === 5m indicators ===
        dataframe["ema9"] = ta.EMA(dataframe, timeperiod=9)
        dataframe["adx14"] = ta.ADX(dataframe, timeperiod=14)

        macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
        dataframe["macd_hist"] = macd["macdhist"]

        # EMA9 cross detection
        dataframe["prev_close"] = dataframe["close"].shift(1)
        dataframe["prev_ema9"] = dataframe["ema9"].shift(1)

        # === 1H indicators (RSI for filter) ===
        if self.dp:
            inf_1h = self.dp.get_pair_dataframe(
                pair=metadata["pair"], timeframe="1h"
            )
            if not inf_1h.empty:
                inf_1h["rsi_1h"] = ta.RSI(inf_1h, timeperiod=14)
                inf_1h = inf_1h[["date", "rsi_1h"]].copy()
                dataframe = merge_informative_pair(
                    dataframe, inf_1h, self.timeframe, "1h", ffill=True
                )

        # Ensure column exists
        if "rsi_1h_1h" not in dataframe.columns:
            dataframe["rsi_1h_1h"] = 50.0

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        FUNNEL ENTRY:
        Base: Price crosses EMA9 (bullish cross = long, bearish = short)
        Filter 1: MACD histogram aligned (>0 long, <0 short)
        Filter 2: 1H RSI aligned (>50 long, <50 short)
        Filter 3: ADX > threshold (trending market)
        """
        # Base signal: EMA9 cross
        cross_above = (
            (dataframe["prev_close"] < dataframe["prev_ema9"]) &
            (dataframe["close"] > dataframe["ema9"])
        )
        cross_below = (
            (dataframe["prev_close"] > dataframe["prev_ema9"]) &
            (dataframe["close"] < dataframe["ema9"])
        )

        # Filter 1: MACD histogram
        macd_bull = dataframe["macd_hist"] > 0
        macd_bear = dataframe["macd_hist"] < 0

        # Filter 2: 1H RSI
        rsi1h_bull = dataframe["rsi_1h_1h"] > 50
        rsi1h_bear = dataframe["rsi_1h_1h"] < 50

        # Filter 3: ADX trending
        adx_ok = dataframe["adx14"] > self.adx_threshold

        # Volume sanity
        vol_ok = dataframe["volume"] > 0

        # === LONG ===
        dataframe.loc[
            cross_above & macd_bull & rsi1h_bull & adx_ok & vol_ok,
            "enter_long",
        ] = 1

        # === SHORT ===
        dataframe.loc[
            cross_below & macd_bear & rsi1h_bear & adx_ok & vol_ok,
            "enter_short",
        ] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # No exit signals — only ROI (TP) and stoploss (SL)
        return dataframe
