# source: https://raw.githubusercontent.com/jcd1991/market-behavior-lab/16a04bd8b1004e90b9b17b556429a2eb730d96da/user_data/strategies/HurstRegimeSwitch.py
# directory_url: https://github.com/jcd1991/market-behavior-lab/blob/main/user_data/strategies/
# User: jcd1991
# Repository: market-behavior-lab
# --------------------"""OHLCV-only Hurst regime switch research lane.

Inspired by research comparing momentum in persistent regimes with mean
reversion in anti-persistent regimes. It is intentionally simple and
interpretable so the result can be compared with RegimeRouted.
"""

from __future__ import annotations

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

from hurst import rolling_hurst


class Github_jcd1991_market_behavior_lab__HurstRegimeSwitch__20260921_130836(IStrategy):
    """Switch between trend continuation and mean reversion using rolling H."""

    INTERFACE_VERSION = 3
    can_short = True
    timeframe = "1h"
    startup_candle_count = 180
    stoploss = -0.08
    minimal_roi = {"0": 0.02}
    trailing_stop = False

    buy_hurst_window = IntParameter(96, 256, default=128, space="buy", optimize=True)
    buy_hurst_trend_min = DecimalParameter(0.52, 0.70, default=0.55, decimals=2, space="buy", optimize=True)
    buy_hurst_revert_max = DecimalParameter(0.30, 0.48, default=0.45, decimals=2, space="buy", optimize=True)
    buy_z_entry = DecimalParameter(1.0, 3.0, default=1.6, decimals=1, space="buy", optimize=True)
    buy_ema_fast = IntParameter(8, 32, default=16, space="buy", optimize=True)
    buy_ema_slow = IntParameter(32, 128, default=64, space="buy", optimize=True)
    sell_z_exit = DecimalParameter(0.0, 1.0, default=0.25, decimals=2, space="sell", optimize=True)

    def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        close = pd.to_numeric(dataframe["close"], errors="coerce")
        window = int(self.buy_hurst_window.value)
        dataframe["hurst"] = rolling_hurst(close, window)
        dataframe["hs_ema_fast"] = ta.EMA(dataframe, timeperiod=int(self.buy_ema_fast.value))
        dataframe["hs_ema_slow"] = ta.EMA(dataframe, timeperiod=int(self.buy_ema_slow.value))
        mean = close.rolling(window, min_periods=window).mean()
        std = close.rolling(window, min_periods=window).std(ddof=0).replace(0, np.nan)
        dataframe["hs_zscore"] = (close - mean) / std
        dataframe["hs_atr_pct"] = ta.ATR(dataframe, timeperiod=14) / close.replace(0, np.nan)
        return dataframe

    def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        close = pd.to_numeric(dataframe["close"], errors="coerce")
        h = pd.to_numeric(dataframe["hurst"], errors="coerce")
        z = pd.to_numeric(dataframe["hs_zscore"], errors="coerce")
        fast = pd.to_numeric(dataframe["hs_ema_fast"], errors="coerce")
        slow = pd.to_numeric(dataframe["hs_ema_slow"], errors="coerce")
        liquid = pd.to_numeric(dataframe["volume"], errors="coerce") > 0

        trend_long = liquid & (h >= float(self.buy_hurst_trend_min.value)) & (close > fast) & (fast > slow)
        trend_short = liquid & (h >= float(self.buy_hurst_trend_min.value)) & (close < fast) & (fast < slow)
        revert_long = liquid & (h <= float(self.buy_hurst_revert_max.value)) & (z <= -float(self.buy_z_entry.value))
        revert_short = liquid & (h <= float(self.buy_hurst_revert_max.value)) & (z >= float(self.buy_z_entry.value))

        dataframe["enter_long"] = (trend_long | revert_long).fillna(False).astype(int)
        dataframe["enter_short"] = (trend_short | revert_short).fillna(False).astype(int)
        dataframe["enter_tag"] = ""
        dataframe.loc[trend_long, "enter_tag"] = "hurst_trend_long"
        dataframe.loc[trend_short, "enter_tag"] = "hurst_trend_short"
        dataframe.loc[revert_long, "enter_tag"] = "hurst_revert_long"
        dataframe.loc[revert_short, "enter_tag"] = "hurst_revert_short"
        return dataframe

    def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        z = pd.to_numeric(dataframe["hs_zscore"], errors="coerce")
        dataframe["exit_long"] = (z >= -float(self.sell_z_exit.value)).fillna(False).astype(int)
        dataframe["exit_short"] = (z <= float(self.sell_z_exit.value)).fillna(False).astype(int)
        dataframe["exit_tag"] = "hurst_mean_reverted"
        return dataframe
