# source: https://raw.githubusercontent.com/jcd1991/market-behavior-lab/16a04bd8b1004e90b9b17b556429a2eb730d96da/user_data/strategies/MultiTimeframeConfirmation.py
# directory_url: https://github.com/jcd1991/market-behavior-lab/blob/main/user_data/strategies/
# User: jcd1991
# Repository: market-behavior-lab
# --------------------"""5-minute signals requiring independent 15-minute trend confirmation."""

from __future__ import annotations

import numpy as np
import pandas as pd
import talib.abstract as ta
from freqtrade.strategy import IntParameter, IStrategy
from pandas import DataFrame

try:
    from user_data.strategies.research_strategy_helpers import utc_series
except ModuleNotFoundError:
    from research_strategy_helpers import utc_series


class Github_jcd1991_market_behavior_lab__MultiTimeframeConfirmation__20260921_130836(IStrategy):
    INTERFACE_VERSION = 3
    timeframe = "5m"
    can_short = True
    process_only_new_candles = True
    startup_candle_count = 600
    stoploss = -0.08
    minimal_roi = {"0": 100.0}

    buy_mtf_fast = IntParameter(6, 36, default=12, space="buy", optimize=True)
    buy_mtf_slow = IntParameter(24, 120, default=48, space="buy", optimize=True)
    buy_mtf_confirm_fast = IntParameter(4, 24, default=12, space="buy", optimize=True)
    buy_mtf_confirm_slow = IntParameter(12, 72, default=36, space="buy", optimize=True)

    def informative_pairs(self):
        try:
            return [(pair, "15m") for pair in self.dp.current_whitelist()]
        except Exception:
            return []

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["mtf_fast"] = ta.EMA(dataframe, timeperiod=int(self.buy_mtf_fast.value))
        dataframe["mtf_slow"] = ta.EMA(dataframe, timeperiod=int(self.buy_mtf_slow.value))
        dataframe["mtf_confirm_fast"] = np.nan
        dataframe["mtf_confirm_slow"] = np.nan
        try:
            higher = self.dp.get_pair_dataframe(pair=metadata["pair"], timeframe="15m")
        except Exception:
            higher = None
        if higher is not None and not higher.empty:
            higher = higher.copy()
            higher["__date"] = utc_series(higher["date"])
            higher["mtf_confirm_fast"] = ta.EMA(higher, timeperiod=int(self.buy_mtf_confirm_fast.value))
            higher["mtf_confirm_slow"] = ta.EMA(higher, timeperiod=int(self.buy_mtf_confirm_slow.value))
            left = dataframe.copy()
            left["__date"] = utc_series(left["date"])
            right = higher[["__date", "mtf_confirm_fast", "mtf_confirm_slow"]].dropna(subset=["__date"]).sort_values("__date")
            merged = pd.merge_asof(left.sort_values("__date"), right, on="__date", direction="backward", suffixes=("", "_higher"))
            dataframe["mtf_confirm_fast"] = merged["mtf_confirm_fast_higher"].to_numpy() if "mtf_confirm_fast_higher" in merged else merged["mtf_confirm_fast"].to_numpy()
            dataframe["mtf_confirm_slow"] = merged["mtf_confirm_slow_higher"].to_numpy() if "mtf_confirm_slow_higher" in merged else merged["mtf_confirm_slow"].to_numpy()
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        higher_up = dataframe["mtf_confirm_fast"].gt(dataframe["mtf_confirm_slow"])
        higher_down = dataframe["mtf_confirm_fast"].lt(dataframe["mtf_confirm_slow"])
        dataframe["enter_long"] = (dataframe["mtf_fast"].gt(dataframe["mtf_slow"]) & higher_up).astype(int)
        dataframe["enter_short"] = (dataframe["mtf_fast"].lt(dataframe["mtf_slow"]) & higher_down).astype(int)
        dataframe["enter_tag"] = np.where(dataframe["enter_long"], "mtf_confirmed_long", np.where(dataframe["enter_short"], "mtf_confirmed_short", ""))
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["exit_long"] = dataframe["mtf_fast"].lt(dataframe["mtf_slow"]).astype(int)
        dataframe["exit_short"] = dataframe["mtf_fast"].gt(dataframe["mtf_slow"]).astype(int)
        dataframe["exit_tag"] = "mtf_fast_slow_exit"
        return dataframe


class Github_jcd1991_market_behavior_lab__MultiTimeframeConfirmation__20260921_130836Spot(Github_jcd1991_market_behavior_lab__MultiTimeframeConfirmation__20260921_130836):
    """Long-only spot equivalent of the benchmark."""

    can_short = False

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe = super().populate_entry_trend(dataframe, metadata)
        dataframe["enter_short"] = 0
        dataframe["enter_tag"] = np.where(dataframe["enter_long"], "mtf_confirmed_long", "")
        return dataframe
