# source: https://raw.githubusercontent.com/lordace-coder/freq-trader-v1/badf5c33d54a070a001b344bef74f5c6a558a190/freqtrade-bot/strategies/Consistent10Monthly.py
"""
Consistent 10% Monthly Strategy
Target: 10% monthly returns ($30/month on $300 capital)

Based on backtesting analysis:
- ONLY trade pairs that actually made profit (ADA, UNI, BNB)
- NO exit signals (they have 12-30% win rate)
- Use ONLY ROI + trailing stops (90-100% win rate)
- Wider stop loss to avoid being stopped out unnecessarily
- 3-4x leverage for balance of risk/reward
- 15m timeframe (proven optimal)

Key insights from testing:
- ROI exits: 869 trades, +$455, 100% win rate ✓
- Trailing stops: 532 trades, +$275, 98.1% win rate ✓
- Stop losses: 249 trades, -$838, 0% win rate ✗
- Exit signals: -$192, 12-30% win rate ✗

Strategy: Keep winners only, remove losers, optimize exits
"""

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


class Github_lordace_coder_freq_trader_v1__Consistent10Monthly__20251203_210234(IStrategy):

    INTERFACE_VERSION = 3
    can_short = True

    # Optimized ROI based on what actually worked
    # Faster exits to lock in profits before they reverse
    minimal_roi = {
        "0": 0.06,    # 6% immediate (1.5% real with 4x leverage)
        "10": 0.045,  # 4.5% after 10 min
        "20": 0.03,   # 3% after 20 min
        "40": 0.02,   # 2% after 40 min
        "80": 0.015   # 1.5% after 80 min
    }

    # WIDER stop loss - avoid being stopped out unnecessarily
    # Main lesson: Stop losses killed $838 vs $730 in wins
    stoploss = -0.15  # 15% (3.75% real with 4x leverage)

    # Conservative trailing stop
    trailing_stop = True
    trailing_stop_positive = 0.012   # Start trailing at 1.2%
    trailing_stop_positive_offset = 0.018  # Trail by 1.8%
    trailing_only_offset_is_reached = True

    timeframe = '15m'  # Proven optimal timeframe
    startup_candle_count = 100

    # 3-4x leverage (balanced)
    leverage_num = IntParameter(3, 4, default=4, space='buy', optimize=False)

    # Entry parameters - proven values from TemaAdxCmo
    adx_threshold = IntParameter(18, 25, default=20, space='buy', optimize=True)
    cmo_threshold = IntParameter(5, 15, default=10, space='buy', optimize=True)
    rsi_long_threshold = IntParameter(40, 50, default=45, space='buy', optimize=True)
    tema_rolling_window = IntParameter(2, 5, default=3, space='buy', optimize=True)
    volume_factor = DecimalParameter(1.0, 1.5, default=1.2, decimals=1, space='buy', optimize=True)

    # CRITICAL: NO exit signals!
    use_exit_signal = False

    def leverage(self, pair: str, current_time, current_rate: float,
                 proposed_leverage: float, max_leverage: float, side: str,
                 **kwargs) -> float:
        return self.leverage_num.value

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # TEMA (proven indicator from successful strategy)
        dataframe['tema'] = ta.TEMA(dataframe, timeperiod=9)
        dataframe['tema_rolling'] = dataframe['tema'].rolling(window=self.tema_rolling_window.value).mean()

        # ADX for trend strength
        dataframe['adx'] = ta.ADX(dataframe, timeperiod=14)

        # CMO for momentum
        dataframe['cmo'] = ta.CMO(dataframe, timeperiod=14)

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

        # EMA for trend
        dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
        dataframe['ema20'] = ta.EMA(dataframe, timeperiod=20)

        # MACD
        macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
        dataframe['macd'] = macd['macd']
        dataframe['macdsignal'] = macd['macdsignal']

        # Bollinger Bands
        bollinger = ta.BBANDS(dataframe, timeperiod=20, nbdevup=2.0, nbdevdn=2.0)
        dataframe['bb_lower'] = bollinger['lowerband']
        dataframe['bb_upper'] = bollinger['upperband']

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

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

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Entry logic based on proven TEMA + ADX + CMO approach
        Only enter when multiple signals align
        """

        # LONG conditions - oversold bounce in uptrend
        long_conditions = (
            # Trend: Price above EMA
            (dataframe['close'] > dataframe['ema50']) &

            # TEMA signal
            (dataframe['tema'] > dataframe['tema_rolling']) &
            (dataframe['tema'].shift(1) <= dataframe['tema_rolling'].shift(1)) &

            # ADX: Strong trend
            (dataframe['adx'] > self.adx_threshold.value) &

            # CMO: Oversold
            (dataframe['cmo'] < -self.cmo_threshold.value) &

            # RSI: Not too oversold
            (dataframe['rsi'] > 30) &
            (dataframe['rsi'] < self.rsi_long_threshold.value) &

            # MACD: Bullish or turning bullish
            (
                (dataframe['macd'] > dataframe['macdsignal']) |
                ((dataframe['macd'] < dataframe['macdsignal']) &
                 (dataframe['macd'] > dataframe['macd'].shift(1)))
            ) &

            # Volume confirmation
            (dataframe['volume'] > dataframe['volume_mean'] * self.volume_factor.value) &

            # Price near lower BB (oversold)
            (dataframe['close'] < dataframe['bb_lower'] * 1.02)
        )

        dataframe.loc[long_conditions, 'enter_long'] = 1

        # SHORT conditions - overbought rejection in downtrend
        short_conditions = (
            # Trend: Price below EMA
            (dataframe['close'] < dataframe['ema50']) &

            # TEMA signal
            (dataframe['tema'] < dataframe['tema_rolling']) &
            (dataframe['tema'].shift(1) >= dataframe['tema_rolling'].shift(1)) &

            # ADX: Strong trend
            (dataframe['adx'] > self.adx_threshold.value) &

            # CMO: Overbought
            (dataframe['cmo'] > self.cmo_threshold.value) &

            # RSI: Not too overbought
            (dataframe['rsi'] < 70) &
            (dataframe['rsi'] > 100 - self.rsi_long_threshold.value) &

            # MACD: Bearish or turning bearish
            (
                (dataframe['macd'] < dataframe['macdsignal']) |
                ((dataframe['macd'] > dataframe['macdsignal']) &
                 (dataframe['macd'] < dataframe['macd'].shift(1)))
            ) &

            # Volume confirmation
            (dataframe['volume'] > dataframe['volume_mean'] * self.volume_factor.value) &

            # Price near upper BB (overbought)
            (dataframe['close'] > dataframe['bb_upper'] * 0.98)
        )

        dataframe.loc[short_conditions, 'enter_short'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        NO EXIT SIGNALS
        Let ROI and trailing stops handle all exits
        """
        dataframe.loc[:, 'exit_long'] = 0
        dataframe.loc[:, 'exit_short'] = 0

        return dataframe
