# source: https://raw.githubusercontent.com/camster91/crypto-bots/5fd45118d5be1eaadd338e71ca26072dd5437831/strategies/ShortStrategy.py
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
import numpy as np
import pandas as pd
from pandas import DataFrame
from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib


class Github_camster91_crypto_bots__ShortStrategy__20260511_032334(IStrategy):
    """
    Short-Selling Mean Reversion Strategy.

    Mirrors MeanReversionStrategyV3 logic for SHORT entries.
    Enters SHORT when price is significantly ABOVE mean (overbought).
    Designed for bearish/downtrend market conditions.

    REQUIRES: Futures/margin trading (set trading_mode: "futures" in config)
    NOT for spot trading.

    Entry (short): Z-score > +1.5 AND RSI > 75 AND volume spike
    Exit (cover):  Z-score < +0.3 AND RSI < 45

    Parameters match V3 long strategy defaults (mirrored):
    - sell_zscore (short entry): +1.8
    - buy_zscore (short exit): +0.3
    - RSI thresholds: enter > 76, exit < 45

    CAUTION: Short selling carries higher risk than long-only.
    Always paper trade extensively before going live.
    """

    INTERFACE_VERSION = 3
    can_short = True

    # Short entry params (overbought thresholds)
    short_zscore_entry = DecimalParameter(1.0, 3.0, default=1.8, space="sell", decimals=1)
    short_zscore_exit = DecimalParameter(-1.0, 1.0, default=0.3, space="buy", decimals=1)
    short_rsi_entry = IntParameter(65, 85, default=76, space="sell")
    short_rsi_exit = IntParameter(30, 55, default=45, space="buy")
    short_ma_period = IntParameter(20, 150, default=92, space="sell")
    short_volume_spike = DecimalParameter(1.5, 4.0, default=2.5, space="sell", decimals=1)

    minimal_roi = {"141": 0, "71": 0.013, "37": 0.045, "0": 0.11}

    stoploss = -0.15  # Wider stop for shorts (gap risk)
    trailing_stop = False
    timeframe = "5m"
    process_only_new_candles = True
    startup_candle_count: int = 150

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["ma"] = ta.SMA(dataframe, timeperiod=self.short_ma_period.value)
        dataframe["std"] = dataframe["close"].rolling(window=self.short_ma_period.value).std()
        dataframe["zscore"] = (dataframe["close"] - dataframe["ma"]) / dataframe["std"]
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
        dataframe["volume_mean"] = dataframe["volume"].rolling(window=20).mean()
        dataframe["atr"] = ta.ATR(dataframe, timeperiod=14)

        # Additional overbought confirmation
        bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
        dataframe["bb_upper"] = bollinger["upper"]
        dataframe["bb_lower"] = bollinger["lower"]
        dataframe["bb_mid"] = bollinger["mid"]

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Long entries disabled (short-only strategy)
        dataframe.loc[:, "enter_long"] = 0

        # Short entry: price significantly above mean
        dataframe.loc[
            (
                (dataframe["zscore"] > self.short_zscore_entry.value) &
                (dataframe["rsi"] > self.short_rsi_entry.value) &
                (dataframe["volume"] > self.short_volume_spike.value * dataframe["volume_mean"]) &
                (dataframe["std"] > 0) &
                (dataframe["volume"] > 0)
            ),
            "enter_short",
        ] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[:, "exit_long"] = 0

        # Exit short: price reverted back to mean
        dataframe.loc[
            (
                (dataframe["zscore"] < self.short_zscore_exit.value) &
                (dataframe["rsi"] < self.short_rsi_exit.value) &
                (dataframe["volume"] > 0)
            ),
            "exit_short",
        ] = 1
        return dataframe
