# source: https://raw.githubusercontent.com/RoboticAutomations/freqtradestrategies/52c4bd40414645f079a980cf4486dc7af4061efb/AIRA%20-%20open%20code%20v2/strategies/rsi-momentum/ImprovedClaudioStrategy036.py
# directory_url: https://github.com/RoboticAutomations/freqtradestrategies/blob/main/AIRA - open code v2/strategies/rsi-momentum/
# User: RoboticAutomations
# Repository: freqtradestrategies
# --------------------from freqtrade.strategy import IStrategy
from pandas import DataFrame
import talib.abstract as ta
import pandas as pd
import numpy as np
from typing import Dict, List, Optional
from datetime import datetime, timezone
from freqtrade.persistence import Trade

class Github_RoboticAutomations_freqtradestrategies__ImprovedClaudioStrategy036__20260915_233254(IStrategy):
    INTERFACE_VERSION = 3
    
    # Strategy settings
    minimal_roi = {
        "0": 0.05  # 5% profit
    }
    
    stoploss = -0.20  # 20% stop loss
    
    # Trailing stoploss
    trailing_stop = True
    trailing_stop_positive = 0.0005 
    trailing_stop_positive_offset = 0.015 # 1.5%
    trailing_only_offset_is_reached = True
    
    # Timeframe settings
    timeframe = '1h'
    
    # Buy hyperparameters
    buy_params = {
        "bb_length": 20,
        "bb_mult": 2.0,
        "kc_length": 20,
        "kc_mult": 1.5,
    }

    # DCA Parameters - DCA Simples com valores fixos
    max_dca_orders = 6  # 5 ordens DCA
    
    # Multiplicadores fixos para garantir valores mínimos executáveis
    dca_multipliers = {
        1: 0.35,    # €5 (primeira DCA)
        2: 0.67,    # €10 (segunda DCA) 
        3: 1.00,    # €15 (terceira DCA - igual ao inicial)
        4: 1.33,    # €20 (quarta DCA)
        5: 1.67,     # €25 (quinta DCA)
	6: 1.67     # 25 euros para o ultimo DCA 
    }

    # Thresholds para DCA Simples - mais espaçados
    dca_thresholds = {
        1: -0.05,   # -5% para 1ª DCA (€5)
        2: -0.10,   # -10% para 2ª DCA (€10)
        3: -0.18,   # -18% para 3ª DCA (€15)
        4: -0.28,   # -28% para 4ª DCA (€20)
        5: -0.40,   # -40% para 5ª DCA (€25)
	6: -0.50    # -60% para o 6 e ultimo DCA
    }


    def adjust_trade_position(self, trade: Trade, current_time: datetime,
                            current_rate: float, current_profit: float,
                            min_stake: float, max_stake: float,
                            current_entry_profit: float, current_exit_profit: float,
                            **kwargs) -> Optional[float]:
        
        # Verifica se já atingiu o número máximo de ordens DCA
        current_order_number = trade.nr_of_successful_entries
        if current_order_number >= self.max_dca_orders:
            return None

        # Verifica se atingiu o threshold para DCA
        threshold = self.dca_thresholds.get(current_order_number, -1.0)
        if current_profit <= threshold:
            # Calcula o novo valor de entrada
            multiplier = self.dca_multipliers.get(current_order_number, 1.0)
            new_stake = trade.stake_amount * multiplier

            # Verifica se está dentro dos limites
            if new_stake <= max_stake :
                return new_stake

        return None

    # [Resto do código permanece igual...]
    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # BB Calculation
        bb_length = self.buy_params['bb_length']
        bb_mult = self.buy_params['bb_mult']
        
        dataframe['bb_basis'] = ta.SMA(dataframe['close'], timeperiod=bb_length)
        dataframe['bb_dev'] = bb_mult * ta.STDDEV(dataframe['close'], timeperiod=bb_length)
        dataframe['bb_upper'] = dataframe['bb_basis'] + dataframe['bb_dev']
        dataframe['bb_lower'] = dataframe['bb_basis'] - dataframe['bb_dev']
        
        # KC Calculation
        kc_length = self.buy_params['kc_length']
        kc_mult = self.buy_params['kc_mult']
        
        dataframe['kc_ma'] = ta.SMA(dataframe['close'], timeperiod=kc_length)
        dataframe['tr'] = ta.TRANGE(dataframe['high'], dataframe['low'], dataframe['close'])
        dataframe['kc_range'] = ta.SMA(dataframe['tr'], timeperiod=kc_length)
        dataframe['kc_upper'] = dataframe['kc_ma'] + dataframe['kc_range'] * kc_mult
        dataframe['kc_lower'] = dataframe['kc_ma'] - dataframe['kc_range'] * kc_mult
        
        # Squeeze Conditions
        dataframe['sqz_on'] = (dataframe['bb_lower'] > dataframe['kc_lower']) & \
                             (dataframe['bb_upper'] < dataframe['kc_upper'])
        dataframe['sqz_off'] = (dataframe['bb_lower'] < dataframe['kc_lower']) & \
                              (dataframe['bb_upper'] > dataframe['kc_upper'])
        dataframe['no_sqz'] = ~(dataframe['sqz_on'] | dataframe['sqz_off'])
        
        # Momentum Value calculation
        highest_high = dataframe['high'].rolling(window=kc_length).max()
        lowest_low = dataframe['low'].rolling(window=kc_length).min()
        avg_hl = (highest_high + lowest_low) / 2
        avg_close = ta.SMA(dataframe['close'], timeperiod=kc_length)
        final_avg = (avg_hl + avg_close) / 2
        
        # Linear regression calculation
        source = dataframe['close'] - final_avg
        dataframe['momentum'] = ta.LINEARREG(source, timeperiod=kc_length)
        
        # Previous momentum for comparison
        dataframe['momentum_prev'] = dataframe['momentum'].shift(1)
        
        return dataframe
    
    def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe['momentum'] > 0) &  # Positive momentum
                (dataframe['momentum'] > dataframe['momentum_prev']) &  # Increasing momentum
                (dataframe['sqz_off'])  # Squeeze is off (expansion)
            ),
            'buy'] = 1
        return dataframe
    
    def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe['momentum'] < 0) &  # Negative momentum
                (dataframe['momentum'] < dataframe['momentum_prev'])  # Decreasing momentum
            ),
            'sell'] = 1
        return dataframe
    
    def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float,
                          rate: float, time_in_force: str, sell_reason: str,
                          current_time: datetime, **kwargs) -> bool:
        """
        Override to prevent selling when in negative profit
        """
        current_profit = trade.calc_profit_ratio(rate)
        
        # Don't sell if we're in a loss
        if current_profit < 0:
            return False
            
        return True
