# source: https://raw.githubusercontent.com/camster91/crypto-bots/96f56c8fd946079607e2fe6405c07226fe198aa0/bot-instance/user_data/strategies/FreqAIStrategy.py
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
import logging
import numpy as np
import pandas as pd
from pandas import DataFrame
from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib

logger = logging.getLogger(__name__)


class Github_camster91_crypto_bots__FreqAIStrategy__20260520_151918(IStrategy):
    """
    FreqAI Machine Learning Strategy Template.

    Uses Freqtrade's built-in FreqAI module to train a classifier
    that predicts price direction using technical indicators as features.

    Model: LightGBMClassifier (default) or RandomForest
    Target: Predict if price will rise > 1% in next 24 candles (2 hours)

    Features used:
    - RSI (14)
    - MACD histogram
    - Bollinger Band position (%)
    - EMA slopes (fast/slow)
    - Volume ratio
    - ATR (normalized)
    - ADX

    REQUIRES: freqai config section in config.json
    See: freqai/freqai_config.json for full setup

    Paper trade for minimum 2 weeks before going live.
    Model needs 500+ candles to train initially.
    """

    INTERFACE_VERSION = 3
    freqai_info: dict = {}

    # Entry/exit thresholds (model outputs probability 0-1)
    entry_threshold = DecimalParameter(0.5, 0.9, default=0.6, space="buy", decimals=2)
    exit_threshold = DecimalParameter(0.1, 0.5, default=0.4, space="sell", decimals=2)

    minimal_roi = {"60": 0.01, "30": 0.02, "0": 0.04}
    stoploss = -0.10
    trailing_stop = True
    trailing_stop_positive = 0.02
    trailing_stop_positive_offset = 0.04
    trailing_only_offset_is_reached = True

    timeframe = "5m"
    process_only_new_candles = True
    startup_candle_count: int = 40
    can_short = False

    def feature_engineering_expand_all(self, dataframe: DataFrame, period: int,
                                        metadata: dict, **kwargs) -> DataFrame:
        """
        FreqAI feature engineering — called for each period in indicator_periods_candles.
        Features prefixed with %% are used as ML inputs.
        """
        dataframe[f"%rsi-period_{period}"] = ta.RSI(dataframe, timeperiod=period)

        macd = ta.MACD(dataframe, fastperiod=period, slowperiod=period * 2, signalperiod=period // 2)
        dataframe[f"%macd-period_{period}"] = macd["macdhist"]

        dataframe[f"%ema_fast-period_{period}"] = ta.EMA(dataframe, timeperiod=period)
        dataframe[f"%ema_slow-period_{period}"] = ta.EMA(dataframe, timeperiod=period * 2)

        dataframe[f"%atr-period_{period}"] = ta.ATR(dataframe, timeperiod=period) / dataframe["close"]

        bollinger = qtpylib.bollinger_bands(
            qtpylib.typical_price(dataframe), window=period, stds=2
        )
        dataframe[f"%bb_percent-period_{period}"] = (
            (dataframe["close"] - bollinger["lower"]) /
            (bollinger["upper"] - bollinger["lower"] + 1e-6)
        )

        return dataframe

    def feature_engineering_standard(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
        """Standard features added once (not per period)."""
        dataframe["%adx"] = ta.ADX(dataframe, timeperiod=14)
        dataframe["%volume_ratio"] = dataframe["volume"] / dataframe["volume"].rolling(20).mean()
        dataframe["%day_of_week"] = pd.to_datetime(dataframe["date"]).dt.dayofweek
        dataframe["%hour_of_day"] = pd.to_datetime(dataframe["date"]).dt.hour
        return dataframe

    def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
        """
        Define the target variable for training.
        &target_roi = 1 if price rises > 1% in next 24 candles, else 0.
        """
        dataframe["&target_roi"] = (
            dataframe["close"].shift(-24) > dataframe["close"] * 1.01
        ).astype(int)
        return dataframe

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """Standard indicators (non-FreqAI, for entry/exit logic)."""
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
        dataframe["volume_mean"] = dataframe["volume"].rolling(window=20).mean()

        # FreqAI prediction columns are added automatically after this
        dataframe = self.freqai.start(dataframe, metadata, self)

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # FreqAI outputs: do_predict (1=trade, 0=skip), &target_roi_mean (probability)
        enter_long_conditions = [
            dataframe["do_predict"] == 1,
            dataframe["&target_roi_mean"] > self.entry_threshold.value,
            dataframe["volume"] > 0.8 * dataframe["volume_mean"],
        ]

        if enter_long_conditions:
            dataframe.loc[
                pd.concat([c.to_frame() for c in enter_long_conditions], axis=1).all(axis=1),
                "enter_long",
            ] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        exit_long_conditions = [
            dataframe["do_predict"] == 1,
            dataframe["&target_roi_mean"] < self.exit_threshold.value,
        ]

        if exit_long_conditions:
            dataframe.loc[
                pd.concat([c.to_frame() for c in exit_long_conditions], axis=1).all(axis=1),
                "exit_long",
            ] = 1

        return dataframe
