# source: https://raw.githubusercontent.com/jaredrsommer/freqtradestrategies/9d66f71ce21f2f65feaad6bb967215be22a3cfd6/2Candle%20(3).py
from datetime import datetime
from freqtrade.persistence import Trade
from freqtrade.strategy import IStrategy, informative
from pandas import DataFrame
import numpy
import talib.abstract as ta
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter, 
                                IStrategy, IntParameter, RealParameter, merge_informative_pair)

class Github_jaredrsommer_freqtradestrategies__2Candle__20260518_195114(IStrategy):
    # Strategy parameters
    timeframe = "1h"  # 5-minute timeframe as per the video example
    minimal_roi = {}  # 1.5% ROI (1:1.5 risk-reward ratio)
    stoploss = -0.04  # 1% stop loss (adjustable)
    # Trailing stop:
    trailing_stop = True  # value loaded from strategy
    trailing_stop_positive = 0.025 # value loaded from strategy
    trailing_stop_positive_offset = 0.10 # value loaded from strategy
    trailing_only_offset_is_reached = True  # value loaded from strategy
    buy_threshold = DecimalParameter(3.0, 8.0, default=4.0, decimals=1, space="buy")
    rsi_threshold = DecimalParameter(40.0, 70.0, default=65.0, decimals=1, space="buy")
    sell_threshold = DecimalParameter(3.0, 4.0, default=4.0, decimals=1, space="sell")
    sr_length = IntParameter(12, 50, default=24, space="buy")
    sr_shift = IntParameter(12, 50, default=24, space="buy")
    fast_rsi = IntParameter(4, 20, default=12, space="buy")

    @informative('4h')
    def populate_indicators_4h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Calculate candle range (high - low)
        dataframe['range'] = dataframe['high'] - dataframe['low']
        dataframe['range_third'] = dataframe['range'] / 3

        # Close position: Determine if close is in upper, mid, or lower third
        dataframe['close_position'] = 0  # Default: mid
        dataframe.loc[dataframe['close'] > (dataframe['high'] - dataframe['range_third']), 'close_position'] = 1  # High close
        dataframe.loc[dataframe['close'] < (dataframe['low'] + dataframe['range_third']), 'close_position'] = -1  # Low close

        # Close comparison: Compare current close to previous candle's range
        dataframe['prev_high'] = dataframe['high'].shift(1)
        dataframe['prev_low'] = dataframe['low'].shift(1)
        dataframe['close_comparison'] = 0  # Default: range
        dataframe.loc[dataframe['close'] > dataframe['prev_high'], 'close_comparison'] = 1  # Bull candle
        dataframe.loc[dataframe['close'] < dataframe['prev_low'], 'close_comparison'] = -1  # Bear candle
        dataframe['CO2'] = ((dataframe['close'] - dataframe['open']) / 2) + dataframe['open']


        # Combine close position and close comparison into 9 patterns
        dataframe['pattern'] = dataframe['close_position'] * 3 + dataframe['close_comparison'] + 4  # Maps to 0-8 (9 patterns)
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=6)
        return dataframe

    # Define custom variables
    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Calculate candle range (high - low)
        dataframe['range'] = dataframe['high'] - dataframe['low']
        dataframe['range_third'] = dataframe['range'] / 3

        # Close position: Determine if close is in upper, mid, or lower third
        dataframe['close_position'] = 0  # Default: mid
        dataframe.loc[dataframe['close'] > (dataframe['high'] - dataframe['range_third']), 'close_position'] = 1  # High close
        dataframe.loc[dataframe['close'] < (dataframe['low'] + dataframe['range_third']), 'close_position'] = -1  # Low close

        # Close comparison: Compare current close to previous candle's range
        dataframe['prev_high'] = dataframe['high'].shift(1)
        dataframe['prev_low'] = dataframe['low'].shift(1)
        dataframe['close_comparison'] = 0  # Default: range
        dataframe.loc[dataframe['close'] > dataframe['prev_high'], 'close_comparison'] = 1  # Bull candle
        dataframe.loc[dataframe['close'] < dataframe['prev_low'], 'close_comparison'] = -1  # Bear candle

        # Combine close position and close comparison into 9 patterns
        dataframe['pattern'] = dataframe['close_position'] * 3 + dataframe['close_comparison'] + 4  # Maps to 0-8 (9 patterns)
        dataframe['pattern_avg'] = ((dataframe['pattern'] + dataframe['pattern_4h']) / 2).rolling(2).mean()
        # Simple support/resistance levels using rolling min/max
        dataframe['support'] = dataframe['low_4h'].rolling(window=self.sr_length.value).min().shift(self.sr_shift.value)
        dataframe['resistance'] = dataframe['high_4h'].rolling(window=self.sr_length.value).max().shift(self.sr_shift.value)

        # 4h S/R 
        dataframe['range_4h'] = dataframe['resistance'] - dataframe['support']
        dataframe['inflection'] = (dataframe['range_4h']/2) + dataframe['support']
        dataframe['range_third_4h'] = dataframe['range_4h'] / 3

        # Close position: Determine if close is in upper, mid, or lower third
        dataframe['CO2_position'] = 0  # Default: mid
        dataframe.loc[dataframe['CO2_4h'] > (dataframe['resistance'] - dataframe['range_third_4h']), 'CO2_position'] = 1  # High close
        dataframe.loc[dataframe['CO2_4h'] < (dataframe['support'] + dataframe['range_third_4h']), 'CO2_position'] = -1  # Low close

        # Close comparison: Compare current close to previous candle's range
        dataframe['prev_high_4h'] = dataframe['resistance'].shift(1)
        dataframe['prev_low_4h'] = dataframe['support'].shift(1)
        dataframe['close_c'] = 0
        dataframe.loc[dataframe['close'] > dataframe['close_4h'].shift(4), 'close_c'] = 1  # Bull candle
        dataframe.loc[dataframe['close'] < dataframe['close_4h'].shift(4), 'close_c'] = -1  # Bear candle
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=self.fast_rsi.value)

        # # Combine close position and close comparison into 9 patterns
        dataframe['pattern_CO2'] = dataframe['CO2_position'] * 3 + dataframe['close_c'] + 4  # Maps to 0-8 (9 patterns)
        dataframe['bull_bear'] = 0 
        dataframe.loc[dataframe['CO2_4h'] < dataframe['close'], 'bull_bear'] = 1  # High close
        dataframe.loc[dataframe['CO2_4h'] > dataframe['close'], 'bull_bear'] = -1  # Low close

        # timestamp = datetime.now().strftime('%Y-%m-%d_%H%M')
        # pair = metadata['pair'].replace('/', '_')  # Replace '/' with '_' for valid filename
        # filename = f"{pair}_{timestamp}.csv"
        # dataframe.to_csv(filename, index=True)
        # logger.info(f"Exported DataFrame for {pair} to {filename}")

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Buy conditions based on Two Candle Theory
        dataframe.loc[
            (
                # High close bull candle (pattern 4: most bullish)
                (dataframe['pattern_avg'] >= self.buy_threshold.value) &
                (dataframe['pattern_avg'].shift() < 8) &
                (dataframe['rsi_4h'] < self.rsi_threshold.value) &
                (dataframe['rsi'] > dataframe['rsi_4h'])
                # Breakout above resistance
                # (dataframe['close'] > dataframe['resistance'].shift(1)) &
                # Previous candle was not bearish (avoid false breakouts)
                # (dataframe['pattern'].shift(1) != 0)  # Not low close bear
            ),
            ['enter_long', 'enter_tag']] = (1, 'Pattern and RSI')

        dataframe.loc[
            (
                # High close bull candle (pattern 4: most bullish)
                (dataframe['pattern_avg'] >= self.buy_threshold.value) &
                (dataframe['pattern_avg'].shift() < 8) &
                (dataframe['CO2_4h'] > dataframe['resistance']) &
                (dataframe['CO2_4h'].shift() < dataframe['resistance'].shift()) & 
                (dataframe['rsi_4h'] < self.rsi_threshold.value) &
                (dataframe['rsi'] > dataframe['rsi_4h'])
                # Breakout above resistance
                # (dataframe['close'] > dataframe['resistance'].shift(1)) &
                # Previous candle was not bearish (avoid false breakouts)
                # (dataframe['pattern'].shift(1) != 0)  # Not low close bear
            ),
            ['enter_long', 'enter_tag']] = (1, 'Resistance Cross')

        dataframe.loc[
            (
                # High close bull candle (pattern 4: most bullish)
                (dataframe['pattern_avg'] >= self.buy_threshold.value) &
                # (dataframe['pattern_avg'].shift() < 8) &
                (dataframe['CO2_4h'] > dataframe['support']) &
                (dataframe['CO2_4h'].shift() < dataframe['support'].shift()) 
                # (dataframe['rsi_4h'] < self.rsi_threshold.value) 
                # (dataframe['rsi'] > dataframe['rsi_4h'])
                # Breakout above resistance
                # (dataframe['close'] > dataframe['resistance'].shift(1)) &
                # Previous candle was not bearish (avoid false breakouts)
                # (dataframe['pattern'].shift(1) != 0)  # Not low close bear
            ),
            ['enter_long', 'enter_tag']] = (1, 'Support Cross')

        dataframe.loc[
            (
                # High close bull candle (pattern 4: most bullish)
                (dataframe['pattern_avg'] >= self.buy_threshold.value) &
                # (dataframe['pattern_avg'].shift() < 8) &
                (dataframe['CO2_4h'] < dataframe['support']) &
                (dataframe['CO2_4h'].shift(4) < dataframe['CO2_4h']) &
                # (dataframe['rsi_4h'] < self.rsi_threshold.value) 
                (dataframe['rsi'] > dataframe['rsi_4h'])
                # Breakout above resistance
                # (dataframe['close'] > dataframe['resistance'].shift(1)) &
                # Previous candle was not bearish (avoid false breakouts)
                # (dataframe['pattern'].shift(1) != 0)  # Not low close bear
            ),
            ['enter_long', 'enter_tag']] = (1, 'Below Support 4h pull up')


        dataframe.loc[
            (
                # High close bull candle (pattern 4: most bullish)
                # (dataframe['pattern_avg'] >= self.buy_threshold.value) &
                # (dataframe['pattern_avg'].shift() < 8) &
                (dataframe['CO2_4h'] < dataframe['support']) &
                (dataframe['rsi_4h'] < 10) &
                (dataframe['rsi'] > dataframe['rsi_4h'])
                # Breakout above resistance
                # (dataframe['close'] > dataframe['resistance'].shift(1)) &
                # Previous candle was not bearish (avoid false breakouts)
                # (dataframe['pattern'].shift(1) != 0)  # Not low close bear
            ),
            ['enter_long', 'enter_tag']] = (1, '4h Extreme RSI')

        # # Alternative buy: High close bull after support bounce
        # dataframe.loc[
        #     (
        #         (dataframe['pattern'] == 4) &
        #         (dataframe['close'] > dataframe['support']) &
        #         (dataframe['pattern'].shift(1) == 0)  # Previous was low close bear
        #     ),
        #     'enter_long'] = 1

        # # Sell conditions (short entry)
        # dataframe.loc[
        #     (
        #         # Low close bear candle (pattern 0: most bearish)
        #         (dataframe['pattern'] == 0) &
        #         # Breakdown below support
        #         (dataframe['close'] < dataframe['support'].shift(1)) &
        #         # Previous candle was not bullish (avoid false breakdowns)
        #         (dataframe['pattern'].shift(1) != 4)  # Not high close bull
        #     ),
        #     'enter_short'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Exit long on strong bearish signal
        # dataframe.loc[
        #     # (dataframe['enter_long'].shift(1) == 1) &
        #     (dataframe['pattern_avg'] <= self.sell_threshold.value),  # Low close bear candle
        #     'exit_long'] = 1

        # # Exit short on strong bullish signal
        # dataframe.loc[
        #     (dataframe['enter_short'].shift(1) == 1) &
        #     (dataframe['pattern'] == 4),  # High close bull candle
        #     'exit_short'] = 1

        dataframe.loc[
            (
                # High close bull candle (pattern 4: most bullish)
                # (dataframe['pattern_avg'] >= self.buy_threshold.value) &
                # (dataframe['pattern_avg'].shift() < 8) &
                (dataframe['CO2_4h'] > dataframe['resistance']) &
                (dataframe['close'] > dataframe['resistance']) &
                (dataframe['close'] < dataframe['CO2_4h']) &
                (dataframe['rsi_4h'] > 85) 
                # (dataframe['rsi'] > dataframe['rsi_4h'])
                # Breakout above resistance
                # (dataframe['close'] > dataframe['resistance'].shift(1)) &
                # Previous candle was not bearish (avoid false breakouts)
                # (dataframe['pattern'].shift(1) != 0)  # Not low close bear
            ),
            ['exit_long', 'exit_tag']] = (1, 'Above Resistance 4h')

        # dataframe.loc[
        #     (
        #         # High close bull candle (pattern 4: most bullish)
        #         # (dataframe['pattern_avg'] >= self.buy_threshold.value) &
        #         # (dataframe['pattern_avg'].shift() < 8) &
        #         (dataframe['CO2_4h'] < dataframe['resistance']) &
        #         (dataframe['CO2_4h'].shift() > dataframe['resistance'].shift()) 
        #         # (dataframe['rsi'] > dataframe['rsi_4h'])
        #         # Breakout above resistance
        #         # (dataframe['close'] > dataframe['resistance'].shift(1)) &
        #         # Previous candle was not bearish (avoid false breakouts)
        #         # (dataframe['pattern'].shift(1) != 0)  # Not low close bear
        #     ),
        #     ['exit_long', 'exit_tag']] = (1, 'Resistance Cross')


        # dataframe.loc[
        #     (
        #         # High close bull candle (pattern 4: most bullish)
        #         # (dataframe['pattern_avg'] >= self.buy_threshold.value) &
        #         # (dataframe['pattern_avg'].shift() < 8) &
        #         (dataframe['CO2_4h'] < dataframe['support']) &
        #         (dataframe['CO2_4h'].shift() > dataframe['support'].shift()) 
        #         # (dataframe['rsi'] > dataframe['rsi_4h'])
        #         # Breakout above resistance
        #         # (dataframe['close'] > dataframe['resistance'].shift(1)) &
        #         # Previous candle was not bearish (avoid false breakouts)
        #         # (dataframe['pattern'].shift(1) != 0)  # Not low close bear
        #     ),
        #     ['exit_long', 'exit_tag']] = (1, 'Below Support 4h cross')

        return dataframe