# source: https://raw.githubusercontent.com/jaredrsommer/freqtradestrategies/9d66f71ce21f2f65feaad6bb967215be22a3cfd6/TwoCandle.py
from freqtrade.strategy import IStrategy
from pandas import DataFrame
import pandas_ta as ta
from technical import qtpylib

class Github_jaredrsommer_freqtradestrategies__TwoCandle__20260518_195114(IStrategy):
    # Strategy parameters
    timeframe = "1h"  # 5-minute timeframe as per the video example
    minimal_roi = {"0": 0.015, "15": 0.012, "30": 0.05, "60": 0.025}  # 1.5% ROI (1:1.5 risk-reward ratio)
    stoploss = -0.03  # 1% stop loss (adjustable)
    # Trailing stop
    trailing_stop = True
    trailing_stop_positive = 0.013
    trailing_stop_positive_offset = 0.035
    trailing_only_offset_is_reached = True

    plot_config = {
        "main_plot": {
        "support": {
          "color": "green",
          "type": "line"
        },
        "resistance": {
          "color": "red",
          "type": "line"
        }
        },
        "subplots": {
        "close": {
          "close_position": {
            "color": "#76f639",
            "type": "bar"
          },
          "close_comparison": {
            "color": "#dedcf9",
            "type": "line"
          }
        },
        "pattern": {
          "pattern": {
            "color": "#165e70",
            "type": "bar"
          },
          "pattern diff": {
            "color": "#744bce",
            "type": "bar"
          }
        }
        }
        }

    # Define custom variables
    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:

        heikinashi = qtpylib.heikinashi(dataframe)

        dataframe['ha_open'] = heikinashi['open']
        dataframe['ha_close'] = heikinashi['close']
        dataframe['ha_high'] = heikinashi['high']
        dataframe['ha_low'] = heikinashi['low']
        # Calculate candle range (high - low)
        dataframe['range'] = dataframe['high'] - dataframe['low']
        dataframe['range_third'] = dataframe['range'] / 3

        # Calculate candle body (close - open)
        dataframe['body'] = abs(dataframe['close'] - dataframe['open'])
        dataframe['body_third'] = dataframe['body'] / 3

        # Simple support/resistance levels using rolling min/max
        dataframe['support'] = dataframe['low'].rolling(window=80).min().shift(80)
        dataframe['resistance'] = dataframe['high'].rolling(window=80).max().shift(80)
        dataframe['midpoint'] = ((dataframe['resistance']-dataframe['support'])/2) + dataframe['support']
        dataframe['trading_range'] = abs(dataframe['support'] - dataframe['resistance']) / 8

        # 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['hl_close_comparison'] = 0  # Default: range
        dataframe.loc[dataframe['close'] > dataframe['prev_high'], 'hl_close_comparison'] = 1  # Bull candle
        dataframe.loc[dataframe['close'] < dataframe['prev_low'], 'hl_close_comparison'] = -1  # Bear candle

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

        # Close comparison: Compare current close to previous candle's range
        dataframe['prev_close'] = dataframe['close'].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['hl_close_comparison'] + 4  # Maps to 0-8 (9 patterns)
        dataframe['body_pattern'] = dataframe['close_body_position'] * 3 + dataframe['close_comparison'] + 4  # Maps to 0-8 (9 patterns)
        dataframe['pattern_mean'] = dataframe['pattern'].rolling(2).mean()
        dataframe['pattern_trend'] = dataframe['pattern'].rolling(9).mean()
        dataframe['pattern_trend_ma'] = dataframe['support'] + (dataframe['pattern_trend'] * dataframe['trading_range'])
        dataframe['pattern diff'] = dataframe['pattern'].diff()



        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'] == 4) &
        #         # Breakout above resistance
        #         (dataframe['close'] > dataframe['resistance'].shift(1)) &
        #         (dataframe['pattern_mean'] >= 4) &
        #         # Previous candle was not bearish (avoid false breakouts)
        #         (dataframe['pattern'].shift(1) != 0)  # Not low close bear
        #     ),
        #     ['enter_long', 'enter_tag']] = (1, 'long 1')

        # dataframe.loc[
        #     (
        #         # High close bull candle (pattern 4: most bullish)
        #         (dataframe['pattern'] == 8) &
        #         # Breakout above resistance
        #         (dataframe['pattern_mean'] >= 4) &
        #         # Previous candle was not bearish (avoid false breakouts)
        #         (dataframe['pattern'].shift(1) == 0)  # Not low close bear
        #     ),
        #     ['enter_long', 'enter_tag']] = (1, 'long 3')

        # dataframe.loc[
        #     (
        #         # High close bull candle (pattern 4: most bullish)
        #         (dataframe['pattern'] <= 7) &
        #         # Breakout above resistance
        #         (dataframe['pattern_mean'] >= 4) &
        #         # Previous candle was not bearish (avoid false breakouts)
        #         (dataframe['pattern'].shift(1) <= 0)  # Not low close bear
        #     ),
        #     ['enter_long', 'enter_tag']] = (1, 'long 4')

        # dataframe.loc[
        #     (
        #         # High close bull candle (pattern 4: most bullish)
        #         (dataframe['pattern'] <= 6) &
        #         # Breakout above resistance
        #         (dataframe['pattern_mean'] >= 4) &
        #         # Previous candle was not bearish (avoid false breakouts)
        #         (dataframe['pattern'].shift(1) <= 0)  # Not low close bear
        #     ),
        #     ['enter_long', 'enter_tag']] = (1, 'long 5')


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


        # Track bias (simplified as a rolling score)
        dataframe['bias'] = 0  # Neutral
        dataframe.loc[dataframe['pattern'] == 4, 'bias'] = 1  # Bullish on high close bull
        dataframe.loc[dataframe['pattern'] == 0, 'bias'] = -1  # Bearish on low close bear
        dataframe['bias'] = dataframe['bias'].rolling(window=3).mean().fillna(0)  # 3-candle bias

        # # Bullish entries
        # dataframe.loc[
        #     # High close bull at breakout
        #     ((dataframe['pattern'] == 4) & (dataframe['close'] > dataframe['resistance'].shift(1))) |
        #     # High close bull after support bounce
        #     ((dataframe['pattern'] == 4) & (dataframe['pattern'].shift(1) == 0) & (dataframe['close'] > dataframe['support'])) |
        #     # Two consecutive high close bull candles
        #     ((dataframe['pattern'] == 4) & (dataframe['pattern'].shift(1) == 4) & (dataframe['bias'] > 0)) |
        #     # High close range after pullback in uptrend
        #     ((dataframe['pattern'] == 1) & (dataframe['bias'] > 0) & (dataframe['close'] > dataframe['support'])),
        #     'enter_long'] = 1

        # # Bearish entries
        # dataframe.loc[
        #     # Low close bear at breakdown
        #     ((dataframe['pattern'] == 0) & (dataframe['close'] < dataframe['support'].shift(1))) |
        #     # Two consecutive low close bear candles
        #     ((dataframe['pattern'] == 0) & (dataframe['pattern'].shift(1) == 0) & (dataframe['bias'] < 0)) |
        #     # Low close bear after resistance rejection
        #     ((dataframe['pattern'] == 0) & (dataframe['close'] < dataframe['resistance']) & (dataframe['bias'] < 0)),
        #     'enter_short'] = 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[
            (
                # High close bull candle (pattern 4: most bullish)
                (dataframe['pattern'] >= 0) &
                # Breakout above resistance
                (dataframe['pattern_mean'] < 3.5) &
                # Previous candle was not bearish (avoid false breakouts)
                (dataframe['pattern'].shift(1) == 8)  # Not low close bear
            ),
            ['exit_long', 'exit_tag']] = (1, 'short1')

        dataframe.loc[
            (
                # High close bull candle (pattern 4: most bullish)
                (dataframe['pattern'] >= 0) &
                # Breakout above resistance3.5
                (dataframe['pattern_mean'] < 3.5) &
                # Previous candle was not bearish (avoid false breakouts)
                (dataframe['pattern'].shift(1) == 7)  # Not low close bear
            ),
            ['exit_long', 'exit_tag']] = (1, 'short2')

        dataframe.loc[
            (
                # High close bull candle (pattern 4: most bullish)
                (dataframe['pattern'] >= 0) &
                # Breakout above resistance
                (dataframe['pattern_mean'] < 3.5) &
                # Previous candle was not bearish (avoid false breakouts)
                (dataframe['pattern'].shift(1) == 6)  # Not low close bear
            ),
            ['exit_long', 'exit_tag']] = (1, 'short1')

        dataframe.loc[
            (
                (dataframe['pattern_mean'].shift() > 4) &
                (dataframe['pattern_mean'] < 4) 
            ),            
            ['exit_long', 'exit_tag']] = (1, 'exit 2')

        # # Bearish entries
        # dataframe.loc[
        #     # Low close bear at breakdown
        #     ((dataframe['pattern'] == 0) & (dataframe['close'] < dataframe['support'].shift(1))) |
        #     # Two consecutive low close bear candles
        #     ((dataframe['pattern'] == 0) & (dataframe['pattern'].shift(1) == 0) & (dataframe['bias'] < 0)) |
        #     # Low close bear after resistance rejection
        #     ((dataframe['pattern'] == 0) & (dataframe['close'] < dataframe['resistance']) & (dataframe['bias'] < 0)),
        #     '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

        return dataframe