# source: https://raw.githubusercontent.com/lordace-coder/freq-trader-v1/badf5c33d54a070a001b344bef74f5c6a558a190/freqtrade-bot/strategies/NoExitSignals.py
"""
No Exit Signals Strategy - Target 30% Monthly
Based on analysis showing exit signals have 12-30% win rate while ROI has 100% win rate

Key Changes:
1. NO EXIT SIGNALS (they kill profits)
2. Only use ROI and trailing stops
3. 6x leverage (aggressive but safer than 10x)
4. Tight, fast ROI targets (30%+ monthly needs fast profits)
5. BTC/ETH only (most liquid)
6. Keep proven TEMA entry logic
"""

import numpy as np
from pandas import DataFrame
from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter
import talib.abstract as ta
from datetime import datetime
from typing import Optional


class Github_lordace_coder_freq_trader_v1__NoExitSignals__20251203_210234(IStrategy):

    INTERFACE_VERSION = 3
    can_short = True

    # ULTRA-FAST ROI - Exit winners VERY quickly
    minimal_roi = {
        "0": 0.04,   # 4% immediate (0.67% real with 6x)
        "2": 0.025,  # 2.5% after 2 min
        "5": 0.02,   # 2% after 5 min
        "10": 0.015, # 1.5% after 10 min
        "20": 0.01   # 1% after 20 min
    }

    # Balanced stop loss
    stoploss = -0.12  # 12% (2% real move with 6x leverage)

    # Aggressive trailing stop
    trailing_stop = True
    trailing_stop_positive = 0.008  # Start trailing at 0.8%
    trailing_stop_positive_offset = 0.012  # Trail by 1.2%
    trailing_only_offset_is_reached = True

    timeframe = '5m'  # Fast timeframe for more opportunities
    startup_candle_count = 50

    # 6x leverage (aggressive but not crazy)
    leverage_num = IntParameter(5, 7, default=6, space='buy', optimize=False)

    # Looser entry filters (more opportunities)
    rsi_buy_long = IntParameter(35, 50, default=42, space='buy', optimize=True)
    rsi_buy_short = IntParameter(50, 65, default=58, space='buy', optimize=True)
    adx_min = IntParameter(15, 25, default=20, space='buy', optimize=True)
    volume_mult = DecimalParameter(0.8, 1.5, default=1.0, decimals=1, space='buy', optimize=True)

    # NO EXIT SIGNALS - This is critical!
    use_exit_signal = False

    def leverage(self, pair: str, current_time, current_rate: float,
                 proposed_leverage: float, max_leverage: float, side: str,
                 **kwargs) -> float:
        return self.leverage_num.value

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Fast indicators for 5min timeframe
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=9)
        dataframe['adx'] = ta.ADX(dataframe, timeperiod=9)

        # Fast EMAs for trend
        dataframe['ema12'] = ta.EMA(dataframe, timeperiod=12)
        dataframe['ema26'] = ta.EMA(dataframe, timeperiod=26)
        dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)

        # MACD for momentum
        macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
        dataframe['macd'] = macd['macd']
        dataframe['macdsignal'] = macd['macdsignal']
        dataframe['macdhist'] = macd['macdhist']

        # Bollinger Bands
        bollinger = ta.BBANDS(dataframe, timeperiod=20, nbdevup=2.0, nbdevdn=2.0)
        dataframe['bb_lower'] = bollinger['lowerband']
        dataframe['bb_middle'] = bollinger['middleband']
        dataframe['bb_upper'] = bollinger['upperband']

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

        # ATR
        dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)

        # Stochastic for oversold/overbought
        stoch = ta.STOCH(dataframe, fastk_period=14, slowk_period=3, slowd_period=3)
        dataframe['slowk'] = stoch['slowk']
        dataframe['slowd'] = stoch['slowd']

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Two types of trades:
        1. NORMAL trades - Standard signals
        2. SURE trades - All signals align (bigger position size)
        """

        # LONG - Oversold bounce in uptrend (STRICTER = fewer bad trades)
        long_conditions = (
            # Trend: Price above EMA50 AND price trending up
            (dataframe['close'] > dataframe['ema50']) &
            (dataframe['ema12'] > dataframe['ema26']) &  # EMA cross
            (dataframe['ema26'] > dataframe['ema50']) &  # All EMAs aligned

            # Momentum: RSI oversold in a CONTROLLED way
            (dataframe['rsi'] < self.rsi_buy_long.value) &
            (dataframe['rsi'] > 30) &  # Not TOO oversold (avoid falling knives)
            (dataframe['rsi'] > dataframe['rsi'].shift(1)) &  # RSI turning up

            # Trend strength - MUST be in a trend
            (dataframe['adx'] > 22) &  # Higher minimum

            # MACD MUST be bullish (not "or turning")
            (dataframe['macd'] > dataframe['macdsignal']) &
            (dataframe['macdhist'] > 0) &  # MACD above zero line

            # Volume confirmation - STRONG volume
            (dataframe['volume'] > dataframe['volume_mean'] * 1.2) &

            # Price structure: MUST be near lower BB (clear oversold)
            (dataframe['close'] < dataframe['bb_lower'] * 1.01) &

            # Stochastic oversold
            (dataframe['slowk'] < 35)
        )

        # SURE LONG - All signals strongly align (high confidence)
        sure_long = (
            long_conditions &
            (dataframe['adx'] > 25) &  # Strong trend
            (dataframe['macd'] > dataframe['macdsignal']) &  # MACD bullish
            (dataframe['slowk'] < 25) &  # Very oversold
            (dataframe['volume'] > dataframe['volume_mean'] * 1.3) &  # High volume
            (dataframe['macdhist'] > dataframe['macdhist'].shift(1))  # MACD turning up
        )

        dataframe.loc[long_conditions, 'enter_long'] = 1
        dataframe.loc[sure_long, 'enter_tag'] = 'sure_long'  # Tag for bigger position

        # SHORT - Overbought rejection in downtrend (STRICTER)
        short_conditions = (
            # Trend: Price below EMA50 AND price trending down
            (dataframe['close'] < dataframe['ema50']) &
            (dataframe['ema12'] < dataframe['ema26']) &  # EMA cross
            (dataframe['ema26'] < dataframe['ema50']) &  # All EMAs aligned

            # Momentum: RSI overbought in a CONTROLLED way
            (dataframe['rsi'] > self.rsi_buy_short.value) &
            (dataframe['rsi'] < 70) &  # Not TOO overbought
            (dataframe['rsi'] < dataframe['rsi'].shift(1)) &  # RSI turning down

            # Trend strength - MUST be in a trend
            (dataframe['adx'] > 22) &

            # MACD MUST be bearish (not "or turning")
            (dataframe['macd'] < dataframe['macdsignal']) &
            (dataframe['macdhist'] < 0) &  # MACD below zero line

            # Volume confirmation - STRONG volume
            (dataframe['volume'] > dataframe['volume_mean'] * 1.2) &

            # Price structure: MUST be near upper BB (clear overbought)
            (dataframe['close'] > dataframe['bb_upper'] * 0.99) &

            # Stochastic overbought
            (dataframe['slowk'] > 65)
        )

        # SURE SHORT - All signals strongly align (high confidence)
        sure_short = (
            short_conditions &
            (dataframe['adx'] > 25) &  # Strong trend
            (dataframe['macd'] < dataframe['macdsignal']) &  # MACD bearish
            (dataframe['slowk'] > 75) &  # Very overbought
            (dataframe['volume'] > dataframe['volume_mean'] * 1.3) &  # High volume
            (dataframe['macdhist'] < dataframe['macdhist'].shift(1))  # MACD turning down
        )

        dataframe.loc[short_conditions, 'enter_short'] = 1
        dataframe.loc[sure_short, 'enter_tag'] = 'sure_short'  # Tag for bigger position

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        NO EXIT SIGNALS - Let ROI and trailing stops handle exits
        Exit signals have 12-30% win rate, ROI has 100% win rate
        """
        # Never exit based on signals
        dataframe.loc[:, 'exit_long'] = 0
        dataframe.loc[:, 'exit_short'] = 0

        return dataframe

    def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
                           proposed_stake: float, min_stake: Optional[float],
                           max_stake: float, leverage: float, entry_tag: Optional[str],
                           side: str, **kwargs) -> float:
        """
        Dynamic position sizing:
        - SURE trades (all signals align): Use 95% of capital (GO BIG!)
        - NORMAL trades: Use 70% of capital (standard)
        """

        if entry_tag in ['sure_long', 'sure_short']:
            # SURE TRADE - All signals align, bet BIG!
            multiplier = 0.95
        else:
            # NORMAL TRADE - Standard sizing
            multiplier = 0.70

        stake = max_stake * multiplier

        if min_stake is not None:
            stake = max(stake, min_stake)

        return min(stake, max_stake)
