# source: https://raw.githubusercontent.com/markelayan/hhec-dois-bull-manager/09fa8d07121e68880686b2f9b8d4201bca0dd669/1strategies1/ClaudeScalping.py
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
# isort: skip_file
# --- Do not remove these libs ---
import numpy as np
import pandas as pd
from pandas import DataFrame
from datetime import datetime, timedelta
from typing import Optional, Union

from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
                                IntParameter, IStrategy, merge_informative_pair)

# --------------------------------
# Add your lib to import here
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib


class Github_markelayan_hhec_dois_bull_manager__ClaudeScalping__20250810_092830(IStrategy):
    """
    Professional High-Frequency Scalping Strategy with High Leverage
    
    Optimized for:
    - 1-5 minute timeframes
    - High leverage (10-20x)
    - Low margin requirements
    - Quick entries/exits
    - Momentum-based scalping
    - Tight risk management
    - Volume spike detection
    - Orderbook analysis
    
    Features:
    - Ultra-fast signals with minimal lag
    - Scalping-specific indicators (Bollinger Bands, RSI, MACD)
    - Volume confirmation for entries
    - Tight stops with trailing functionality
    - High win rate, low risk/reward ratio approach
    - Designed for hyperopt, backtesting, FreqAI and ML
    """

    INTERFACE_VERSION = 3

    # Scalping-optimized ROI - Quick profits
    minimal_roi = {
        "0": 0.02,     # 2% at any time
        "1": 0.015,    # 1.5% after 1 minute
        "3": 0.01,     # 1% after 3 minutes
        "5": 0.008,    # 0.8% after 5 minutes
        "10": 0.005,   # 0.5% after 10 minutes
        "15": 0.003,   # 0.3% after 15 minutes
        "30": 0.001    # 0.1% after 30 minutes
    }

    # Tight stoploss for scalping
    stoploss = -0.015  # 1.5% stoploss - tight for high leverage

    # Scalping timeframe
    timeframe = '1m'
    
    # Informative timeframes for context
    inf_5m = '5m'
    inf_15m = '15m'

    # Process only new candles for speed
    process_only_new_candles = True

    # Use exit signals
    use_exit_signal = True
    exit_profit_only = True
    ignore_roi_if_entry_signal = False

    # Minimal startup candles for speed
    startup_candle_count: int = 50

    # Strategy parameters - Hyperopt enabled for scalping
    
    # === Momentum Parameters ===
    rsi_period = IntParameter(5, 14, default=7, space='buy', optimize=True)
    rsi_entry_long = IntParameter(30, 50, default=40, space='buy', optimize=True)
    rsi_entry_short = IntParameter(50, 70, default=60, space='sell', optimize=True)
    rsi_exit_long = IntParameter(65, 85, default=75, space='sell', optimize=True)
    rsi_exit_short = IntParameter(15, 35, default=25, space='sell', optimize=True)
    
    # === Bollinger Bands ===
    bb_period = IntParameter(10, 25, default=20, space='buy', optimize=True)
    bb_std = DecimalParameter(1.5, 2.5, default=2.0, space='buy', optimize=True)
    
    # === MACD ===
    macd_fast = IntParameter(8, 15, default=12, space='buy', optimize=True)
    macd_slow = IntParameter(20, 30, default=26, space='buy', optimize=True)
    macd_signal = IntParameter(7, 12, default=9, space='buy', optimize=True)
    
    # === EMA ===
    ema_fast = IntParameter(5, 12, default=8, space='buy', optimize=True)
    ema_slow = IntParameter(15, 25, default=21, space='buy', optimize=True)
    
    # === Volume ===
    volume_factor = DecimalParameter(1.2, 3.0, default=2.0, space='buy', optimize=True)
    volume_ma_period = IntParameter(5, 20, default=10, space='buy', optimize=True)
    
    # === ADX for trend strength ===
    adx_period = IntParameter(10, 20, default=14, space='buy', optimize=True)
    adx_threshold = IntParameter(20, 40, default=25, space='buy', optimize=True)
    
    # === Stochastic ===
    stoch_k = IntParameter(10, 20, default=14, space='buy', optimize=True)
    stoch_d = IntParameter(3, 8, default=3, space='buy', optimize=True)
    stoch_smooth = IntParameter(3, 8, default=3, space='buy', optimize=True)
    
    # === Exit Parameters ===
    trailing_stop = BooleanParameter(default=True, space='sell', optimize=True)
    trailing_stop_positive = DecimalParameter(0.005, 0.02, default=0.01, space='sell', optimize=True)
    trailing_stop_positive_offset = DecimalParameter(0.01, 0.03, default=0.015, space='sell', optimize=True)
    
    # === Risk Management ===
    max_open_trades = 5
    position_adjustment_enable = False  # No DCA for scalping

    def informative_pairs(self):
        """
        Define informative pairs for context
        """
        pairs = self.dp.current_whitelist()
        informative_pairs = [(pair, self.inf_5m) for pair in pairs]
        informative_pairs += [(pair, self.inf_15m) for pair in pairs]
        return informative_pairs

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Populate indicators optimized for scalping
        """
        
        # === Price Action ===
        dataframe['hl2'] = (dataframe['high'] + dataframe['low']) / 2
        dataframe['hlc3'] = (dataframe['high'] + dataframe['low'] + dataframe['close']) / 3
        
        # === EMAs ===
        dataframe['ema_fast'] = ta.EMA(dataframe, timeperiod=self.ema_fast.value)
        dataframe['ema_slow'] = ta.EMA(dataframe, timeperiod=self.ema_slow.value)
        
        # === RSI ===
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=self.rsi_period.value)
        
        # === Bollinger Bands ===
        bollinger = qtpylib.bollinger_bands(dataframe['close'], 
                                           window=self.bb_period.value, 
                                           stds=self.bb_std.value)
        dataframe['bb_lower'] = bollinger['lower']
        dataframe['bb_middle'] = bollinger['mid']
        dataframe['bb_upper'] = bollinger['upper']
        dataframe['bb_percent'] = ((dataframe['close'] - dataframe['bb_lower']) / 
                                  (dataframe['bb_upper'] - dataframe['bb_lower']))
        dataframe['bb_width'] = ((dataframe['bb_upper'] - dataframe['bb_lower']) / 
                                dataframe['bb_middle'])
        
        # === MACD ===
        macd = ta.MACD(dataframe, 
                      fastperiod=self.macd_fast.value,
                      slowperiod=self.macd_slow.value, 
                      signalperiod=self.macd_signal.value)
        dataframe['macd'] = macd['macd']
        dataframe['macdsignal'] = macd['macdsignal']
        dataframe['macdhist'] = macd['macdhist']
        
        # === Stochastic ===
        stoch = ta.STOCH(dataframe,
                        fastk_period=self.stoch_k.value,
                        slowk_period=self.stoch_d.value,
                        slowd_period=self.stoch_smooth.value)
        dataframe['stoch_k'] = stoch['slowk']
        dataframe['stoch_d'] = stoch['slowd']
        
        # === ADX ===
        dataframe['adx'] = ta.ADX(dataframe, timeperiod=self.adx_period.value)
        dataframe['di_plus'] = ta.PLUS_DI(dataframe, timeperiod=self.adx_period.value)
        dataframe['di_minus'] = ta.MINUS_DI(dataframe, timeperiod=self.adx_period.value)
        
        # === Volume Analysis ===
        dataframe['volume_sma'] = ta.SMA(dataframe['volume'], timeperiod=self.volume_ma_period.value)
        dataframe['volume_ratio'] = dataframe['volume'] / dataframe['volume_sma']
        dataframe['high_volume'] = dataframe['volume_ratio'] > self.volume_factor.value
        
        # === VWAP ===
        dataframe['vwap'] = qtpylib.vwap(dataframe)
        
        # === ATR for volatility ===
        dataframe['atr'] = ta.ATR(dataframe, timeperiod=7)  # Shorter period for scalping
        
        # === Price Position Analysis ===
        dataframe['close_above_ema_fast'] = dataframe['close'] > dataframe['ema_fast']
        dataframe['close_above_ema_slow'] = dataframe['close'] > dataframe['ema_slow']
        dataframe['ema_fast_above_slow'] = dataframe['ema_fast'] > dataframe['ema_slow']
        
        # === Scalping-specific indicators ===
        dataframe = self.calculate_scalping_signals(dataframe)
        
        # === Higher timeframe context ===
        dataframe = self.populate_higher_timeframe_indicators(dataframe, metadata)
        
        return dataframe

    def calculate_scalping_signals(self, dataframe: DataFrame) -> DataFrame:
        """
        Calculate scalping-specific signals
        """
        
        # Price momentum
        dataframe['price_change'] = dataframe['close'].pct_change()
        dataframe['price_momentum_3'] = dataframe['close'].pct_change(3)
        dataframe['price_momentum_5'] = dataframe['close'].pct_change(5)
        
        # Volume momentum
        dataframe['volume_change'] = dataframe['volume'].pct_change()
        dataframe['volume_momentum'] = dataframe['volume'].rolling(3).mean() / dataframe['volume'].rolling(10).mean()
        
        # Volatility squeeze
        dataframe['squeeze'] = (dataframe['bb_width'] < dataframe['bb_width'].rolling(20).quantile(0.2))
        
        # Support/Resistance levels (simple)
        dataframe['resistance'] = dataframe['high'].rolling(10).max()
        dataframe['support'] = dataframe['low'].rolling(10).min()
        dataframe['near_resistance'] = (dataframe['close'] >= dataframe['resistance'] * 0.998)
        dataframe['near_support'] = (dataframe['close'] <= dataframe['support'] * 1.002)
        
        # Candle patterns
        dataframe['doji'] = (abs(dataframe['open'] - dataframe['close']) <= (dataframe['high'] - dataframe['low']) * 0.1)
        dataframe['hammer'] = (
            (dataframe['close'] > dataframe['open']) &
            ((dataframe['close'] - dataframe['open']) / (0.001 + dataframe['high'] - dataframe['low']) > 0.6) &
            ((dataframe['open'] - dataframe['low']) / (0.001 + dataframe['high'] - dataframe['low']) > 0.6)
        )
        
        return dataframe

    def populate_higher_timeframe_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Add higher timeframe context
        """
        # 5m context
        inf_5m = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_5m)
        inf_5m['ema_trend_5m'] = ta.EMA(inf_5m, timeperiod=20)
        inf_5m['rsi_5m'] = ta.RSI(inf_5m, timeperiod=14)
        inf_5m['trend_5m'] = (inf_5m['close'] > inf_5m['ema_trend_5m']).astype(int)
        
        dataframe = merge_informative_pair(dataframe, inf_5m, self.timeframe, self.inf_5m, ffill=True)
        
        # 15m context
        inf_15m = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_15m)
        inf_15m['ema_trend_15m'] = ta.EMA(inf_15m, timeperiod=20)
        inf_15m['trend_15m'] = (inf_15m['close'] > inf_15m['ema_trend_15m']).astype(int)
        
        dataframe = merge_informative_pair(dataframe, inf_15m, self.timeframe, self.inf_15m, ffill=True)
        
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Scalping entry signals - fast and aggressive
        """
        
        # === LONG CONDITIONS ===
        
        # 1. Trend alignment
        trend_bullish = (
            (dataframe['ema_fast_above_slow']) &
            (dataframe['close_above_ema_fast']) &
            (dataframe['trend_5m'] == 1) &
            (dataframe['trend_15m'] == 1)
        )
        
        # 2. Momentum conditions
        momentum_bullish = (
            (dataframe['rsi'] > self.rsi_entry_long.value) &
            (dataframe['rsi'] < 70) &  # Not overbought
            (dataframe['macd'] > dataframe['macdsignal']) &
            (dataframe['macdhist'] > 0) &
            (dataframe['stoch_k'] > 20) &
            (dataframe['stoch_k'] < 80)
        )
        
        # 3. Price action
        price_action_bullish = (
            (dataframe['close'] > dataframe['vwap']) &
            (dataframe['close'] > dataframe['bb_middle']) &
            (dataframe['bb_percent'] > 0.2) &  # Not at bottom of BB
            (~dataframe['near_resistance'])  # Not at resistance
        )
        
        # 4. Volume confirmation
        volume_bullish = (
            (dataframe['high_volume']) &
            (dataframe['volume_momentum'] > 1.1) &
            (dataframe['volume_change'] > 0)
        )
        
        # 5. Volatility and ADX
        volatility_ok = (
            (dataframe['adx'] > self.adx_threshold.value) &  # Strong trend
            (dataframe['di_plus'] > dataframe['di_minus']) &
            (~dataframe['squeeze'])  # Not in squeeze
        )
        
        # 6. Entry triggers
        entry_triggers = (
            (dataframe['price_momentum_3'] > 0.002) |  # Recent momentum
            (dataframe['hammer']) |  # Hammer pattern
            (dataframe['close'] > dataframe['bb_middle'].shift(1))  # Breaking BB middle
        )
        
        dataframe.loc[
            (trend_bullish) &
            (momentum_bullish) &
            (price_action_bullish) &
            (volume_bullish) &
            (volatility_ok) &
            (entry_triggers),
            'enter_long'] = 1

        # === SHORT CONDITIONS ===
        
        # 1. Trend alignment
        trend_bearish = (
            (~dataframe['ema_fast_above_slow']) &
            (~dataframe['close_above_ema_fast']) &
            (dataframe['trend_5m'] == 0) &
            (dataframe['trend_15m'] == 0)
        )
        
        # 2. Momentum conditions
        momentum_bearish = (
            (dataframe['rsi'] < self.rsi_entry_short.value) &
            (dataframe['rsi'] > 30) &  # Not oversold
            (dataframe['macd'] < dataframe['macdsignal']) &
            (dataframe['macdhist'] < 0) &
            (dataframe['stoch_k'] > 20) &
            (dataframe['stoch_k'] < 80)
        )
        
        # 3. Price action
        price_action_bearish = (
            (dataframe['close'] < dataframe['vwap']) &
            (dataframe['close'] < dataframe['bb_middle']) &
            (dataframe['bb_percent'] < 0.8) &  # Not at top of BB
            (~dataframe['near_support'])  # Not at support
        )
        
        # 4. Volume confirmation
        volume_bearish = (
            (dataframe['high_volume']) &
            (dataframe['volume_momentum'] > 1.1) &
            (dataframe['volume_change'] > 0)
        )
        
        # 5. Volatility and ADX
        volatility_ok_short = (
            (dataframe['adx'] > self.adx_threshold.value) &  # Strong trend
            (dataframe['di_minus'] > dataframe['di_plus']) &
            (~dataframe['squeeze'])  # Not in squeeze
        )
        
        # 6. Entry triggers
        entry_triggers_short = (
            (dataframe['price_momentum_3'] < -0.002) |  # Recent negative momentum
            (dataframe['close'] < dataframe['bb_middle'].shift(1))  # Breaking BB middle down
        )
        
        dataframe.loc[
            (trend_bearish) &
            (momentum_bearish) &
            (price_action_bearish) &
            (volume_bearish) &
            (volatility_ok_short) &
            (entry_triggers_short),
            'enter_short'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Scalping exit signals - quick profits
        """
        
        # === EXIT LONG ===
        
        exit_long_conditions = (
            (dataframe['rsi'] > self.rsi_exit_long.value) |  # Overbought
            (dataframe['macd'] < dataframe['macdsignal']) |  # MACD cross down
            (dataframe['close'] < dataframe['ema_fast']) |  # Below fast EMA
            (dataframe['stoch_k'] > 80) |  # Stochastic overbought
            (dataframe['close'] >= dataframe['bb_upper'] * 0.999) |  # At BB upper
            (dataframe['near_resistance']) |  # At resistance
            (dataframe['volume_ratio'] < 0.8)  # Volume drying up
        )
        
        dataframe.loc[exit_long_conditions, 'exit_long'] = 1
        
        # === EXIT SHORT ===
        
        exit_short_conditions = (
            (dataframe['rsi'] < self.rsi_exit_short.value) |  # Oversold
            (dataframe['macd'] > dataframe['macdsignal']) |  # MACD cross up
            (dataframe['close'] > dataframe['ema_fast']) |  # Above fast EMA
            (dataframe['stoch_k'] < 20) |  # Stochastic oversold
            (dataframe['close'] <= dataframe['bb_lower'] * 1.001) |  # At BB lower
            (dataframe['near_support']) |  # At support
            (dataframe['volume_ratio'] < 0.8)  # Volume drying up
        )
        
        dataframe.loc[exit_short_conditions, 'exit_short'] = 1

        return dataframe

    def leverage(self, pair: str, current_time: datetime, current_rate: float,
                 proposed_leverage: float, max_leverage: float, entry_tag: Optional[str],
                 side: str, **kwargs) -> float:
        """
        High leverage for scalping
        """
        return min(proposed_leverage, 20.0)  # Up to 20x leverage

    def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
                       current_rate: float, current_profit: float, **kwargs) -> float:
        """
        Scalping-optimized trailing stop
        """
        if not self.trailing_stop.value:
            return self.stoploss
            
        # Trailing stop for scalping
        if current_profit > self.trailing_stop_positive.value:
            return self.trailing_stop_positive_offset.value - current_profit
        
        return self.stoploss

    def confirm_trade_entry(self, pair: str, order_type: str, amount: float,
                           rate: float, time_in_force: str, current_time: datetime,
                           entry_tag: Optional[str], side: str, **kwargs) -> bool:
        """
        Final entry confirmation for scalping
        """
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
        last_candle = dataframe.iloc[-1].squeeze()
        
        # Scalping safety checks
        # 1. Ensure decent volume
        if last_candle['volume_ratio'] < 1.2:
            return False
        
        # 2. Not during low volatility
        if last_candle['squeeze']:
            return False
        
        # 3. ADX strong enough
        if last_candle['adx'] < 20:
            return False
        
        return True

    def custom_exit(self, pair: str, trade: 'Trade', current_time: datetime, current_rate: float,
                   current_profit: float, **kwargs) -> Optional[Union[str, bool]]:
        """
        Custom scalping exits
        """
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
        last_candle = dataframe.iloc[-1].squeeze()
        
        # Quick profit taking
        if current_profit > 0.015:  # 1.5% profit
            return "scalp_profit"
        
        # Volume drying up
        if last_candle['volume_ratio'] < 0.6 and current_profit > 0.005:
            return "volume_exit"
        
        # Momentum reversal
        if trade.is_open:
            if (trade.is_short and last_candle['macd'] > last_candle['macdsignal'] and 
                current_profit > 0.003):
                return "momentum_reversal"
            elif (not trade.is_short and last_candle['macd'] < last_candle['macdsignal'] and 
                  current_profit > 0.003):
                return "momentum_reversal"
        
        return None

    def bot_loop_start(self, **kwargs) -> None:
        """
        Called at the start of each bot loop
        """
        pass

    def check_entry_timeout(self, pair: str, trade: 'Trade', order: 'Order',
                           current_time: datetime, **kwargs) -> bool:
        """
        Scalping - cancel entries quickly if not filled
        """
        return False

    def check_exit_timeout(self, pair: str, trade: 'Trade', order: 'Order',
                          current_time: datetime, **kwargs) -> bool:
        """
        Scalping - cancel exits quickly if not filled
        """
        return False