# source: https://raw.githubusercontent.com/Filimonov-Eremeyka/freqtrade/edf4ff8f6dc4d6617f318dd5ebaa0c3427654b1f/user_data/strategies/SkdVisualization.py
import logging
from freqtrade.strategy import IStrategy
from pandas import DataFrame

from skd_enhanced import EnhancedSkdIndicator, SkdLevelVisualizer


class Github_Filimonov_Eremeyka_freqtrade__SkdVisualization__20250905_154014(IStrategy):
    """
    Визуализация СКО под Freqtrade:
    - сигнал на t+1;
    - BUY — зелёный, SELL — красный;
    - отрезки длиной 5 свечей;
    - слоты с cooldown=1, отключение наложений:
        * expire_opposite_on_new=True (гасим противоположные активные уровни)
        * same_side_latest_only=True (оставляем только последний уровень той же стороны)
    - фильтры контрастности/дистанции по умолчанию выключены (показываем всё).
    """
    INTERFACE_VERSION = 3
    logger = logging.getLogger(__name__)

    timeframe = "5m"
    startup_candle_count = 100

    minimal_roi = {"0": 100}
    stoploss = -1.0
    process_only_new_candles = True

    # --- параметры индикатора ---
    skd_method: str = "basic"          # можно: "zscore", "percentile", "rvol", "stoch"
    skd_vol_min: float | None = None

    skd_percentile_lookback: int = 20
    skd_percentile: float = 70.0
    skd_rvol_lookback: int = 20
    skd_rvol_threshold: float = 1.5
    skd_zscore_lookback: int = 20
    skd_zscore_threshold: float = 2.0
    skd_stoch_lookback: int = 14
    skd_stoch_threshold: float = 80.0

    skd_signal_lag_bars: int = 1

    skd_min_distance_mode: str = "pct"
    skd_min_distance_pct: float = 0.0
    skd_atr_period: int = 14
    skd_min_distance_atr_mult: float = 0.0
    skd_filter_ttl_bars: int = 1

    # --- отрезки / визуализация ---
    skd_level_ttl: int = 5
    skd_max_slots: int = 4
    skd_slot_cooldown_bars: int = 1
    skd_expire_opposite_on_new: bool = True
    skd_same_side_latest_only: bool = True

    # цвета
    _BUY_COLOR = "#2ecc71"   # зелёный
    _SELL_COLOR = "#e74c3c"  # красный

    _BUY_LINE = {"mode": "lines", "line": {"color": _BUY_COLOR}}
    _SELL_LINE = {"mode": "lines", "line": {"color": _SELL_COLOR}}
    _BUY_MARKER = {"mode": "markers", "marker": {"symbol": "circle", "size": 8, "color": _BUY_COLOR}}
    _SELL_MARKER = {"mode": "markers", "marker": {"symbol": "circle", "size": 8, "color": _SELL_COLOR}}

    plot_config = {
        "main_plot": {
            "skd_buy_marker":  {"type": "scatter", "plotly": _BUY_MARKER},
            "skd_sell_marker": {"type": "scatter", "plotly": _SELL_MARKER},

            "skd_buy_signal_line_0":  {"type": "scatter", "plotly": _BUY_LINE},
            "skd_buy_signal_line_1":  {"type": "scatter", "plotly": _BUY_LINE},
            "skd_buy_signal_line_2":  {"type": "scatter", "plotly": _BUY_LINE},
            "skd_buy_signal_line_3":  {"type": "scatter", "plotly": _BUY_LINE},

            "skd_sell_signal_line_0": {"type": "scatter", "plotly": _SELL_LINE},
            "skd_sell_signal_line_1": {"type": "scatter", "plotly": _SELL_LINE},
            "skd_sell_signal_line_2": {"type": "scatter", "plotly": _SELL_LINE},
            "skd_sell_signal_line_3": {"type": "scatter", "plotly": _SELL_LINE},
        }
    }

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        df = dataframe.copy().reset_index(drop=True)

        ind = EnhancedSkdIndicator(
            method=self.skd_method,
            vol_min=self.skd_vol_min,
            percentile_lookback=self.skd_percentile_lookback,
            percentile=self.skd_percentile,
            rvol_lookback=self.skd_rvol_lookback,
            rvol_threshold=self.skd_rvol_threshold,
            zscore_lookback=self.skd_zscore_lookback,
            zscore_threshold=self.skd_zscore_threshold,
            stoch_lookback=self.skd_stoch_lookback,
            stoch_threshold=self.skd_stoch_threshold,
            signal_lag_bars=self.skd_signal_lag_bars,
            min_distance_mode=self.skd_min_distance_mode,
            min_distance_pct=self.skd_min_distance_pct,
            atr_period=self.skd_atr_period,
            min_distance_atr_mult=self.skd_min_distance_atr_mult,
            filter_ttl_bars=self.skd_filter_ttl_bars,
        )
        df = ind.compute(df)

        vis = SkdLevelVisualizer(
            max_slots=self.skd_max_slots,
            level_ttl=self.skd_level_ttl,
            slot_cooldown_bars=self.skd_slot_cooldown_bars,
            expire_opposite_on_new=self.skd_expire_opposite_on_new,
            same_side_latest_only=self.skd_same_side_latest_only,
        )
        df = vis.render_levels(df)

        self.logger.info(
            f"[SKD] created={ind.stats.get('levels_created')} | "
            f"filtered={ind.stats.get('levels_filtered_distance')} | "
            f"total_skd={ind.stats.get('total_skd_found')}"
        )
        return df

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["enter_long"] = 0
        dataframe["enter_short"] = 0
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["exit_long"] = 0
        dataframe["exit_short"] = 0
        return dataframe
