# source: https://raw.githubusercontent.com/Logashan/freqtrade-news-ml/ea2203157448cacf407f6ea6c1df2e17be5f11d5/strategies/NewsHeliusBitqueryML_NoProt.py
from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame
import pandas as pd
import ta

class Github_Logashan_freqtrade_news_ml__NewsHeliusBitqueryML_NoProt__20250814_154308(IStrategy):
    """
    Версия без защит для сравнения производительности:
    - Фильтр тренда: EMA50 > EMA200 (лонг), EMA50 < EMA200 (шорт)
    - Волатильность: ATR/close > порога
    - Временной фильтр: торги по UTC 6..22
    - Входы: пересечения RSI порогов + ADX + MACD
    - Выходы: RSI/EMA + ROI/SL из конфига
    - ЗАЩИТЫ ОТКЛЮЧЕНЫ для сравнения
    """
    timeframe = "5m"
    can_short = False
    process_only_new_candles = True
    startup_candle_count = 240
    minimal_roi = {"0": 0.01, "30": 0.005, "90": 0.0}
    stoploss = -0.02
    use_exit_signal = True
    trailing_stop = True
    trailing_stop_positive = 0.004
    trailing_stop_positive_offset = 0.009
    trailing_only_offset_is_reached = True
    ignore_buying_expired_candle_after = 1

    # --- простые индикаторы на pandas ---
    @staticmethod
    def _ema(series: pd.Series, length: int) -> pd.Series:
        return series.ewm(span=length, adjust=False).mean()

    @staticmethod
    def _rsi(series: pd.Series, length: int = 14) -> pd.Series:
        delta = series.diff()
        up = delta.clip(lower=0)
        down = (-delta.clip(upper=0))
        ma_up = up.ewm(alpha=1/length, adjust=False, min_periods=length).mean()
        ma_down = down.ewm(alpha=1/length, adjust=False, min_periods=length).mean()
        rs = ma_up / (ma_down.replace(0, 1e-9))
        return 100 - (100 / (1 + rs))

    @staticmethod
    def _atr(df: DataFrame, length: int = 14) -> pd.Series:
        high, low, close = df['high'], df['low'], df['close']
        tr = pd.concat([
            (high - low),
            (high - close.shift()).abs(),
            (low - close.shift()).abs()
        ], axis=1).max(axis=1)
        return tr.ewm(alpha=1/length, adjust=False, min_periods=length).mean()

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        df = dataframe.copy()
        
        # --- EMA, MACD ---
        ema_fast = df["close"].ewm(span=12, adjust=False).mean()
        ema_slow = df["close"].ewm(span=26, adjust=False).mean()
        df["macd"] = ema_fast - ema_slow
        df["macd_sig"] = df["macd"].ewm(span=9, adjust=False).mean()
        df["macd_hist"] = df["macd"] - df["macd_sig"]
        
        # Дополнительные EMA для анализа тренда
        df["ema50"] = df["close"].ewm(span=50, adjust=False).mean()
        df["ema200"] = df["close"].ewm(span=200, adjust=False).mean()
        
        # Сохраняем быстрые EMA для совместимости с существующим кодом
        df['ema_fast'] = df["ema50"]
        df['ema_slow'] = df["ema200"]

        # --- RSI(14) ---
        delta = df["close"].diff()
        gain = delta.clip(lower=0)
        loss = -delta.clip(upper=0)
        avg_gain = gain.ewm(alpha=1/14, min_periods=14, adjust=False).mean()
        avg_loss = loss.ewm(alpha=1/14, min_periods=14, adjust=False).mean()
        rs = avg_gain / (avg_loss + 1e-10)
        df["rsi"] = 100 - (100 / (1 + rs))

        # --- ATR(14) ---
        prev_close = df["close"].shift()
        tr = pd.concat([
            (df["high"] - df["low"]),
            (df["high"] - prev_close).abs(),
            (df["low"] - prev_close).abs()
        ], axis=1).max(axis=1)
        df["atr"] = tr.ewm(alpha=1/14, min_periods=14, adjust=False).mean()
        
        # ADX calculation (simplified)
        df['adx'] = df['atr'].rolling(window=14).mean()  # Simplified ADX
        
        # Volume fraction
        df['vol_frac'] = (df['atr'] / df['close']).fillna(0)
        
        # Временной фильтр
        hours = df['date'].dt.hour if 'date' in df.columns else df.index.tz_convert('UTC').hour
        df['tradable_hour'] = ((hours >= 6) & (hours <= 22)).astype(int)
        
        # Подчищаем и убеждаемся, что всё числовое
        for c in ["macd", "macd_sig", "macd_hist", "ema50", "ema200", "rsi", "atr", "ema_fast", "ema_slow"]:
            df[c] = pd.to_numeric(df[c], errors="coerce")

        df.ffill(inplace=True)
        df.bfill(inplace=True)
        return df

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        df = dataframe.copy()

        vol_min = 0.002     # ~0.2% средней 5m-волы (смягчено с 0.003)
        rsi_long_th = 45    # смягчено с 40
        rsi_short_th = 55   # смягчено с 60

        long_cond = (
            (df['ema_fast'] > df['ema_slow']) &
            (df['vol_frac'] > vol_min) &
            (df['macd'] > df['macd_sig']) &
            (df['adx'] >= 14) &  # смягчено с 18
            (df['rsi'].shift(1) < rsi_long_th) & (df['rsi'] >= rsi_long_th)
            # (df['tradable_hour'] == 1)  # временно закомментировано для 24/7 торговли
        )
        df['enter_long'] = long_cond.astype(int)
        return df

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        df = dataframe.copy()
        exit_long = ( (df['rsi'] > 70) | (df['close'] < df['ema_fast']) )
        df['exit_long'] = exit_long.astype(int)
        return df

    @property
    def protections(self):
        # Защиты отключены для сравнения производительности
        return []
