# source: https://raw.githubusercontent.com/lordace-coder/freq-trader-v1/badf5c33d54a070a001b344bef74f5c6a558a190/freqtrade-bot/strategies/TemaAdxCmo_NoStopLoss.py
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
# isort: skip_file
# --- Do not remove these imports ---
import numpy as np
import pandas as pd
from datetime import datetime, timedelta, timezone
from pandas import DataFrame
from typing import Dict, Optional, Union, Tuple, List
from freqtrade.optimize.space import Categorical, Dimension, Integer, SKDecimal
import logging

logger = logging.getLogger(__name__)

from freqtrade.strategy import (
    IStrategy,
    Trade,
    Order,
    PairLocks,
    informative,  # @informative decorator
    # Hyperopt Parameters
    BooleanParameter,
    CategoricalParameter,
    DecimalParameter,
    IntParameter,
    RealParameter,
    # timeframe helpers
    timeframe_to_minutes,
    timeframe_to_next_date,
    timeframe_to_prev_date,
    # Strategy helper functions
    merge_informative_pair,
    stoploss_from_absolute,
    stoploss_from_open,
)


# --------------------------------
# Add your lib to import here
import talib.abstract as ta
import pandas_ta as pta
from technical import qtpylib


# ==========================================
# AGGRESSIVE Monthly Trading Strategy
# Based on TemaAdxCmo but optimized for:
# - Higher frequency trading
# - Monthly profit targets
# - Faster entries and exits
# - More pairs
# ==========================================


