# source: https://raw.githubusercontent.com/remiotore/freqtrade/44beaeb6a420cd8e9f2e4ea93e11d6cfa192ee03/strategies/darphane_501_v3.py
from datetime import datetime
from typing import Optional
import logging
import talib.abstract as ta

import numpy as np
import freqtrade.vendor.qtpylib.indicators as qtpylib
from freqtrade.persistence import Trade
from freqtrade.strategy import (BooleanParameter, DecimalParameter, IntParameter, IStrategy,
                                RealParameter,informative,stoploss_from_open,timeframe_to_minutes,stoploss_from_absolute)
from functools import reduce
import time

from pandas import DataFrame, Series, DatetimeIndex, merge


from technical.util import resample_to_interval, resampled_merge
log = logging.getLogger(__name__)






class Github_remiotore_freqtrade__darphane_501_v3__20260111_210550(IStrategy):
    INTERFACE_VERSION = 3
    def version(self) -> str:
        return "v106.00.00"
    
    minimal_roi = {
        "0": 100.00  
    }
    timeframe = '5m'
    order_types = {
        'entry': 'market',
        'exit': 'market',
        'stoploss': 'market',
        'stoploss_on_exchange': False
    }
    order_time_in_force = {
        'entry': 'gtc',
        'exit': 'gtc',
    }
    stoploss = -0.99

    trailing_stop = False
    trailing_only_offset_is_reached = False
    trailing_stop_positive = 0.01
    trailing_stop_positive_offset = 0.03

    use_custom_stoploss = True
    
    process_only_new_candles = True
    position_adjustment_enable = True
    
    can_short = True
    bot_started = True

    max_entry_position_adjustment = 5
    custom_info = {}












    @property
    def protections(self):
        return [
            
            {
                "method": "MaxDrawdown",
                "lookback_period_candles": 5,
                "trade_limit": 2,
                "stop_duration_candles": 2,
                "max_allowed_drawdown": 0.19
            }
        ]

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



        lvl = self.custom_info[f'{pair}']['Level']
        

        if (self.custom_info[f'{pair}']['Level'] == 1):
            if 2.00 < current_profit :
                return stoploss_from_open(2.00, current_profit, is_short=trade.is_short)
            elif 1.80 < current_profit <= 2.00: # 180%
                return stoploss_from_open(1.60, current_profit, is_short=trade.is_short)
            elif 1.70 < current_profit <= 1.80: # 170%
                return stoploss_from_open(1.20, current_profit, is_short=trade.is_short)
            elif 1.60 < current_profit <= 1.80: # 160%
                return stoploss_from_open(1.20, current_profit, is_short=trade.is_short)
            elif 1.50 < current_profit <= 1.80: # 150%
                return stoploss_from_open(1.20, current_profit, is_short=trade.is_short)
            elif 1.40 < current_profit <= 1.50: # 140%
                return stoploss_from_open(1.00, current_profit, is_short=trade.is_short)
            elif 1.30 < current_profit <= 1.50: # 130%
                return stoploss_from_open(1.00, current_profit, is_short=trade.is_short)
            elif 1.00 < current_profit <= 1.30: # 100
                return stoploss_from_open(0.65, current_profit, is_short=trade.is_short)
            elif 0.90 < current_profit <= 1.00: # 90%
                return stoploss_from_open(0.50, current_profit, is_short=trade.is_short)
            elif 0.80 < current_profit <= 0.90: # 80%
                return stoploss_from_open(0.50, current_profit, is_short=trade.is_short)
            elif 0.70 < current_profit <= 0.80: # 70%
                return stoploss_from_open(0.40, current_profit, is_short=trade.is_short)
            elif 0.60 < current_profit <= 0.70: # 60%
                return stoploss_from_open(0.35, current_profit, is_short=trade.is_short)
            elif 0.40 < current_profit <= 0.60: # 40%
                return stoploss_from_open(0.30, current_profit, is_short=trade.is_short)
            elif 0.20 < current_profit <= 0.40: # 30%
                return stoploss_from_open(0.20, current_profit, is_short=trade.is_short)

        elif (self.custom_info[f'{pair}']['Level'] == 2):
            if 2.00 < current_profit :
                return stoploss_from_open(2.00, current_profit, is_short=trade.is_short)
            elif 1.80 < current_profit <= 2.00: # 180%
                return stoploss_from_open(1.60, current_profit, is_short=trade.is_short)
            elif 1.70 < current_profit <= 1.80: # 170%
                return stoploss_from_open(1.20, current_profit, is_short=trade.is_short)
            elif 1.60 < current_profit <= 1.80: # 160%
                return stoploss_from_open(1.20, current_profit, is_short=trade.is_short)
            elif 1.50 < current_profit <= 1.80: # 150%
                return stoploss_from_open(1.20, current_profit, is_short=trade.is_short)
            elif 1.40 < current_profit <= 1.50: # 140%
                return stoploss_from_open(1.00, current_profit, is_short=trade.is_short)
            elif 1.30 < current_profit <= 1.50: # 130%
                return stoploss_from_open(1.00, current_profit, is_short=trade.is_short)
            elif 1.00 < current_profit <= 1.30: # 100
                return stoploss_from_open(0.65, current_profit, is_short=trade.is_short)
            elif 0.90 < current_profit <= 1.00: # 90%
                return stoploss_from_open(0.50, current_profit, is_short=trade.is_short)
            elif 0.80 < current_profit <= 0.90: # 80%
                return stoploss_from_open(0.50, current_profit, is_short=trade.is_short)
            elif 0.70 < current_profit <= 0.80: # 70%
                return stoploss_from_open(0.40, current_profit, is_short=trade.is_short)
            elif 0.60 < current_profit <= 0.70: # 60%
                return stoploss_from_open(0.35, current_profit, is_short=trade.is_short)
            elif 0.40 < current_profit <= 0.60: # 40%
                return stoploss_from_open(0.30, current_profit, is_short=trade.is_short)
            elif 0.20 < current_profit <= 0.40: # 30%
                return stoploss_from_open(0.20, current_profit, is_short=trade.is_short)

        elif (self.custom_info[f'{pair}']['Level'] == 3):
            if 2.00 < current_profit :
                return stoploss_from_open(2.00, current_profit, is_short=trade.is_short)
            elif 1.80 < current_profit <= 2.00: # 180%
                return stoploss_from_open(1.60, current_profit, is_short=trade.is_short)
            elif 1.70 < current_profit <= 1.80: # 170%
                return stoploss_from_open(1.20, current_profit, is_short=trade.is_short)
            elif 1.60 < current_profit <= 1.80: # 160%
                return stoploss_from_open(1.20, current_profit, is_short=trade.is_short)
            elif 1.50 < current_profit <= 1.80: # 150%
                return stoploss_from_open(1.20, current_profit, is_short=trade.is_short)
            elif 1.40 < current_profit <= 1.50: # 140%
                return stoploss_from_open(1.00, current_profit, is_short=trade.is_short)
            elif 1.30 < current_profit <= 1.50: # 130%
                return stoploss_from_open(1.00, current_profit, is_short=trade.is_short)
            elif 1.00 < current_profit <= 1.30: # 100
                return stoploss_from_open(0.65, current_profit, is_short=trade.is_short)
            elif 0.90 < current_profit <= 1.00: # 90%
                return stoploss_from_open(0.50, current_profit, is_short=trade.is_short)
            elif 0.80 < current_profit <= 0.90: # 80%
                return stoploss_from_open(0.50, current_profit, is_short=trade.is_short)
            elif 0.70 < current_profit <= 0.80: # 70%
                return stoploss_from_open(0.40, current_profit, is_short=trade.is_short)
            elif 0.60 < current_profit <= 0.70: # 60%
                return stoploss_from_open(0.35, current_profit, is_short=trade.is_short)
            elif 0.40 < current_profit <= 0.60: # 40%
                return stoploss_from_open(0.30, current_profit, is_short=trade.is_short)
            elif 0.20 < current_profit <= 0.40: # 30%
                return stoploss_from_open(0.20, current_profit, is_short=trade.is_short)

        elif (self.custom_info[f'{pair}']['Level'] == 4):
            if 2.00 < current_profit :
                return stoploss_from_open(2.00, current_profit, is_short=trade.is_short)
            elif 1.80 < current_profit <= 2.00: # 180%
                return stoploss_from_open(1.60, current_profit, is_short=trade.is_short)
            elif 1.70 < current_profit <= 1.80: # 170%
                return stoploss_from_open(1.20, current_profit, is_short=trade.is_short)
            elif 1.60 < current_profit <= 1.80: # 160%
                return stoploss_from_open(1.20, current_profit, is_short=trade.is_short)
            elif 1.50 < current_profit <= 1.80: # 150%
                return stoploss_from_open(1.20, current_profit, is_short=trade.is_short)
            elif 1.40 < current_profit <= 1.50: # 140%
                return stoploss_from_open(1.00, current_profit, is_short=trade.is_short)
            elif 1.30 < current_profit <= 1.50: # 130%
                return stoploss_from_open(1.00, current_profit, is_short=trade.is_short)
            elif 1.00 < current_profit <= 1.30: # 100
                return stoploss_from_open(0.65, current_profit, is_short=trade.is_short)
            elif 0.90 < current_profit <= 1.00: # 90%
                return stoploss_from_open(0.50, current_profit, is_short=trade.is_short)
            elif 0.80 < current_profit <= 0.90: # 80%
                return stoploss_from_open(0.50, current_profit, is_short=trade.is_short)
            elif 0.70 < current_profit <= 0.80: # 70%
                return stoploss_from_open(0.40, current_profit, is_short=trade.is_short)
            elif 0.60 < current_profit <= 0.70: # 60%
                return stoploss_from_open(0.35, current_profit, is_short=trade.is_short)
            elif 0.40 < current_profit <= 0.60: # 40%
                return stoploss_from_open(0.30, current_profit, is_short=trade.is_short)
            elif 0.20 < current_profit <= 0.40: # 30%
                return stoploss_from_open(0.20, current_profit, is_short=trade.is_short)
            elif 0.10 < current_profit <= 0.20: # 30%
                return stoploss_from_open(0.10, current_profit, is_short=trade.is_short)

        
        return 1
        

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


        if (self.custom_info[f'{pair}']['Level'] == 1):
            if (current_profit >= 0.10):

               return 'Level 1 Exit - Take Profit'
            if (current_profit <= -0.10):
                self.custom_info[f'{pair}']['Level'] = 2
                return 'Level 1 Exit - StopLoss / Entering Level 2'

        if (self.custom_info[f'{pair}']['Level'] == 2):
            if (current_profit >= 0.10):

               return 'Level 2 Exit - Take Profit'
            if (current_profit <= -0.10):
                self.custom_info[f'{pair}']['Level'] = 3
                return 'Level 2 Exit - StopLoss / Entering Level 3'

        if (self.custom_info[f'{pair}']['Level'] == 3):
            if (current_profit >= 0.10):

               return 'Level 3 Exit - Take Profit'
            if (current_profit <= -0.10):
                self.custom_info[f'{pair}']['Level'] = 4
                return 'Level 3 Exit - StopLoss / Entering Level 4'

        if (self.custom_info[f'{pair}']['Level'] == 4):
            if (current_profit >= 0.10):

               return 'Level 4 Exit - Take Profit'
            if (current_profit <= -0.10):
                self.custom_info[f'{pair}']['Level'] = 5
                return 'Level 4 Exit - StopLoss / Entering Level 5'

        if (self.custom_info[f'{pair}']['Level'] == 5):
            if (current_profit >= 0.10):

               return 'Level 5 Exit - Take Profit'
            if (current_profit <= -0.10):
                self.custom_info[f'{pair}']['Level'] = 6
                return 'Level 5 Exit - StopLoss / Entering Level 6'

        if (self.custom_info[f'{pair}']['Level'] == 6):
            if (current_profit >= 0.10):

               return 'Level 6 Exit - Take Profit'
            if (current_profit <= -0.10):
                self.custom_info[f'{pair}']['Level'] = 0
                return 'Level 6 Exit - StopLoss / RESET'
















        
        return None

    def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
                            proposed_stake: float, min_stake: Optional[float], max_stake: float,
                            leverage: float, entry_tag: Optional[str], side: str,
                            **kwargs) -> float:

        if (self.custom_info[pair]['Level'] == 2):

            proposed_stake = 30
        elif (self.custom_info[pair]['Level'] == 3):

            proposed_stake = 90
        elif (self.custom_info[pair]['Level'] == 4):

            proposed_stake = 270
        elif (self.custom_info[pair]['Level'] == 5):

            proposed_stake = 810
        elif (self.custom_info[pair]['Level'] == 6):

            proposed_stake = 1500







        return proposed_stake 

    def adjust_trade_position(self, trade: Trade, current_time: datetime,
                              current_rate: float, current_profit: float,
                              min_stake: Optional[float], max_stake: float,
                              current_entry_rate: float, current_exit_rate: float,
                              current_entry_profit: float, current_exit_profit: float,
                              **kwargs) -> Optional[float]:
       
        return None

    def bot_start(self):
        self.bot_started = True

    def informative_pairs(self):

        return []

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        if not metadata["pair"] in self.custom_info:

            self.custom_info[metadata["pair"]] = {}
            self.custom_info[metadata["pair"]]['Level'] = {}










        dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100, price='close')
        dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50, price='close')
        dataframe['sma25'] = ta.SMA(dataframe, timeperiod=25, price='close')
        dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200, price='close')
        dataframe['sma_15'] = ta.SMA(dataframe, timeperiod=15)
        dataframe['cci_one'] = ta.CCI(dataframe, timeperiod=170)
        dataframe['cci_two'] = ta.CCI(dataframe, timeperiod=34)
        dataframe['rsi'] = ta.RSI(dataframe)
        dataframe['mfi'] = ta.MFI(dataframe)

        dataframe['cmf'] = chaikin_mf(dataframe) # period = 20
        dataframe['cmo'] = ta.CMO(dataframe) # period = 14





        str = f'{metadata["pair"]}'
        str = str.replace('/','_')
        dataframe.to_csv(f'user_data/pair_test/{str}_dataframe.csv', index=False, header=True, mode='w', encoding='UTF-8')
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:

        dataframe.loc[
            (
                    (dataframe['cci_one'] < -100)
                    & (dataframe['cci_two'] < -100)
                    & (dataframe['cmf'] < -0.1)
                    & (dataframe['mfi'] < 25)
                    & (dataframe['rsi'] < 30)




            ),
            ['enter_long','enter_tag']] = (1,'Long1')
        
        dataframe.loc[
            (
                    (dataframe['cmo'] < -50)
                    & (dataframe['rsi'] < 22)
                    

            ),
            ['enter_long','enter_tag']] = (1,'Long2')
        
        
        
        dataframe.loc[
            (


                (dataframe['cci_one'] > 100)
                & (dataframe['cci_two'] > 100)
                & (dataframe['cmf'] > 0.1)
                & (dataframe['mfi'] > 75)
                & (dataframe['rsi'] > 75)
            ),
            ['enter_short','enter_tag']] = (1,'Short1')
            
        dataframe.loc[
            (
                (dataframe['cmo'] > 70)
              & (dataframe['rsi'] > 75)
            ),
            ['enter_short','enter_tag']] = (1,'Short2')

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        

        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:

        return 1.0

    def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float,
                            time_in_force: str, current_time: datetime, entry_tag: Optional[str],
                            side: str, **kwargs) -> bool:
        
        if (self.custom_info[f'{pair}']['Level'] == {} or self.custom_info[f'{pair}']['Level'] == 0):
            self.custom_info[f'{pair}']['Level'] = 1
        
        ll = self.custom_info[f'{pair}']['Level']

        return True
    
    def colored(self,param, color):
        color_codes = {
            'red': '\033[91m',
            'green': '\033[92m',
            'yellow': '\033[93m',
        }
        return color_codes[color] + param + '\033[0m'

    def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float,
                           rate: float, time_in_force: str, exit_reason: str,
                           current_time: datetime, **kwargs) -> bool:

        filled_entries = trade.select_filled_orders(trade.entry_side)
        min_profit_rate = trade.max_rate if trade.is_short else trade.min_rate
        max_profit_rate = trade.min_rate if trade.is_short else trade.max_rate

        min_profit = (trade.calc_profit_ratio(min_profit_rate) * 100)
        max_profit = (trade.calc_profit_ratio(max_profit_rate) * 100)

        profit = (trade.calc_profit_ratio(rate) * 100)

        ll = self.custom_info[f'{pair}']['Level']
        
        if profit < 0:
            if ll == '0' or ll == 0 :
                log.info(
                f'EXIT Pair: {pair:13} | Level: {ll} | Exit Reason: {exit_reason} | Min_profit: {min_profit:.2f}% | Max_profit: {max_profit:.2f}% |  profit: {profit:.2f}% | {current_time}')
            else:
                self.log(
                f'EXIT Pair: {pair:13} | Level: {ll} | Exit Reason: {exit_reason} | Min_profit: {min_profit:.2f}% | Max_profit: {max_profit:.2f}% |  profit: {profit:.2f}% | {current_time}',color='red')
        else:
            self.log(
                f'EXIT Pair: {pair:13} | Level: {ll} | Exit Reason: {exit_reason} | Min_profit: {min_profit:.2f}% | Max_profit: {max_profit:.2f}% |  profit: {profit:.2f}% | {current_time}',color='green')
            self.custom_info[f'{pair}']['Level'] = 0
        
        return True

    def log(self, param, color):
        log.info(self.colored(param, color))

def chaikin_mf(df, periods=20):
    close = df['close']
    low = df['low']
    high = df['high']
    volume = df['volume']

    mfv = ((close - low) - (high - close)) / (high - low)
    mfv = mfv.fillna(0.0)  # float division by zero
    mfv *= volume
    cmf = mfv.rolling(periods).sum() / volume.rolling(periods).sum()

    return Series(cmf, name='cmf')



