# source: https://raw.githubusercontent.com/imadev26/crypto-trading-bot/4335d4bd136c42854e81def5ee01afa882707de2/user_data/strategies/FastScalperPro.py
# directory_url: https://github.com/imadev26/crypto-trading-bot/blob/main/user_data/strategies/
# User: imadev26
# Repository: crypto-trading-bot
# --------------------# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
# isort: skip_file
import numpy as np
import pandas as pd
from datetime import datetime, timedelta, timezone
from pandas import DataFrame
from typing import Optional, Union, Dict

from freqtrade.strategy import (
    IStrategy,
    Trade,
    Order,
    PairLocks,
    informative,
    BooleanParameter,
    CategoricalParameter,
    DecimalParameter,
    IntParameter,
    RealParameter,
)

import talib.abstract as ta
import pandas_ta as pta
from technical import qtpylib


class Github_imadev26_crypto_trading_bot__FastScalperPro__20260831_150440(IStrategy):
    """
    ================================================================================
    Github_imadev26_crypto_trading_bot__FastScalperPro__20260831_150440 - High-Frequency Sniper Scalper (1m Timeframe)
    ================================================================================
    Built for:
    - High trade frequency (20-50 quick trades per day)
    - Quick in & out (5 to 20 minutes average trade duration)
    - High Win Rate target (70% - 80%+)
    - Fast compounding for small capital (50$)
    
    Logic:
    1. Trend Confirmation (15m): 15m Close > 15m EMA 50 (Trade only with momentum)
    2. 1m Trigger:
       - Price bounces off Lower Bollinger Band (Oversold Dip)
       - Stochastic RSI K crosses above D in Oversold zone (< 25)
       - RSI recovers above 35
       - Volume surge (Volume > 1.3x Volume SMA 15)
    3. Quick Sniper Exits:
       - Immediate Take-Profit at +1.2% to +1.8%
       - Trailing Stop locks profit after +0.8%
       - Tight Hard Stoploss at -1.6%
    """

    INTERFACE_VERSION = 3

    # Fast 1-minute execution timeframe
    timeframe = "1m"
    informative_timeframe = "15m"

    can_short: bool = False
    startup_candle_count: int = 150
    process_only_new_candles = True

    # -------------------------------------------------------------------------
    # Sniper Risk Management & Quick Take-Profit
    # -------------------------------------------------------------------------
    # Tight Stoploss (-1.6%)
    stoploss = -0.016

    # Trailing Stop: Activates quickly at +0.8% profit, trails tightly by 0.35%
    trailing_stop = True
    trailing_stop_positive = 0.0035         # 0.35% trailing gap
    trailing_stop_positive_offset = 0.008   # Triggers once +0.8% is hit
    trailing_only_offset_is_reached = True

    # Quick Sniper ROI ladder
    minimal_roi = {
        "0": 0.018,      # 1.8% immediate sniper profit
        "10": 0.012,     # 1.2% profit after 10 mins
        "20": 0.008,     # 0.8% profit after 20 mins
        "40": 0.005      # 0.5% profit after 40 mins
    }

    use_exit_signal = True
    exit_profit_only = True
    ignore_roi_if_entry_signal = False

    order_types = {
        "entry": "limit",
        "exit": "limit",
        "emergency_exit": "market",
        "force_entry": "market",
        "force_exit": "market",
        "stoploss": "market",
        "stoploss_on_exchange": False
    }

    order_time_in_force = {
        "entry": "GTC",
        "exit": "GTC"
    }

    # Protections
    protections = [
        {
            "method": "CooldownPeriod",
            "stop_duration_candles": 3
        },
        {
            "method": "StoplossGuard",
            "lookback_period_candles": 30,
            "trade_limit": 2,
            "stop_duration_candles": 30,
            "only_per_pair": True
        }
    ]

    # -------------------------------------------------------------------------
    # Informative Higher Timeframe (15 Min) Trend Filter
    # -------------------------------------------------------------------------
    @informative("15m")
    def populate_indicators_15m(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["ema_50"] = ta.EMA(dataframe, timeperiod=50)
        dataframe["ema_200"] = ta.EMA(dataframe, timeperiod=200)
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
        return dataframe

    # -------------------------------------------------------------------------
    # Base 1-Minute Scalping Indicators
    # -------------------------------------------------------------------------
    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # EMAs
        dataframe["ema_9"] = ta.EMA(dataframe, timeperiod=9)
        dataframe["ema_21"] = ta.EMA(dataframe, timeperiod=21)
        dataframe["ema_50"] = ta.EMA(dataframe, timeperiod=50)

        # RSI & Stochastic RSI (Fast momentum)
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
        stoch_rsi = ta.STOCHRSI(dataframe, timeperiod=14, fastk_period=3, fastd_period=3)
        dataframe["stoch_k"] = stoch_rsi["fastk"]
        dataframe["stoch_d"] = stoch_rsi["fastd"]

        # Bollinger Bands for Dip-Buying
        bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2.0)
        dataframe["bb_lowerband"] = bollinger["lower"]
        dataframe["bb_middleband"] = bollinger["mid"]
        dataframe["bb_upperband"] = bollinger["upper"]
        dataframe["bb_percent"] = (
            (dataframe["close"] - dataframe["bb_lowerband"]) /
            (dataframe["bb_upperband"] - dataframe["bb_lowerband"])
        )

        # Volume Moving Average
        dataframe["volume_mean_15"] = dataframe["volume"].rolling(window=15).mean()

        return dataframe

    # -------------------------------------------------------------------------
    # Entry Signals (Quick Buy Trigger)
    # -------------------------------------------------------------------------
    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        conditions = []

        # 1. Higher Timeframe 15m Trend Confirmation (Micro Bullish bias)
        conditions.append(dataframe["close_15m"] > dataframe["ema_50_15m"])
        conditions.append(dataframe["rsi_15m"] > 45)

        # 2. Oversold Bounce on 1m (Dip Buying)
        conditions.append(dataframe["close"] <= dataframe["bb_lowerband"] * 1.002) # Touched / near lower band
        conditions.append(dataframe["rsi"] < 45)
        conditions.append(dataframe["stoch_k"] < 30)                               # Stoch RSI oversold
        conditions.append(dataframe["stoch_k"] > dataframe["stoch_d"])             # Stoch Bullish Crossover

        # 3. Volume Surge (Buyer presence)
        conditions.append(dataframe["volume"] > (dataframe["volume_mean_15"] * 1.15))
        conditions.append(dataframe["volume"] > 0)

        if conditions:
            dataframe.loc[
                np.logical_and.reduce(conditions),
                "enter_long"
            ] = 1

        return dataframe

    # -------------------------------------------------------------------------
    # Exit Signals (Fast Take-Profit & Reversal)
    # -------------------------------------------------------------------------
    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        conditions = []

        # Exit when price hits upper Bollinger Band with overbought RSI
        hit_upper_bb = dataframe["close"] >= dataframe["bb_upperband"]
        rsi_overbought = dataframe["rsi"] > 70
        stoch_overbought = (dataframe["stoch_k"] > 80) & (dataframe["stoch_k"] < dataframe["stoch_d"])

        conditions.append(hit_upper_bb | (rsi_overbought & stoch_overbought))
        conditions.append(dataframe["volume"] > 0)

        if conditions:
            dataframe.loc[
                np.logical_and.reduce(conditions),
                "exit_long"
            ] = 1

        return dataframe
