# source: https://raw.githubusercontent.com/OzzyHA-company/OZ_A2M/912c2113f6005e902c1220b6d3978d302930c6bc/department_7/strategies/scalping.py
"""
OZ_A2M Scalping Strategy for Department 7.

This is a high-frequency scalping strategy optimized for 5-minute candles.
Uses RSI, EMA, and Volume indicators for entry/exit signals.
"""

import logging
from typing import Optional

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

logger = logging.getLogger(__name__)


class Github_OzzyHA_company_OZ_A2M__scalping__20260403_071544(IStrategy):
    """
    OZ_A2M Scalping Strategy.

    Optimized for:
    - 5-minute timeframe
    - Major pairs (BTC, ETH, etc.)
    - Quick entries/exits (2-4% target)
    - Tight stop-loss (2%)
    """

    # Strategy metadata
    INTERFACE_VERSION = 3

    # Minimal ROI designed for quick scalping
    minimal_roi = {
        "0": 0.04,    # 4% profit at 0 minutes
        "30": 0.02,   # 2% profit after 30 minutes
        "60": 0.01,   # 1% profit after 60 minutes
        "120": 0      # Exit at breakeven after 120 minutes
    }

    # Stoploss: 2% (aggressive scalping)
    stoploss = -0.02

    # Trailing stop
    trailing_stop = True
    trailing_stop_positive = 0.01
    trailing_stop_positive_offset = 0.02
    trailing_only_offset_is_reached = True

    # Timeframe
    timeframe = '5m'

    # Run "populate_indicators" only for new candle
    process_only_new_candles = True

    # These values can be overridden in the config
    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = False

    # Number of candles the strategy requires to keep
    startup_candle_count: int = 30

    # Hyperopt parameters
    buy_rsi = IntParameter(10, 40, default=30, space="buy")
    buy_fast_ema_period = IntParameter(5, 20, default=9, space="buy")
    buy_slow_ema_period = IntParameter(15, 50, default=21, space="buy")

    sell_rsi = IntParameter(60, 90, default=70, space="sell")
    sell_fast_ema_period = IntParameter(5, 20, default=9, space="sell")

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """Add technical indicators to the dataframe."""

        # RSI
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)

        # EMA
        dataframe['ema9'] = ta.EMA(dataframe, timeperiod=9)
        dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21)
        dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)

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

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

        # Bollinger Bands
        bollinger = ta.BBANDS(dataframe, timeperiod=20)
        dataframe['bb_lower'] = bollinger['lowerband']
        dataframe['bb_middle'] = bollinger['middleband']
        dataframe['bb_upper'] = bollinger['upperband']
        dataframe['bb_width'] = (dataframe['bb_upper'] - dataframe['bb_lower']) / dataframe['bb_middle']

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

        return dataframe

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

        # Condition 1: RSI oversold
        conditions.append(dataframe['rsi'] < self.buy_rsi.value)

        # Condition 2: EMA crossover (fast > slow)
        conditions.append(dataframe['ema9'] > dataframe['ema21'])

        # Condition 3: Price above EMA50 (uptrend)
        conditions.append(dataframe['close'] > dataframe['ema50'])

        # Condition 4: MACD bullish
        conditions.append(dataframe['macd'] > dataframe['macdsignal'])

        # Condition 5: Volume confirmation
        conditions.append(dataframe['volume_ratio'] > 1.2)

        # Condition 6: Price near lower BB (mean reversion)
        conditions.append(dataframe['close'] < dataframe['bb_lower'] * 1.02)

        if conditions:
            dataframe.loc[
                pd.concat(conditions, axis=1).all(axis=1),
                'enter_long'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """Define exit conditions."""
        conditions = []

        # Condition 1: RSI overbought
        conditions.append(dataframe['rsi'] > self.sell_rsi.value)

        # Condition 2: EMA crossover (fast < slow)
        conditions.append(dataframe['ema9'] < dataframe['ema21'])

        # Condition 3: MACD bearish
        conditions.append(dataframe['macd'] < dataframe['macdsignal'])

        # Condition 4: Price near upper BB
        conditions.append(dataframe['close'] > dataframe['bb_upper'] * 0.98)

        if conditions:
            dataframe.loc[
                pd.concat(conditions, axis=1).all(axis=1),
                'exit_long'] = 1

        return dataframe

    def leverage(self, pair: str, current_time, current_rate: float,
                 proposed_leverage: float, max_leverage: float, entry_tag: Optional[str], side: str,
                 **kwargs) -> float:
        """Define leverage - 1x for spot trading."""
        return 1.0
