# source: https://raw.githubusercontent.com/lordace-coder/freq-trader-v1/badf5c33d54a070a001b344bef74f5c6a558a190/freqtrade-bot/strategies/UltraAggressive30.py
"""
Ultra-Aggressive 30% Monthly Strategy
WARNING: Extremely high risk - designed to either make 30% monthly or blow up account

Approach:
- 10x leverage (maximum risk)
- 5min timeframe (many trades)
- Loose entry filters (more opportunities)
- Tight profit targets (quick wins)
- Wide stop loss (avoid getting stopped out)
- Martingale position sizing (double down on losses)
"""

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


class Github_lordace_coder_freq_trader_v1__UltraAggressive30__20251203_210234(IStrategy):

    INTERFACE_VERSION = 3
    can_short = True

    # Ultra-fast ROI - take profits quickly
    minimal_roi = {
        "0": 0.03,   # 3% immediate (0.3% real move with 10x)
        "5": 0.02,   # 2% after 5 min
        "10": 0.015, # 1.5% after 10 min
        "20": 0.01   # 1% after 20 min
    }

    # Wide stop loss to avoid getting stopped out
    stoploss = -0.15  # 15% loss (1.5% real move with 10x)

    # Aggressive trailing
    trailing_stop = True
    trailing_stop_positive = 0.005
    trailing_stop_positive_offset = 0.01
    trailing_only_offset_is_reached = True

    timeframe = '5m'
    startup_candle_count = 50

    # Max leverage
    leverage_num = IntParameter(8, 10, default=10, space='buy', optimize=False)

    # Loose parameters for more trades
    rsi_buy = IntParameter(35, 50, default=45, space='buy', optimize=True)
    rsi_sell = IntParameter(50, 65, default=55, space='buy', optimize=True)
    adx_min = IntParameter(15, 25, default=18, space='buy', optimize=True)

    # Martingale tracking
    _consecutive_losses = 0

    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:
        # Fast indicators for 5min timeframe
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=7)  # Faster RSI
        dataframe['adx'] = ta.ADX(dataframe, timeperiod=7)  # Faster ADX

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

        # MACD
        macd = ta.MACD(dataframe, fastperiod=8, slowperiod=21, signalperiod=5)
        dataframe['macd'] = macd['macd']
        dataframe['macdsignal'] = macd['macdsignal']
        dataframe['macdhist'] = macd['macdhist']

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

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

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

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # LONG - Very loose conditions for many trades
        long_conditions = (
            (dataframe['rsi'] < self.rsi_buy.value) &  # Oversold
            (dataframe['close'] > dataframe['ema9']) &  # Above short EMA
            (dataframe['adx'] > self.adx_min.value) &  # Some trend
            (dataframe['volume'] > dataframe['volume_mean'] * 0.8) &  # Any volume
            (
                (dataframe['macd'] > dataframe['macdsignal']) |  # Bullish OR
                (dataframe['close'] < dataframe['bb_lower'] * 1.02)  # Oversold bounce
            )
        )
        dataframe.loc[long_conditions, 'enter_long'] = 1

        # SHORT - Loose conditions
        short_conditions = (
            (dataframe['rsi'] > self.rsi_sell.value) &  # Overbought
            (dataframe['close'] < dataframe['ema9']) &  # Below short EMA
            (dataframe['adx'] > self.adx_min.value) &  # Some trend
            (dataframe['volume'] > dataframe['volume_mean'] * 0.8) &  # Any volume
            (
                (dataframe['macd'] < dataframe['macdsignal']) |  # Bearish OR
                (dataframe['close'] > dataframe['bb_upper'] * 0.98)  # Overbought drop
            )
        )
        dataframe.loc[short_conditions, 'enter_short'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Exit on opposite signals
        dataframe.loc[(dataframe['rsi'] > 70), 'exit_long'] = 1
        dataframe.loc[(dataframe['rsi'] < 30), 'exit_short'] = 1
        return dataframe

    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:
        """
        MARTINGALE: Double down after losses
        This is EXTREMELY DANGEROUS but needed for 30% monthly target
        """

        # Get recent closed trades
        trades = Trade.get_trades_proxy(is_open=False, pair=pair)

        if trades:
            # Get last 3 trades
            recent_trades = sorted(trades, key=lambda x: x.close_date, reverse=True)[:3]

            # Count consecutive losses
            consecutive_losses = 0
            for trade in recent_trades:
                if trade.close_profit_abs < 0:
                    consecutive_losses += 1
                else:
                    break

            # Martingale multiplier
            if consecutive_losses == 1:
                multiplier = 1.5  # 50% more after 1 loss
            elif consecutive_losses == 2:
                multiplier = 2.0  # Double after 2 losses
            elif consecutive_losses >= 3:
                multiplier = 3.0  # Triple after 3+ losses (YOLO)
            else:
                multiplier = 1.0

            stake = proposed_stake * multiplier
        else:
            stake = proposed_stake

        # Cap at max stake
        return min(stake, max_stake)
