# source: https://raw.githubusercontent.com/remiotore/freqtrade/44beaeb6a420cd8e9f2e4ea93e11d6cfa192ee03/strategies/Discord_FuturesStrat8.py
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401

# --- Do not remove these libs ---
import numpy as np  # noqa
import pandas as pd  # noqa
from freqtrade.strategy.strategy_helper import stoploss_from_absolute
from pandas import DataFrame
from datetime import datetime, timedelta, timezone
from ta.trend import stc
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
                                IStrategy, IntParameter)

# --------------------------------
# Add your lib to import here
import talib.abstract as ta
import pandas_ta as pta
import freqtrade.vendor.qtpylib.indicators as qtpylib
from technical.pivots_points import pivots_points



class Github_remiotore_freqtrade__Discord_FuturesStrat8__20260111_210550(IStrategy):
    custom_info = {}
    """
    This is a strategy template to get you started.
    More information in https://www.freqtrade.io/en/latest/strategy-customization/

    You can:
        :return: a Dataframe with all mandatory indicators for the strategies
    - Rename the class name (Do not forget to update class_name)
    - Add any methods you want to build your strategy
    - Add any lib you need to build your strategy

    You must keep:
    - the lib in the section "Do not remove these libs"
    - the methods: populate_indicators, populate_entry_trend, populate_exit_trend
    You should keep:
    - timeframe, minimal_roi, stoploss, trailing_*
    """
    # Strategy interface version - allow new iterations of the strategy interface.
    # Check the documentation or the Sample strategy to get the latest version.
    INTERFACE_VERSION = 3

    # Optimal timeframe for the strategy.
    timeframe = '5m'

    # Can this strategy go short?
    can_short = True

    # Minimal ROI designed for the strategy.
    # This attribute will be overridden if the config file contains "minimal_roi".
    minimal_roi = {
        "0": 0.166,
        "64": 0.104,
        "203": 0.042,
        "531": 0
    }

    # Optimal stoploss designed for the strategy.
    # This attribute will be overridden if the config file contains "stoploss".
    stoploss = -0.078

    # Trailing stoploss
    trailing_stop = False
    trailing_only_offset_is_reached = False

    # Run "populate_indicators()" only for new candle.
    process_only_new_candles = True

    # These values can be overridden in the config.
    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = False

    custom_info = {
        'risk_reward_ratio': 2.0,
        'set_to_break_even_at_profit': 0,
    }
    use_custom_stoploss = True

    # Number of candles the strategy requires before producing valid signals
    startup_candle_count = 200

    # Optional order type mapping.
    order_types = {
        'entry': 'market',
        'exit': 'market',
        'stoploss': 'market',
        'stoploss_on_exchange': False
    }

    # Optional order time in force.
    order_time_in_force = {
        'entry': 'gtc',
        'exit': 'gtc'
    }

    def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
                            proposed_stake: float, min_stake: float, max_stake: float,
                            entry_tag: str, **kwargs) -> float:
        return self.wallets.get_total_stake_amount() / 10

    def informative_pairs(self):
        return []

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe['atr'] = pta.atr(dataframe['high'], dataframe['low'], dataframe['close'])
        dataframe['stoploss_rate_long'] = dataframe['low'].rolling(5).min() - (dataframe['low'].rolling(window=5).min() * 0.001)
        dataframe['stoploss_rate_short'] = dataframe['high'].rolling(5).max() + (dataframe['high'].rolling(window=5).min() * 0.001)
        self.custom_info[metadata['pair']] = dataframe[
            ['date', 'stoploss_rate_long', 'stoploss_rate_short']].copy().set_index('date')

        dataframe['ema200'] = ta.EMA(dataframe, timeperiod=200)

        dataframe['STC'] = stc(dataframe['close'], window_slow=50, window_fast=26, cycle=12, smooth1=3, smooth2=3)
        dataframe['STC_BULL'] = np.where(dataframe['STC'] > dataframe['STC'].shift(1), 1, 0)
        dataframe['STC_BER'] = np.where(dataframe['STC'] < dataframe['STC'].shift(1), 1, 0)
        dataframe['adx'] = ta.ADX(dataframe)
        dataframe['adx_20'] = 20
        return dataframe

    def leverage(self, pair: str, current_time: 'datetime', current_rate: float,
                 proposed_leverage: float, max_leverage: float, side: str,
                 **kwargs) -> float:
        """
        Customize leverage for each new trade.

        :param pair: Pair that's currently analyzed
        :param current_time: datetime object, containing the current datetime
        :param current_rate: Rate, calculated based on pricing settings in exit_pricing.
        :param proposed_leverage: A leverage proposed by the bot.
        :param max_leverage: Max leverage allowed on this pair
        :param side: 'long' or 'short' - indicating the direction of the proposed trade
        :return: A leverage amount, which is between 1.0 and max_leverage.
        """
        return 10.0

    def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
                        current_rate: float, current_profit: float, **kwargs) -> float:

        """
            custom_stoploss using a risk/reward ratio
        """
        result = -1
        custom_info_pair = self.custom_info.get(pair)
        if custom_info_pair is not None:
            # using current_time/open_date directly via custom_info_pair[trade.open_daten]
            # would only work in backtesting/hyperopt.
            # in live/dry-run, we have to search for nearest row before it
            open_date_mask = custom_info_pair.index.unique().get_indexer([trade.open_date_utc], method='ffill')[0]
            open_df = custom_info_pair.iloc[open_date_mask]

            # trade might be open too long for us to find opening candle
            if (len(open_df) != 2):
                return -1  # won't update current stoploss

            if trade.is_short:
                if open_df['stoploss_rate_short'] == None:
                    return 0.0001
            else:
                if open_df['stoploss_rate_long'] == None:
                    return 0.0001


            initial_sl_abs = open_df['stoploss_rate_long']
            delta_price_for_stop_loss = trade.open_rate - initial_sl_abs
            fixed_take_profit_price = trade.open_rate + (
                    delta_price_for_stop_loss * self.custom_info['risk_reward_ratio'])

            if trade.is_short:
                initial_sl_abs = open_df['stoploss_rate_short']
                delta_price_for_stop_loss = initial_sl_abs - trade.open_rate
                fixed_take_profit_price = trade.open_rate - (
                            delta_price_for_stop_loss * self.custom_info['risk_reward_ratio'])

            fixed_stop_loss = stoploss_from_absolute(initial_sl_abs, current_rate, is_short=trade.is_short)

            result = fixed_stop_loss

            if trade.is_short:
                if current_rate < fixed_take_profit_price:
                    result = 0.0001
                    custom_info_pair.iloc[open_date_mask]['stoploss_rate_short'] = None
            else:
                if current_rate > fixed_take_profit_price:
                    result = 0.0001
                    custom_info_pair.iloc[open_date_mask]['stoploss_rate_long'] = None


            # if trade.is_short:
            #     print(f"short trade on pair {trade.pair} on {trade.open_date_utc} op: {trade.open_rate}, csl: {result}, slp: {initial_sl_abs}, tpp:{fixed_take_profit_price} cp: {current_rate}")
            # else:
            #     print(
            #         f"long trade on pair {trade.pair} on {trade.open_date_utc} op: {trade.open_rate}, csl: {result}, slp: {initial_sl_abs}, tpp:{fixed_take_profit_price} cp: {current_rate}")


        return result

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Based on TA indicators, populates the entry signal for the given dataframe
        :param dataframe: DataFrame
        :param metadata: Additional information, like the currently traded pair
        :return: DataFrame with entry columns populated
        """

        dataframe.loc[
            (
                # LONG
                    (dataframe['low'] > dataframe['ema200']) &
                    (dataframe['STC_BULL'] > 0) &
                    (dataframe['STC_BER'].shift(1) > 0) &
                    (dataframe['STC'].shift(1) < 1) &
                    (dataframe['adx'] > 20) &
                    (dataframe['volume'] > 0)  # Make sure Volume is not 0
            ),
            'enter_long'] = 1

        dataframe.loc[
            (
                # SHORT
                    (dataframe['high'] < dataframe['ema200']) &  # Check if candle is winning
                    (dataframe['STC_BER'] > 0) &
                    (dataframe['STC_BULL'].shift(1) > 0) &
                    (dataframe['STC'].shift(1) > 95) &
                    (dataframe['adx'] > 20) &
                    (dataframe['volume'] > 0)  # Make sure Volume is not 0
            ),
            'enter_short'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Based on TA indicators, populates the exit signal for the given dataframe
        :param dataframe: DataFrame
        :param metadata: Additional information, like the currently traded pair
        :return: DataFrame with exit columns populated
        """
        dataframe.loc[
            (
                # (dataframe["close"] > dataframe["open"]) & # Exit if price reverse
                (dataframe['volume'] == 0)  # Make sure Volume is not 0
            ),
            'exit_long'] = 0
        # Uncomment to use shorts (Only used in futures/margin mode. Check the documentation for more info)

        dataframe.loc[
            (
                # (dataframe["close"] < dataframe["open"]) & # Exit if price reverse
                (dataframe['volume'] > 0)  # Make sure Volume is not 0
            ),
            'exit_short'] = 0

        return dataframe
