# source: https://raw.githubusercontent.com/remiotore/freqtrade/44beaeb6a420cd8e9f2e4ea93e11d6cfa192ee03/strategies/AnomalyDetectorv2_2.py
import numpy as np
from pandas import DataFrame
import pandas as pd
from freqtrade.strategy.interface import IStrategy
from freqtrade.strategy import CategoricalParameter, DecimalParameter, IntParameter
import talib.abstract as ta

class Github_remiotore_freqtrade__AnomalyDetectorv2_2__20260111_210550(IStrategy):
    def version(self) -> str:
        return "AnomalyDetector-v2-1h"

    INTERFACE_VERSION = 3

    """
    Strategy to detect volume anomalies using Z-Score
    """   

    stoploss = -0.99
    timeframe = '1h'

    trailing_stop = True
    trailing_stop_positive = 0.01
    trailing_stop_positive_offset = 0.025
    trailing_only_offset_is_reached = False
    
    fast_length = IntParameter(10, 20, default=12, space='buy')
    slow_length = IntParameter(24, 30, default=26, space='buy')
    signal_length = IntParameter(7, 14, default=9, space='buy')
    rsi_length = IntParameter(10, 30, default=14, space='buy')
    atr_length = IntParameter(10, 30, default=14, space='buy')
    
    plot_config = {

        'main_plot': {
        },
        'subplots': {

            "TVTechRec": {
                'tvsummaryaction': {'color': 'white'}
            },
            "ATR": {
                'atr': {'color': 'white'}
            },
            "RSI": {
                'rsi': {'color': 'purple'},
                'rsi_backup': {'color': 'red'},
            },
            "Volume": {
                'volume': {'color': 'black'},
                'anomaly': {
                    'color': 'orange',
                    'drawstyle': 'steps-mid',
                    'fill_to': 'anomaly',
                    'panel': 'lower',
                    'linestyle': '-',
                    'linewidth': 2,
                },
            },
            "Z-Score": {
                'vol_z_score': {'color': 'blue'},
            },
        }
    }

    startup_candle_count = 999

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=self.rsi_length.value)
        dataframe['atr'] = ta.ATR(dataframe, timeperiod=self.atr_length.value)

        vol_z_score = (dataframe['volume'] - dataframe['volume'].rolling(window=30).mean()) / dataframe['volume'].rolling(window=30).std()
        threshold = 3
        dataframe['anomaly'] = np.where(vol_z_score > threshold, 1, 0)

        delta = dataframe['close'].diff()
        gain = delta.where(delta > 0, 0)
        loss = -delta.where(delta < 0, 0)

        avg_gain = gain.rolling(window=self.rsi_length.value).mean()
        avg_loss = loss.rolling(window=self.rsi_length.value).mean()

        rs = avg_gain / avg_loss

        dataframe['rsi_backup'] = 100 - (100 / (1 + rs)) #For exchanges where RSI shows zero using ta-lib

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe['anomaly'] > 0) &
                (dataframe['atr'] > dataframe['atr'].rolling(window=self.atr_length.value).mean())
            ),
            'enter_long'] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                ((dataframe['rsi'] > 70) | (dataframe['rsi_backup'] > 85))
            ),
            'exit_long'] = 1
        return dataframe