# source: https://raw.githubusercontent.com/groxaxo/op-web-projects/cc4820bf964638628d65114257b1de8d652ae579/grok-harmony-trader/config/strategies/HarmonyMLStrategy.py
"""Github_groxaxo_op_web_projects__HarmonyMLStrategy__20260527_084945 — FreqAI strategy for grok-harmony-trader.

Targets an 8-bar forward return percentage as the FreqAI prediction label.
Long entries fire when do_predict==1 and the model is confident the price
will rise. Short entries are defined but disabled via can_short=False.
"""

from __future__ import annotations

import talib.abstract as ta
from freqtrade.strategy import IStrategy
from pandas import DataFrame


class Github_groxaxo_op_web_projects__HarmonyMLStrategy__20260527_084945(IStrategy):
    timeframe = "5m"
    can_short = False
    minimal_roi = {"0": 0.05}
    stoploss = -0.03
    process_only_new_candles = True
    startup_candle_count = 50

    # ── FreqAI hooks ───────────────────────────────────────────────────────

    def feature_engineering_expand_all(
        self, dataframe: DataFrame, period: int, metadata: dict, **kwargs
    ) -> DataFrame:
        """Add technical indicators for FreqAI feature set."""
        # EMA 20
        dataframe["%-ema20"] = ta.EMA(dataframe, timeperiod=20)

        # RSI 14
        dataframe["%-rsi14"] = ta.RSI(dataframe, timeperiod=14)

        # ATR 14
        dataframe["%-atr14"] = ta.ATR(dataframe, timeperiod=14)

        # Bollinger Bands (20, 2)
        upper, middle, lower = ta.BBANDS(dataframe, timeperiod=20, nbdevup=2, nbdevdn=2, matype=0)
        dataframe["%-bb_upper"] = upper
        dataframe["%-bb_middle"] = middle
        dataframe["%-bb_lower"] = lower
        dataframe["%-bb_width"] = (upper - lower) / middle.where(middle != 0, 1)

        # Volume mean ratio: current volume vs 20-bar rolling mean
        dataframe["%-volume_mean_ratio"] = dataframe["volume"] / (
            dataframe["volume"].rolling(20).mean().replace(0, 1)
        )

        return dataframe

    def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
        """Define the prediction target: 8-bar forward return percentage."""
        dataframe["&-regime_direction"] = (
            dataframe["close"].shift(-8) / dataframe["close"] - 1
        ) * 100
        return dataframe

    # ── Standard strategy hooks ────────────────────────────────────────────

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """Run FreqAI model and compute ATR for downstream use."""
        dataframe = self.freqai.start(dataframe, metadata, self)

        # Standalone ATR14 (not prefixed) for stop-loss calculations in exit logic
        dataframe["atr14"] = ta.ATR(dataframe, timeperiod=14)

        # Normalise confidence: absolute prediction scaled to [0, 1]
        if "&-regime_direction" in dataframe.columns:
            dataframe["confidence"] = (dataframe["&-regime_direction"].abs() / 100.0).clip(
                upper=1.0
            )
        else:
            dataframe["confidence"] = 0.0

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """Long entry: FreqAI is confident in a bullish 8-bar move."""
        dataframe.loc[
            (
                (dataframe["do_predict"] == 1)
                & (dataframe["&-regime_direction"] > 0.5)
                & (dataframe["confidence"] > 0.6)
                & (dataframe["volume"] > 0)
            ),
            "enter_long",
        ] = 1

        # Short entries defined but disabled (can_short=False)
        dataframe.loc[
            (
                (dataframe["do_predict"] == 1)
                & (dataframe["&-regime_direction"] < -0.5)
                & (dataframe["volume"] > 0)
            ),
            "enter_short",
        ] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """Exit long when the model predicts a negative direction."""
        dataframe.loc[
            ((dataframe["do_predict"] == 1) & (dataframe["&-regime_direction"] < 0)),
            "exit_long",
        ] = 1

        dataframe.loc[
            ((dataframe["do_predict"] == 1) & (dataframe["&-regime_direction"] > 0)),
            "exit_short",
        ] = 1

        return dataframe
