# source: https://raw.githubusercontent.com/a1exander81/clawmimoto-backtests/de399a73a61446bed15fe3614b1f014252a14f2a/strategies/claw5m_sniper.py
"""
Github_a1exander81_clawmimoto_backtests__claw5m_sniper__20260430_031719 — Session mode (market open scalper)

Trades only during NY, Tokyo, and London opens (3 trades/day max).
5-minute timeframe. Isolated margin, 1-2% risk, 50-100% RRR.
"""

from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter
import talib.abstract as ta
import pandas as pd


class Github_a1exander81_clawmimoto_backtests__claw5m_sniper__20260430_031719(IStrategy):
    """
    Freqtrade strategy for 5M scalping with session filters.
    Compatible with Freqtrade backtesting & hyperopt.
    """

    # Strategy interface
    INTERFACE_VERSION = 3

    # Timeframe
    timeframe = "5m"
    can_short = False
    use_exit_signal = True
    stoploss = -0.30  # -30% max loss (hard stop)
    trailing_stop = True
    trailing_stop_positive = 0.50  # Start trailing when +50% achieved
    trailing_stop_positive_offset = 0.0
    trailing_only_offset_is_reached = True

    # Minimal ROI table
    minimal_roi = {
        "0": 1.00,      # 100% target (will trail)
    }

    # Order types
    order_types = {
        "entry": "market",
        "exit": "market",
        "stoploss": "market",
        "stoploss_on_exchange": True,
    }

    # Session filters — trade only during market opens
    # SGT times: NY 21:30, Tokyo 08:00 & 11:30, London 16:00
    # These are checked in populate_buy_trend()
    SESSION_ENABLED = True

    # Indicator parameters (optimized for 5M scalping)
    buy_rsi = IntParameter(25, 40, default=30, space="buy")
    sell_rsi = IntParameter(60, 80, default=70, space="sell")
    ema_short = IntParameter(5, 20, default=9, space="buy")
    ema_long = IntParameter(20, 50, default=21, space="buy")

    # Protection
    use_stop_protection = True
    stoploss_protection = DecimalParameter(-0.05, -0.01, default=-0.03, space="protection")

    def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        """Add technical indicators."""
        # EMAs
        dataframe["ema_short"] = ta.EMA(dataframe, timeperiod=self.ema_short.value)
        dataframe["ema_long"] = ta.EMA(dataframe, timeperiod=self.ema_long.value)

        # RSI
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)

        # Volume spike detection
        dataframe["volume_ma"] = ta.SMA(dataframe["volume"], timeperiod=20)
        dataframe["volume_ratio"] = dataframe["volume"] / dataframe["volume_ma"]

        # ATR for dynamic SL
        dataframe["atr"] = ta.ATR(dataframe, timeperiod=14)

        return dataframe

    def populate_buy_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        """Generate buy signals — session-filtered."""
        dataframe["buy"] = 0

        # Session filter (if enabled)
        if self.SESSION_ENABLED:
            # Convert timestamp to SGT (UTC+8)
            sgt_hour = (dataframe["date"].dt.hour + 8) % 24
            sgt_minute = dataframe["date"].dt.minute

            # NY open: 21:30 SGT (09:30 EST = 21:30 SGT)
            ny_open = ((sgt_hour == 21) & (sgt_minute >= 30)) | (sgt_hour == 22)
            # Tokyo open: 08:00–08:15 and 11:30–11:45
            tokyo_open = ((sgt_hour == 8) & (sgt_minute <= 15)) | ((sgt_hour == 11) & (sgt_minute >= 30) & (sgt_minute <= 45))
            # London open: 16:00–16:15
            london_open = (sgt_hour == 16) & (sgt_minute <= 15)

            session_cond = ny_open | tokyo_open | london_open
        else:
            session_cond = True

        # Trading logic
        buy_cond = (
            (dataframe["ema_short"] > dataframe["ema_long"]) &
            (dataframe["rsi"] < self.buy_rsi.value) &
            (dataframe["volume_ratio"] > 1.5) &  # Volume spike
            session_cond
        )

        dataframe.loc[buy_cond, "buy"] = 1
        return dataframe

    def populate_sell_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        """Generate sell signals."""
        dataframe["sell"] = 0

        sell_cond = (
            (dataframe["rsi"] > self.sell_rsi.value) |
            (dataframe["ema_short"] < dataframe["ema_long"])
        )

        dataframe.loc[sell_cond, "sell"] = 1
        return dataframe

    # Custom exit for trailing
    def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, current_rate: float, current_profit: float, **kwargs):
        """Dynamic stoploss: move to breakeven at +50%."""
        if current_profit >= 0.50:
            return -0.01  # 1% below entry (effectively breakeven + fees)
        return self.stoploss
