# source: https://raw.githubusercontent.com/sriram221189/freqtrade/c6b69bfe321ef608bd67f2b633f6a907b0f45313/williams_fractal.py
from freqtrade.strategy import IStrategy
from functools import reduce

class Github_sriram221189_freqtrade__williams_fractal__20260204_084127(IStrategy):
    # Buy hyperspace params:
    buy_params = {
        "fractal_value": 1,
    }

    # Sell hyperspace params:
    sell_params = {
        "fractal_value": -1,
    }

    # ROI table:
    minimal_roi = {
        "0": 0.05
    }

    # Stoploss:
    stoploss = -0.10

    def informative_pairs(self):
        return []

    def populate_indicators(self, dataframe, metadata):
        # Calculate Williams Fractal indicator:
        dataframe = calculate_fractals(dataframe)
        return dataframe

    def populate_buy_trend(self, dataframe, metadata):
        # Buy when bullish fractal is formed:
        conditions = [
            (dataframe["fractals"].shift(2) == self.buy_params["fractal_value"]),
        ]
        if conditions:
            dataframe.loc[
                reduce(lambda x, y: x & y, conditions), "buy"
            ] = 1
        return dataframe

    def populate_sell_trend(self, dataframe, metadata):
        # Sell when bearish fractal is formed:
        conditions = [
            (dataframe["fractals"].shift(2) == self.sell_params["fractal_value"]),
        ]
        if conditions:
            dataframe.loc[
                reduce(lambda x, y: x & y, conditions), "sell"
            ] = 1
        return dataframe

def calculate_fractals(dataframe, column_name="fractals"):
    """Calculate the Williams Fractal indicator."""
    dataframe[column_name] = 0
    for i in range(2, len(dataframe) - 2):
        if (
                (dataframe["high"][i] > dataframe["high"][i - 1])
                and (dataframe["high"][i] > dataframe["high"][i - 2])
                and (dataframe["high"][i] > dataframe["high"][i + 1])
                and (dataframe["high"][i] > dataframe["high"][i + 2])
        ):
            dataframe.at[i, column_name] = -1
        elif (
                (dataframe["low"][i] < dataframe["low"][i - 1])
                and (dataframe["low"][i] < dataframe["low"][i - 2])
                and (dataframe["low"][i] < dataframe["low"][i + 1])
                and (dataframe["low"][i] < dataframe["low"][i + 2])
        ):
            dataframe.at[i, column_name] = 1
    return dataframe

