# source: https://raw.githubusercontent.com/EJMC95/crypto-trading-bot/02ae8421867e1e62555167b55d643f34165cd644/user_data/strategies/NostalgiaForInfinityX7.py
# directory_url: https://github.com/EJMC95/crypto-trading-bot/blob/main/user_data/strategies/
# User: EJMC95
# Repository: crypto-trading-bot
# --------------------"""
Github_EJMC95_crypto_trading_bot__NostalgiaForInfinityX7__20260911_153029 — Freqtrade strategy for Mum (freqtrade-mum)
Based on the NFI X7 concept: combines trend, RSI, Bollinger Bands, EMA structure
and volume confirmation for 5m entries on Binance spot.

Paper trading only — dry_run: true, $1000 starting wallet.
"""
import numpy as np
import pandas as pd
from freqtrade.strategy import IStrategy, DecimalParameter, IntParameter
from pandas import DataFrame
import talib.abstract as ta


class Github_EJMC95_crypto_trading_bot__NostalgiaForInfinityX7__20260911_153029(IStrategy):
    """
    NFI X7 — trend-following with multi-timeframe confluence.
    5m candles, Binance spot, paper trading.
    """
    INTERFACE_VERSION = 3
    timeframe = '5m'
    startup_candle_count = 200
    stoploss = -0.10
    trailing_stop = True
    trailing_stop_positive = 0.02
    trailing_stop_positive_offset = 0.04
    trailing_only_offset_is_reached = True
    use_custom_stoploss = False
    minimal_roi = {
        "0": 0.06,
        "30": 0.04,
        "60": 0.025,
        "120": 0.01,
    }
    process_only_new_candles = True
    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = False

    # Buy hyperspace params
    buy_rsi_fast = IntParameter(20, 45, default=35, space='buy', optimize=True)
    buy_rsi = IntParameter(15, 40, default=30, space='buy', optimize=True)
    buy_bb_factor = DecimalParameter(0.97, 0.999, default=0.986, space='buy', optimize=True)
    buy_ema_cofi = DecimalParameter(0.96, 1.0, default=0.97, space='buy', optimize=True)

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # RSI
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=4)
        dataframe['rsi_slow'] = ta.RSI(dataframe, timeperiod=20)

        # Bollinger Bands
        bollinger = ta.BBANDS(dataframe, timeperiod=20, nbdevup=2.0, nbdevdn=2.0, matype=0)
        dataframe['bb_lowerband'] = bollinger['lowerband']
        dataframe['bb_middleband'] = bollinger['middleband']
        dataframe['bb_upperband'] = bollinger['upperband']
        dataframe['bb_width'] = (dataframe['bb_upperband'] - dataframe['bb_lowerband']) / dataframe['bb_middleband']

        # EMAs
        dataframe['ema_5'] = ta.EMA(dataframe, timeperiod=5)
        dataframe['ema_12'] = ta.EMA(dataframe, timeperiod=12)
        dataframe['ema_20'] = ta.EMA(dataframe, timeperiod=20)
        dataframe['ema_26'] = ta.EMA(dataframe, timeperiod=26)
        dataframe['ema_50'] = ta.EMA(dataframe, timeperiod=50)
        dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200)

        # MACD
        macd = ta.MACD(dataframe)
        dataframe['macd'] = macd['macd']
        dataframe['macdsignal'] = macd['macdsignal']

        # Volume MA
        dataframe['volume_mean_slow'] = dataframe['volume'].rolling(window=20).mean()

        # Heikin Ashi
        dataframe['ha_open'] = (dataframe['open'].shift(1) + dataframe['close'].shift(1)) / 2
        dataframe['ha_close'] = (dataframe['open'] + dataframe['high'] + dataframe['low'] + dataframe['close']) / 4
        dataframe['ha_high'] = dataframe[['high', 'ha_open', 'ha_close']].max(axis=1)
        dataframe['ha_low'] = dataframe[['low', 'ha_open', 'ha_close']].min(axis=1)

        # CTI (Correlation Trend Indicator)
        dataframe['cti'] = dataframe['close'].rolling(20).corr(pd.Series(range(20), index=dataframe.index[-20:]).reindex(dataframe.index).fillna(method='ffill'))

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        conditions = []

        # Condition 1: RSI oversold with fast bounce
        conditions.append(
            (dataframe['rsi_fast'] < self.buy_rsi_fast.value) &
            (dataframe['rsi'] < self.buy_rsi.value) &
            (dataframe['close'] < dataframe['bb_lowerband'] * self.buy_bb_factor.value) &
            (dataframe['volume'] > 0)
        )

        # Condition 2: EMA structure + MACD cross
        conditions.append(
            (dataframe['ema_5'] > dataframe['ema_12']) &
            (dataframe['ema_12'] > dataframe['ema_20']) &
            (dataframe['macd'] > dataframe['macdsignal']) &
            (dataframe['close'] > dataframe['ema_200'] * self.buy_ema_cofi.value) &
            (dataframe['rsi'] < 55) &
            (dataframe['volume'] > dataframe['volume_mean_slow'] * 0.8)
        )

        if conditions:
            dataframe.loc[
                pd.concat([c.to_frame() for c in conditions], axis=1).any(axis=1),
                'enter_long'
            ] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (dataframe['rsi'] > 75) |
            (dataframe['ema_5'] < dataframe['ema_12']) &
            (dataframe['macd'] < dataframe['macdsignal']),
            'exit_long'
        ] = 1
        return dataframe
