# source: https://raw.githubusercontent.com/wiktorj137/btc-strategy-lab/b68a5518b4a3eba2fde1733160d7d7de356023b5/user_data/strategies/EmaEnsemble.py
# directory_url: https://github.com/wiktorj137/btc-strategy-lab/blob/main/user_data/strategies/
# User: wiktorj137
# Repository: btc-strategy-lab
# --------------------"""Github_wiktorj137_btc_strategy_lab__EmaEnsemble__20260822_031820 - ta sama teza co EmaCross, ale bez wybierania dlugosci EMA.

PROBLEM, KTORY ROZWIAZUJE:
    Walk-forward pokazal, ze optymalna dlugosc EMA skacze miedzy 500 a 1200
    w zaleznosci od okna treningowego. Nie ma stabilnej "wlasciwej" wartosci.
    Kazde wybranie jednej z nich to krok selekcji, ktory trzeba potem odliczyc
    w Deflated Sharpe - i wlasnie na tym kroku strategia oblewala bramke.

ROZWIAZANIE:
    Nie wybieramy. Liczymy caly wachlarz EMA i patrzymy, jaka ICH CZESC cena
    przebila. Powyzej polowy - jestesmy w rynku, ponizej - w gotowce.

    Zero parametrow do dostrojenia:
      - zbior EMA jest ustalony z gory i rozlozony rownomiernie w zakresie,
        ktory walk-forward w ogole odwiedzil (400-1200h)
      - prog to 0.5, czyli wiekszosc; nie ma tu nic do optymalizowania

    Efekt uboczny, ktory jest wlasciwie celem: skoro nie ma czego wybierac,
    nie ma tez selekcji, ktora zawyzalaby wynik.
"""
from __future__ import annotations

import numpy as np
import talib.abstract as ta
from pandas import DataFrame

from freqtrade.strategy import IStrategy

EMA_SET = (400, 600, 800, 1000, 1200)


class Github_wiktorj137_btc_strategy_lab__EmaEnsemble__20260822_031820(IStrategy):
    INTERFACE_VERSION = 3

    timeframe = "1h"
    can_short = False
    process_only_new_candles = True
    startup_candle_count = 1300

    minimal_roi = {"0": 10}
    stoploss = -0.15
    trailing_stop = True

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        above = np.zeros(len(dataframe))
        for p in EMA_SET:
            ema = ta.EMA(dataframe, timeperiod=p)
            above += (dataframe["close"] > ema).astype(float).to_numpy()
        # udzial EMA, ktore cena ma pod soba: 0.0 = ponizej wszystkich, 1.0 = powyzej
        dataframe["ema_score"] = above / len(EMA_SET)
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        s = dataframe["ema_score"]
        dataframe.loc[
            (s > 0.5) & (s.shift(1) <= 0.5) & (dataframe["volume"] > 0),
            ["enter_long", "enter_tag"],
        ] = (1, "majority_above")
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        s = dataframe["ema_score"]
        dataframe.loc[
            (s < 0.5) & (s.shift(1) >= 0.5),
            ["exit_long", "exit_tag"],
        ] = (1, "majority_below")
        return dataframe
