# CiccioStrategy - Strategia principale per CiccioTrading
# Basata su RSI, MACD, Bollinger Bands e EMA

from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter
from pandas import DataFrame
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib


class CiccioStrategy(IStrategy):
    """
    CiccioStrategy - Strategia multi-indicatore conservativa

    Logica:
    - Entry: RSI oversold + MACD bullish crossover + prezzo sotto BB lower
    - Exit: RSI overbought + MACD bearish + prezzo sopra BB upper

    Risk Management:
    - Stop loss: 5%
    - Take profit: 10%
    - Trailing stop: 3%
    """

    # Versione strategia
    INTERFACE_VERSION = 3

    # Timeframe
    timeframe = '1h'

    # Opzioni ROI (Return On Investment)
    minimal_roi = {
        "0": 0.10,      # 10% profit
        "30": 0.05,     # 5% dopo 30 min
        "60": 0.03,     # 3% dopo 1 ora
        "120": 0.01     # 1% dopo 2 ore
    }

    # Stop loss
    stoploss = -0.05  # 5%

    # Trailing stop
    trailing_stop = True
    trailing_stop_positive = 0.01
    trailing_stop_positive_offset = 0.03
    trailing_only_offset_is_reached = True

    # Ordini
    order_types = {
        'entry': 'limit',
        'exit': 'limit',
        'stoploss': 'market',
        'stoploss_on_exchange': False
    }

    # Protections
    @property
    def protections(self):
        return [
            {
                "method": "CooldownPeriod",
                "stop_duration_candles": 3
            },
            {
                "method": "MaxDrawdown",
                "trade_limit": 20,
                "lookback_period_candles": 48,
                "stop_duration_candles": 12,
                "max_allowed_drawdown": 0.2
            },
            {
                "method": "StoplossGuard",
                "lookback_period_candles": 24,
                "trade_limit": 4,
                "stop_duration_candles": 12,
                "only_per_pair": False
            }
        ]

    # Parametri ottimizzabili
    buy_rsi = IntParameter(20, 40, default=30, space='buy')
    sell_rsi = IntParameter(60, 80, default=70, space='sell')

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Calcola tutti gli indicatori tecnici
        """
        # RSI
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)

        # MACD
        macd = ta.MACD(dataframe)
        dataframe['macd'] = macd['macd']
        dataframe['macdsignal'] = macd['macdsignal']
        dataframe['macdhist'] = macd['macdhist']

        # Bollinger Bands
        bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
        dataframe['bb_lowerband'] = bollinger['lower']
        dataframe['bb_middleband'] = bollinger['mid']
        dataframe['bb_upperband'] = bollinger['upper']
        dataframe['bb_percent'] = (
            (dataframe['close'] - dataframe['bb_lowerband']) /
            (dataframe['bb_upperband'] - dataframe['bb_lowerband'])
        )
        dataframe['bb_width'] = (
            (dataframe['bb_upperband'] - dataframe['bb_lowerband']) / dataframe['bb_middleband']
        )

        # EMA
        dataframe['ema9'] = ta.EMA(dataframe, timeperiod=9)
        dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21)
        dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
        dataframe['ema200'] = ta.EMA(dataframe, timeperiod=200)

        # SMA
        dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20)

        # ATR (Average True Range) per volatilità
        dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)

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

        # ADX (Average Directional Index) per forza trend
        dataframe['adx'] = ta.ADX(dataframe, timeperiod=14)

        # Stochastic
        stoch = ta.STOCH(dataframe)
        dataframe['slowk'] = stoch['slowk']
        dataframe['slowd'] = stoch['slowd']

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Condizioni per entrare in un trade (BUY)

        Condizioni:
        1. RSI sotto soglia (oversold)
        2. MACD bullish crossover (macd > signal)
        3. Prezzo vicino/sotto BB lower
        4. EMA9 > EMA21 (trend rialzista breve termine)
        5. Volume sopra media
        """
        dataframe.loc[
            (
                # RSI oversold
                (dataframe['rsi'] < self.buy_rsi.value) &

                # MACD bullish
                (dataframe['macd'] > dataframe['macdsignal']) &

                # Prezzo sotto BB middle
                (dataframe['close'] < dataframe['bb_middleband']) &

                # Trend EMA positivo
                (dataframe['ema9'] > dataframe['ema21']) &

                # Volume confermato
                (dataframe['volume'] > dataframe['volume_mean'] * 0.5) &

                # Volume presente
                (dataframe['volume'] > 0)
            ),
            'enter_long'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Condizioni per uscire da un trade (SELL)

        Condizioni:
        1. RSI sopra soglia (overbought)
        2. MACD bearish (macd < signal)
        3. Prezzo sopra BB upper
        """
        dataframe.loc[
            (
                # RSI overbought
                (dataframe['rsi'] > self.sell_rsi.value) &

                # MACD bearish
                (dataframe['macd'] < dataframe['macdsignal']) &

                # Prezzo sopra BB middle
                (dataframe['close'] > dataframe['bb_middleband']) &

                # Volume presente
                (dataframe['volume'] > 0)
            ),
            'exit_long'] = 1

        return dataframe

    def leverage(self, pair: str, current_time, current_rate: float,
                 proposed_leverage: float, max_leverage: float, entry_tag: str,
                 side: str, **kwargs) -> float:
        """
        Leverage per futures (se abilitato)
        """
        return 1.0  # No leverage per ora (conservativo)