class Github_lordace_coder_freq_trader_v1__TemaAdxCmo_NoStopLoss__20251203_210234(IStrategy):

    # Strategy interface version
    INTERFACE_VERSION = 3

    # AGGRESSIVE: Use 15m timeframe for more trading opportunities
    timeframe = "15m"

    # Only long trades (shorts were unprofitable)
    can_short: bool = False

    # AGGRESSIVE ROI - Take profits much faster!
    minimal_roi = {
        "0": 0.08,  # 8% immediate profit target
        "15": 0.05,  # 5% after 15 min
        "30": 0.03,  # 3% after 30 min
        "60": 0.015,  # 1.5% after 1 hour
        "120": 0.01,  # 1% after 2 hours
    }

    # NO STOP LOSS - Testing best case scenario
    stoploss = -0.99  # Essentially no stop loss (99% would never hit)

    # AGGRESSIVE trailing stop
    trailing_stop = True
    trailing_only_offset_is_reached = True
    trailing_stop_positive = 0.01  # Start trailing at 1% profit
    trailing_stop_positive_offset = 0.015  # Trail by 1.5%

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

    # NO exit signals - they killed profits
    use_exit_signal = False
    exit_profit_only = False
    ignore_roi_if_entry_signal = False

    # Lower startup candles for faster backtesting
    startup_candle_count: int = 100

    # ============================================
    # AGGRESSIVE PARAMETERS - Less restrictive for more trades
    # ============================================

    # TEMA Parameters - More sensitive
    tema_rolling_window = CategoricalParameter([2, 3, 4], default=3, space="buy")

    # ADX Parameters - Lower threshold for more entries
    adx_threshold = IntParameter(15, 30, default=20, space="buy")

    # ATR Risk Management
    atr_mult = DecimalParameter(1.0, 2.5, default=1.5, decimals=1, space="buy")
    risk_ratio = DecimalParameter(2.0, 4.0, default=3.0, decimals=1, space="buy")

    # Volume Filter - Lower requirement
    volume_factor = DecimalParameter(1.0, 1.8, default=1.2, decimals=1, space="buy")

    # RSI Filter - Wider range
    use_rsi_filter = BooleanParameter(default=True, space="buy")
    rsi_long_threshold = IntParameter(30, 55, default=45, space="buy")

    # Trend Filter - Less strict
    use_ema_filter = BooleanParameter(default=True, space="buy")
    ema_period = IntParameter(20, 100, default=50, space="buy")

    # CMO Threshold - Lower for more trades
    cmo_threshold = IntParameter(0, 20, default=10, space="buy")

    leverage_level = IntParameter(
        1, 5, default=2, space="buy", optimize=True, load=True
    )

    @property
    def plot_config(self):
        plot_config = {
            "main_plot": {
                "tema8": {"color": "red"},
                "tema13": {"color": "blue"},
                "tema21": {"color": "green"},
                f"ema_{self.ema_period.value}": {"color": "orange"},
            },
            "subplots": {
                "ADX": {"adx": {"color": "#f50057", "type": "line"}},
                "CMO": {"cmo": {"color": "#2962ff", "type": "line"}},
                "RSI": {"rsi": {"color": "#9c27b0", "type": "line"}},
            },
        }
        return plot_config

    def informative_pairs(self):
        return []

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Optimized indicators for 15m timeframe
        """

        # TEMA indicators
        dataframe["tema8"] = ta.TEMA(dataframe, timeperiod=8)
        dataframe["tema13"] = ta.TEMA(dataframe, timeperiod=13)
        dataframe["tema21"] = ta.TEMA(dataframe, timeperiod=21)

        # EMA trend filter
        for ema_val in self.ema_period.range:
            dataframe[f"ema_{ema_val}"] = ta.EMA(dataframe, timeperiod=ema_val)

        # Momentum indicators
        dataframe["adx"] = ta.ADX(dataframe, timeperiod=14)
        dataframe["cmo"] = ta.CMO(dataframe, timeperiod=14)
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)

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

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

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        AGGRESSIVE entry logic - more opportunities
        """

        ema_col = f"ema_{self.ema_period.value}"

        # LONG ENTRY - Less restrictive conditions
        long_conditions = [
            # TEMA alignment
            (dataframe["tema8"] > dataframe["tema13"]),
            (dataframe["tema13"] > dataframe["tema21"]),
            # TEMA crossover in smaller window
            (
                dataframe["tema8"]
                .rolling(window=self.tema_rolling_window.value)
                .apply(
                    lambda x: any(
                        qtpylib.crossed_above(
                            x, dataframe["tema21"].iloc[x.index[0] : x.index[-1] + 1]
                        )
                    )
                )
            ),
            # Lower ADX threshold
            (dataframe["adx"] > self.adx_threshold.value),
            # CMO positive (lower threshold)
            (dataframe["cmo"] > self.cmo_threshold.value),
            # Volume check (lower requirement)
            (dataframe["volume"] > dataframe["volume_mean"] * self.volume_factor.value),
        ]

        # Optional RSI filter
        if self.use_rsi_filter.value:
            long_conditions.append(dataframe["rsi"] > self.rsi_long_threshold.value)

        # Optional EMA trend filter
        if self.use_ema_filter.value:
            long_conditions.append(dataframe["close"] > dataframe[ema_col])

        # Combine all conditions
        from functools import reduce

        dataframe.loc[reduce(lambda x, y: x & y, long_conditions), "enter_long"] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        No exit signals - rely on ROI and trailing stop
        """
        dataframe.loc[:, "exit_long"] = 0
        return dataframe

    def custom_exit(
        self,
        pair: str,
        trade: Trade,
        current_time: datetime,
        current_rate: float,
        current_profit: float,
        **kwargs,
    ):
        """
        Custom exit with dynamic TP/SL
        """

        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)

        if dataframe.empty or len(dataframe) < 1:
            return None

        current_candle = dataframe.iloc[-1]

        # Quick exit if ADX drops significantly (trend weakening)
        if current_candle["adx"] < 15:
            return "weak_trend"

        # Quick exit if TEMA(8) crosses below TEMA(13) - fast reversal detection
        if qtpylib.crossed_below(dataframe["tema8"], dataframe["tema13"]).iloc[-1]:
            return "tema_reversal"

        return None

    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:
        """
        AGGRESSIVE position sizing - use more capital
        """
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)

        if dataframe.empty:
            return proposed_stake

        current_adx = dataframe.iloc[-1]["adx"]

        # More aggressive sizing based on ADX
        if current_adx > 40:  # Very strong trend
            stake_multiplier = 1.2
        elif current_adx > 30:  # Strong trend
            stake_multiplier = 1.0
        elif current_adx > 20:  # Moderate trend
            stake_multiplier = 0.85
        else:  # Weak trend
            stake_multiplier = 0.7

        adjusted_stake = proposed_stake * stake_multiplier

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

        adjusted_stake = min(adjusted_stake, max_stake)

        return adjusted_stake

    def leverage(
        self,
        pair: str,
        current_time: datetime,
        current_rate: float,
        proposed_leverage: float,
        max_leverage: float,
        side: str,
        **kwargs,
    ) -> float:
        """
        Use leverage for aggressive returns
        """
        return self.leverage_level.value


# Import functools for reduce
from functools import reduce
