from logging import FATAL
from freqtrade.strategy.interface import IStrategy
from typing import Dict, List
from functools import reduce
from pandas import DataFrame
import talib.abstract as ta
import numpy as np
import freqtrade.vendor.qtpylib.indicators as qtpylib
import datetime
from technical.util import resample_to_interval, resampled_merge
from datetime import datetime, timedelta
from freqtrade.persistence import Trade
from freqtrade.strategy import stoploss_from_open, merge_informative_pair, DecimalParameter, IntParameter, CategoricalParameter, BooleanParameter
import requests
import technical.indicators as ftt

# @Rallipanos
# @pluxury

class NASOSv4_FearAndGreed(IStrategy):
    INTERFACE_VERSION = 2

    # Fear and Greed Parameters
    use_fng_filter = BooleanParameter(default=True, space="protection", optimize=True, load=True)
    fng_min_threshold = IntParameter(10, 50, default=20, space="protection", optimize=True, load=True)
    fng_max_threshold = IntParameter(50, 80, default=60, space="protection", optimize=True, load=True)
    fng_change_threshold = IntParameter(-20, 20, default=0, space="protection", optimize=True, load=True)

    # ROI table:
    minimal_roi = {
        "0": 10
    }

    # Stoploss:
    stoploss = -0.15

    # Trailing stop
    trailing_stop = True
    trailing_stop_positive = 0.001
    trailing_stop_positive_offset = 0.016
    trailing_only_offset_is_reached = True

    # Optimal timeframe for the strategy
    timeframe = '5m'
    inf_1h = '1h'

    # Reduce overfitting
    process_only_new_candles = True
    startup_candle_count = 200

    # SMAOffset
    base_nb_candles_buy = IntParameter(2, 20, default=8, space='buy', optimize=True, load=True)
    base_nb_candles_sell = IntParameter(2, 25, default=16, space='sell', optimize=True, load=True)
    low_offset = DecimalParameter(0.9, 0.99, default=0.984, space='buy', optimize=True, load=True)
    low_offset_2 = DecimalParameter(0.9, 0.99, default=0.942, space='buy', optimize=True, load=True)
    high_offset = DecimalParameter(0.95, 1.1, default=1.084, space='sell', optimize=True, load=True)
    high_offset_2 = DecimalParameter(0.99, 1.5, default=1.401, space='sell', optimize=True, load=True)

    lookback_candles = IntParameter(1, 24, default=3, space='buy', optimize=True, load=True)
    profit_threshold = DecimalParameter(1.0, 1.03, default=1.008, space='buy', optimize=True, load=True)

    ewo_low = DecimalParameter(-20.0, -8.0, default=-14.378, space='buy', optimize=True, load=True)
    ewo_high = DecimalParameter(2.0, 12.0, default=2.403, space='buy', optimize=True, load=True)
    ewo_high_2 = DecimalParameter(-6.0, 12.0, default=-5.585, space='buy', optimize=True, load=True)

    rsi_buy = IntParameter(50, 100, default=72, space='buy', optimize=True, load=True)

    def get_fear_and_greed_index(self) -> (int, int):
        try:
            response = requests.get("https://api.alternative.me/fng/?limit=2")
            data = response.json()["data"]
            current_fng = int(data[0]["value"])
            previous_fng = int(data[1]["value"])
            change = current_fng - previous_fng
            return current_fng, change
        except Exception as e:
            self.logger.warning(f"Error fetching Fear and Greed Index: {e}")
            return 50, 0  # Valor neutral si hay un error

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Calculate all ma_buy values
        for val in self.base_nb_candles_buy.range:
            dataframe[f'ma_buy_{val}'] = ta.EMA(dataframe, timeperiod=val)

        # Calculate all ma_sell values
        for val in self.base_nb_candles_sell.range:
            dataframe[f'ma_sell_{val}'] = ta.EMA(dataframe, timeperiod=val)

        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        dataframe['ema_100'] = ta.EMA(dataframe, timeperiod=100)
        dataframe['sma_9'] = ta.SMA(dataframe, timeperiod=9)
        dataframe['hma_50'] = qtpylib.hull_moving_average(dataframe['close'], window=50)
        dataframe['EWO'] = (ta.EMA(dataframe, timeperiod=5) - ta.EMA(dataframe, timeperiod=35)) / dataframe['low'] * 100
        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        fng_index, fng_change = self.get_fear_and_greed_index()
        min_fng = self.fng_min_threshold.value
        max_fng = self.fng_max_threshold.value
        change_threshold = self.fng_change_threshold.value
        use_fng = self.use_fng_filter.value

        dataframe.loc[
            (
                (dataframe['rsi'] < self.rsi_buy.value) &
                (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) &
                ((not use_fng) or (min_fng <= fng_index <= max_fng and fng_change >= change_threshold))
            ),
            ['buy', 'buy_tag']] = (1, 'fng_buy')

        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        fng_index, fng_change = self.get_fear_and_greed_index()
        min_fng = self.fng_min_threshold.value
        max_fng = self.fng_max_threshold.value
        change_threshold = self.fng_change_threshold.value
        use_fng = self.use_fng_filter.value

        dataframe.loc[
            (
                (dataframe['rsi'] > 70) &
                (dataframe['close'] > (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) &
                ((not use_fng) or (fng_index > max_fng and fng_change <= -change_threshold))
            ),
            'sell'] = 1

        return dataframe