# source: https://raw.githubusercontent.com/RoboticAutomations/freqtradestrategies/52c4bd40414645f079a980cf4486dc7af4061efb/AIRA%20-%20open%20code%20v2/strategies/rsi-momentum/E0V1E__2.py
# directory_url: https://github.com/RoboticAutomations/freqtradestrategies/blob/main/AIRA - open code v2/strategies/rsi-momentum/
# User: RoboticAutomations
# Repository: freqtradestrategies
# --------------------# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement, trailing-whitespace, unused-import, wrong-import-order, line-too-long, logging-fstring-interpolation
# flake8: noqa: F401
# isort: skip_file
# from freqtrade.strategy.interface import IStrategy ####
import pandas as pd
from pandas import DataFrame
import numpy as np
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
                                IStrategy, IntParameter, stoploss_from_absolute, informative)
from freqtrade.exchange import timeframe_to_prev_date
# from technical.util import resample_to_interval, resampled_merge

# --------------------------------
# Add your lib to import here
import logging
import talib.abstract as ta
import pandas_ta as pta
from datetime import datetime, timedelta
from typing import List, Optional
from technical.indicators import PMAX, SSLChannels, VIDYA
from freqtrade.optimize.space import Categorical, Dimension, Integer, SKDecimal
from freqtrade.persistence import Trade
import freqtrade.vendor.qtpylib.indicators as qtpylib


logger = logging.getLogger(__name__)

TMP_HOLD = []
TMP_HOLD1 = []


class Github_RoboticAutomations_freqtradestrategies__E0V1E__2__20260915_233254(IStrategy):
    INTERFACE_VERSION = 3
    STRATEGY_VERSION = 1
    
    startup_candle_count: int = 200
    
    minimal_roi = {
        "0": 1
    }
    
    timeframe = '5m'
    strategy_leverage = 5
    stoploss = -0.25 # disabled
    use_custom_stoploss = False
    max_open_trades = 10
    can_short = False
    
    # Trailing stop:
    trailing_stop = False
    
    # Optional order type mapping.
    order_types = {
        'entry': 'market',
        'exit': 'market',
        'emergency_exit': 'market',
        'force_entry': 'market',
        'force_exit': "market",
        'stoploss': 'market',
        'stoploss_on_exchange': True,
    }

    @property
    def protections(self):
        
        return [
        {
            "method": "CooldownPeriod",
            "stop_duration_candles": 18
        }
        ]

    is_optimize_32 = True
    buy_rsi_fast_32 = IntParameter(20, 70, default=40, space='buy', optimize=is_optimize_32)
    buy_rsi_32 = IntParameter(15, 50, default=42, space='buy', optimize=is_optimize_32)
    buy_sma15_32 = DecimalParameter(0.900, 1, default=0.973, decimals=3, space='buy', optimize=is_optimize_32)
    buy_cti_32 = DecimalParameter(-1, 1, default=0.69, decimals=2, space='buy', optimize=is_optimize_32)

    sell_fastx = IntParameter(50, 100, default=84, space='sell', optimize=True)
    # rsi_exit = IntParameter(low=49, high=80, default=70, space='sell', optimize=True)

    cci_opt = True
    sell_loss_cci = IntParameter(low=0, high=600, default=120, space='sell', optimize=cci_opt)
    sell_loss_cci_profit = DecimalParameter(-0.15, 0, default=-0.15, decimals=2, space='sell', optimize=cci_opt)
    

    def custom_exit(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
                    current_profit: float, **kwargs):
        dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe)
        current_candle = dataframe.iloc[-1].squeeze()
        previous_candle = dataframe.iloc[-2].squeeze()


        min_profit = trade.calc_profit_ratio(trade.min_rate)

        if current_candle['close'] > current_candle["ma120"] or current_candle['close'] > current_candle["ma240"]:
            if trade.id not in TMP_HOLD:
                TMP_HOLD.append(trade.id)
        else:
            if trade.id not in TMP_HOLD1:
                TMP_HOLD1.append(trade.id)

        if current_profit > 0:
            if current_candle["fastk"] > self.sell_fastx.value:
                return "fastk_profit_sell"

        if current_candle["cci"] > 80:
            if current_candle["high"] >= trade.open_rate:
                return "cci_high_sell"
            
        if min_profit <= -0.15:
            if current_profit > self.sell_loss_cci_profit.value:
                if current_candle["cci"] > self.sell_loss_cci.value:
                    return "cci_loss_sell"

        if trade.id in TMP_HOLD and current_candle["close"] < current_candle["ma120"] and current_candle["close"] < \
                current_candle["ma240"]:
            if current_time - timedelta(minutes=12) > trade.open_date_utc:
                TMP_HOLD.remove(trade.id)
                return "ma120_sell"

        if trade.id in TMP_HOLD1:
            if current_candle["high"] > current_candle["ma120"] or current_candle["high"] > current_candle["ma240"]:
                if -0.1<= min_profit <= -0.05:
                    TMP_HOLD1.remove(trade.id)
                    return "cross_120_or_240_sell"

        # if (current_candle['rsi'] >= self.rsi_exit.value) and (previous_candle['rsi'] >= current_candle['rsi']):
        #     return "rsi_reversal"

        return None
    
    
    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # buy_1 indicators
        dataframe['sma_15'] = ta.SMA(dataframe, timeperiod=15)
        dataframe['cti'] = pta.cti(dataframe["close"], length=20)
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=4)
        dataframe['rsi_slow'] = ta.RSI(dataframe, timeperiod=20)
        # profit sell indicators
        stoch_fast = ta.STOCHF(dataframe, 5, 3, 0, 3, 0)
        dataframe['fastk'] = stoch_fast['fastk']

        dataframe['cci'] = ta.CCI(dataframe, timeperiod=20)

        dataframe['ma120'] = ta.MA(dataframe, timeperiod=120)
        dataframe['ma240'] = ta.MA(dataframe, timeperiod=240)

        return dataframe
    
    
    def leverage(self, pair: str, current_time: datetime, current_rate: float,
                 proposed_leverage: float, max_leverage: float, entry_tag: Optional[str], side: str,
                 **kwargs) -> float:
        """
        Customize leverage for each new trade. This method is only called in futures mode.
    
        :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 entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal.
        :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 self.strategy_leverage


    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        
        buy_1 = (
                (dataframe['rsi_slow'] < dataframe['rsi_slow'].shift(1)) &
                (dataframe['rsi_fast'] < self.buy_rsi_fast_32.value) &
                (dataframe['rsi'] > self.buy_rsi_32.value) &
                (dataframe['close'] < dataframe['sma_15'] * self.buy_sma15_32.value) &
                (dataframe['cti'] < self.buy_cti_32.value) &
                (dataframe['volume'] > 0)
        )
        dataframe.loc[buy_1, ['enter_long', 'enter_tag']] = (1, 'buy_1')
        

        buy_new = (
                (dataframe['rsi_slow'] < dataframe['rsi_slow'].shift(1)) &
                (dataframe['rsi_fast'] < 34) &
                (dataframe['rsi'] > 28) &
                (dataframe['close'] < dataframe['sma_15'] * 0.96) &
                (dataframe['cti'] < self.buy_cti_32.value) &
                (dataframe['volume'] > 0)
        )
        dataframe.loc[buy_new, ['enter_long', 'enter_tag']] = (1, 'buy_new')
        
        return dataframe
    

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[:, ['exit_long', 'exit_tag']] = (0, 'long_out')
        return dataframe
    