# source: https://raw.githubusercontent.com/DerSalvador/freqtrade-helm-chart/a669dc11b640b0eb63aa8f8b51e9f181fd7ee43c/chart/deployed_strategies/binance-futures-k8s-namespace/NormalizerStrategy.py
import freqtrade.vendor.qtpylib.indicators as qtpylib
import numpy as np
import talib.abstract as ta
from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame
from datetime import datetime, timedelta

class Github_DerSalvador_freqtrade_helm_chart__NormalizerStrategy__20260115_122204(IStrategy):
    INTERFACE_VERSION = 3
    minimal_roi = {'0': 0.18}
    stoploss = -0.99  # effectively disabled.
    timeframe = '1h'
    # Sell signal
    use_exit_signal = True
    exit_profit_only = True
    exit_profit_offset = 0.001  # it doesn't meant anything, just to guarantee there is a minimal profit.
    ignore_roi_if_entry_signal = True
    # Trailing stoploss
    trailing_stop = True
    trailing_only_offset_is_reached = True
    trailing_stop_positive = 0.01
    trailing_stop_positive_offset = 0.015
    # Custom stoploss
    use_custom_stoploss = True
    # Run "populate_indicators()" only for new candle.
    process_only_new_candles = False
    # Number of candles the strategy requires before producing valid signals
    startup_candle_count: int = 610
    # Optional order type mapping.
    order_types = {'entry': 'limit', 'exit': 'limit', 'stoploss': 'market', 'stoploss_on_exchange': False}

    def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> float:
        # Manage losing trades and open room for better ones.
        if (current_profit < 0) & (current_time - timedelta(minutes=300) > trade.open_date_utc):
            return 0.01
        return 0.99

    def fischer_norm(self, x, lookback):
        res = np.zeros_like(x)
        for i in range(lookback, len(x)):
            x_min = np.min(x[i - lookback:i + 1])
            x_max = np.max(x[i - lookback:i + 1])
            #res[i] = (2*(x[i] - x_min) / (x_max - x_min)) - 1
            res[i] = (x[i] - x_min) / (x_max - x_min)
        return res

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        lookback = [13, 21, 34, 55, 89, 144, 233, 377, 610]
        for look in lookback:
            dataframe[f'norm_{look}'] = self.fischer_norm(dataframe['close'].values, look)
        collist = [col for col in dataframe.columns if col.startswith('norm')]
        dataframe['pct_sum'] = dataframe[collist].sum(axis=1)
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:  # Make sure Volume is not 0
        dataframe.loc[(dataframe['pct_sum'] < 0.2) & (dataframe['volume'] > 0), 'entry'] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:  # Make sure Volume is not 0
        dataframe.loc[(dataframe['pct_sum'] > 8) & (dataframe['volume'] > 0), 'exit'] = 1
        return dataframe