# source: https://raw.githubusercontent.com/hibana2077/fqtrade/06e5a08b8bb0f656e53d84566b7c358c450d4c8b/user_data/strategies/Mid.py
from datetime import datetime, timedelta
import talib.abstract as ta
import pandas_ta as pta
from freqtrade.persistence import Trade
from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame
from freqtrade.strategy import DecimalParameter, IntParameter
from functools import reduce
import warnings

warnings.simplefilter(action="ignore", category=RuntimeWarning)


class Github_hibana2077_fqtrade__Mid__20240321_000615(IStrategy):
    minimal_roi = {
        "0": 1
    }
    timeframe = '15m'
    process_only_new_candles = True
    startup_candle_count = 120
    order_types = {
        'entry': 'market',
        'exit': 'market',
        'emergency_exit': 'market',
        'force_entry': 'market',
        'force_exit': "market",
        'stoploss': 'market',
        'stoploss_on_exchange': True,
        'stoploss_on_exchange_interval': 60,
        'stoploss_on_exchange_market_ratio': 0.99
    }
    stoploss = -0.25

    is_optimize_32 = True
    buy_bb_period = IntParameter(5, 60, default=15, space='buy', optimize=True)
    buy_supertrend_period = IntParameter(5, 60, default=15, space='buy', optimize=True)
    buy_supertrend_multiplier = DecimalParameter(0.5, 3, default=1, decimals=1, space='buy', optimize=True)
    buy_bb_width_value = DecimalParameter(0.02, 0.2, default=0.02, decimals=2, space='buy', optimize=True)
    buy_add_lost_pct = DecimalParameter(0.01, 0.1, default=0.05, decimals=2, space='buy', optimize=True)

    tpsl_atr_period = IntParameter(5, 60, default=15, space='buy', optimize=True)
    atr_sl_rate = DecimalParameter(0.3, 3, default=0.3, decimals=1, space='buy', optimize=True)
    tpsl_rate = DecimalParameter(0.3, 2.6, default=0.3, decimals=2, space='buy', optimize=True)

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # buy indicators
        bb_bands = pta.bbands(dataframe['close'], length=self.buy_bb_period.value)
        dataframe['bb_lowerband'] = bb_bands.iloc[:, 0]
        dataframe['bb_upperband'] = bb_bands.iloc[:, 2]
        dataframe['bb_middleband'] = bb_bands.iloc[:, 1]
        dataframe['bb_width'] = bb_bands.iloc[:, 3]

        superT = pta.supertrend(high=dataframe['high'], low=dataframe['low'], close=dataframe['close'], length=self.buy_supertrend_period.value, multiplier=self.buy_supertrend_multiplier.value)
        dataframe['supertrend'] = superT.iloc[:, 1]

        atr = pta.atr(dataframe['high'], dataframe['low'], dataframe['close'], length=self.tpsl_atr_period.value)
        dataframe['atr'] = atr

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        conditions = []
        dataframe.loc[:, 'enter_tag'] = ''
        buy_1 = (
            (dataframe['close'] < dataframe['bb_middleband']) &
            (dataframe['supertrend'] == 1) &
            (dataframe['bb_width'] > self.buy_bb_width_value.value)
        )
        conditions.append(buy_1)
        dataframe.loc[buy_1, 'enter_tag'] += 'buy_1'
        if conditions:
            dataframe.loc[
                reduce(lambda x, y: x | y, conditions),
                'enter_long'] = 1
        return dataframe

    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()
                        
        # if current_time - timedelta(minutes=10) < trade.open_date_utc:
        #     if current_profit >= 0.05:
        #         return "profit_sell_fast"

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

        #     if current_candle["cci"] > self.sell_cci.value:
        #         return "cci_profit_sell"

        # if current_time - timedelta(hours=2) > trade.open_date_utc:
        #     if current_profit > 0:
        #         return "profit_sell_in_2h"
                
        # if current_candle["high"] >= trade.open_rate:
        #     if current_candle["cci"] > self.sell_cci.value:
        #         return "cci_sell"

        # if current_profit > self.sell_loss_cci_profit.value:
        #     if current_candle["cci"] > self.sell_loss_cci.value:
        #         return "cci_loss_sell"
        # if current_profit > 0.05:
            # #print(dir(trade))
            # ['_LocalTrade__set_stop_loss', '__annotations__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slotnames__', '__str__', '__subclasshook__', '__weakref__', '_calc_base_close', '_calc_open_trade_value', '_date_last_filled_utc', 'add_bt_trade', 'adjust_min_max_rates', 'adjust_stop_loss', 'amount', 'amount_precision', 'amount_requested', 'base_currency', 'borrowed', 'bt_open_open_trade_count', 'bt_trades_open_pp', 'buy_tag', 'calc_close_trade_value', 'calc_profit', 'calc_profit_ratio', 'calculate_interest', 'calculate_profit', 'close', 'close_bt_trade', 'close_date', 'close_date_utc', 'close_profit', 'close_profit_abs', 'close_rate', 'close_rate_requested', 'contract_size', 'date_last_filled_utc', 'enter_tag', 'entry_side', 'exchange', 'exit_order_status', 'exit_reason', 'exit_side', 'fee_close', 'fee_close_cost', 'fee_close_currency', 'fee_open', 'fee_open_cost', 'fee_open_currency', 'fee_updated', 'from_json', 'funding_fee_running', 'funding_fees', 'get_canceled_exit_order_count', 'get_open_trade_count', 'get_open_trades', 'get_trades_proxy', 'has_no_leverage', 'has_open_orders', 'id', 'initial_stop_loss', 'initial_stop_loss_pct', 'interest_rate', 'is_open', 'is_short', 'is_stop_loss_trailing', 'leverage', 'liquidation_price', 'max_rate', 'max_stake_amount', 'min_rate', 'nr_of_successful_buys', 'nr_of_successful_entries', 'nr_of_successful_exits', 'nr_of_successful_sells', 'open_date', 'open_date_utc', 'open_orders', 'open_orders_ids', 'open_rate', 'open_rate_requested', 'open_trade_value', 'orders', 'pair', 'precision_mode', 'price_precision', 'realized_profit', 'recalc_open_trade_value', 'recalc_trade_from_orders', 'remove_bt_trade', 'reset_trades', 'safe_base_currency', 'safe_close_rate', 'safe_quote_currency', 'select_filled_or_open_orders', 'select_filled_orders', 'select_order', 'select_order_by_order_id', 'sell_reason', 'set_funding_fees', 'set_liquidation_price', 'stake_amount', 'stake_currency', 'stop_loss', 'stop_loss_pct', 'stoploss_last_update', 'stoploss_last_update_utc', 'stoploss_or_liquidation', 'stoploss_order_id', 'stoploss_reinitialization', 'strategy', 'timeframe', 'to_json', 'total_profit', 'trade_direction', 'trades', 'trades_open', 'trading_mode', 'update_fee', 'update_order', 'update_trade', 'use_db']
            # return "profit_sell
            # "
        if current_profit < 0:
            time_diff = current_time - trade.open_date_utc
            delay_bar = int(time_diff.total_seconds() / (60*15))
            open_candle = dataframe.iloc[-delay_bar] if delay_bar != 0 else current_candle
            if current_candle["close"] < (open_candle["close"]  - open_candle['atr'] * self.atr_sl_rate.value):
                return "lost_sell"
        
        if current_profit > 0:
            time_diff = current_time - trade.open_date_utc
            delay_bar = int(time_diff.total_seconds() / (60*15))
            open_candle = dataframe.iloc[-delay_bar] if delay_bar != 0 else current_candle
            if current_candle["close"] > (open_candle["close"] + open_candle['atr'] * self.tpsl_rate.value):
                return "profit_sell"

        return None

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