# source: https://raw.githubusercontent.com/dhjakhar/BullFlowReversion/1da57f7a23c84e7b8ef7a69bc22dd05372b8c0a0/Fibonacci_Strategy/RatioConfluenceStrategy.py
from freqtrade.strategy import IStrategy
from pandas import DataFrame
import talib.abstract as ta
import numpy as np

class Github_dhjakhar_BullFlowReversion__RatioConfluenceStrategy__20260103_181600(IStrategy):
    # Define the strategy parameters
    timeframe = '5m'  # You can change this to '1m', '15m', etc.
    minimal_roi = {"0": 0.1}  # Example: minimal ROI of 10%
    stoploss = -0.10  # Stop loss at 10%
    trailing_stop = True
    trailing_stop_positive = 0.05  # 5% profit for trailing stop
    trailing_stop_positive_offset = 0.10  # Trailing stop buffer
    trailing_only_offset_is_reached = True

    # You can set these to fine-tune your strategy
    fib_threshold = 0.02
    golden_threshold = 0.015
    math_threshold = 0.02
    lookback = 50

    def __init__(self, config=None):
        super().__init__(config)

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Populate the dataframe with Fibonacci retracement levels, moving averages, etc.
        """
        dataframe['fib_618'] = dataframe['close'].rolling(self.lookback).max() - (
            dataframe['close'].rolling(self.lookback).max() - dataframe['close'].rolling(self.lookback).min()) * 0.618
        dataframe['fib_382'] = dataframe['close'].rolling(self.lookback).max() - (
            dataframe['close'].rolling(self.lookback).max() - dataframe['close'].rolling(self.lookback).min()) * 0.382

        # Golden ratio-based levels
        PHI = 1.618
        high = dataframe['close'].rolling(self.lookback).max()
        low = dataframe['close'].rolling(self.lookback).min()

        dataframe['golden_support'] = low + (high - low) / PHI
        dataframe['golden_resistance'] = high - (high - low) / PHI

        # Moving averages (for math strategy)
        dataframe['ma_short'] = ta.SMA(dataframe, timeperiod=21)
        dataframe['ma_long'] = ta.SMA(dataframe, timeperiod=50)

        # Volatility (for math strategy)
        dataframe['volatility'] = ta.ATR(dataframe, timeperiod=21)

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        This function defines the buy entry conditions.
        In most cases, we just return the signals from populate_buy_trend.
        """
        # Use populate_buy_trend to define entry conditions
        dataframe = self.populate_buy_trend(dataframe, metadata)
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        This function defines the sell exit conditions.
        In most cases, we just return the signals from populate_sell_trend.
        """
        # Use populate_sell_trend to define exit conditions
        dataframe = self.populate_sell_trend(dataframe, metadata)
        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Define conditions for buy signals.
        """
        dataframe.loc[
            (
                # Fibonacci Buy Condition
                (abs(dataframe['close'] - dataframe['fib_618']) / dataframe['close'] < self.fib_threshold)
                |
                # Golden Ratio Buy Condition
                (abs(dataframe['close'] - dataframe['golden_support']) / dataframe['close'] < self.golden_threshold)
                |
                # Mathematical Buy Condition
                ((dataframe['ma_short'] > dataframe['ma_long'] * 1.01) &
                 (dataframe['volatility'] < 0.05) &
                 (abs(dataframe['close'] - dataframe['ma_short']) / dataframe['close'] < self.math_threshold))
            ),
            'buy'] = 1
        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Define conditions for sell signals.
        """
        dataframe.loc[
            (
                # Fibonacci Sell Condition
                (abs(dataframe['close'] - dataframe['fib_382']) / dataframe['close'] < self.fib_threshold)
                |
                # Golden Ratio Sell Condition
                (abs(dataframe['close'] - dataframe['golden_resistance']) / dataframe['close'] < self.golden_threshold)
                |
                # Mathematical Sell Condition
                ((dataframe['ma_short'] < dataframe['ma_long'] * 0.99) &
                 (dataframe['volatility'] < 0.05) &
                 (abs(dataframe['close'] - dataframe['ma_short']) / dataframe['close'] < self.math_threshold))
            ),
            'sell'] = 1
        return dataframe
