# source: https://raw.githubusercontent.com/ayhanarashtasin/MultiLiveBot/e479493782eebf48586320b7bbea8dc212724516/strategies/approved/ZECVolumeFlow5M.py
# directory_url: https://github.com/ayhanarashtasin/MultiLiveBot/blob/main/strategies/approved/
# User: ayhanarashtasin
# Repository: MultiLiveBot
# --------------------"""Frozen ZECUSDT cfg-4ad98627 5m order-flow strategy."""
from __future__ import annotations

import numpy as np
import pandas as pd
from freqtrade.strategy import IStrategy


def _sma(values: pd.Series, period: int) -> pd.Series:
    """Research-compatible SMA: partial windows before ``period`` bars."""
    return values.rolling(period, min_periods=1).mean()


class Github_ayhanarashtasin_MultiLiveBot__ZECVolumeFlow5M__20260920_073741(IStrategy):
    INTERFACE_VERSION = 3
    timeframe = "5m"
    can_short = False
    stoploss = -0.99
    minimal_roi = {"0": 100.0}
    process_only_new_candles = True
    use_exit_signal = False
    startup_candle_count = 1000
    trailing_stop = False

    atr_period = 21
    sl_multiplier = 6.9
    tp_r = 15.0
    break_even_r = 0.7
    break_even_offset = 0.0012
    max_hold = 864
    slots = 10
    leverage = 1

    def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        close = dataframe["close"].astype(float)
        high = dataframe["high"].astype(float)
        low = dataframe["low"].astype(float)
        volume = dataframe["volume"].astype(float)

        def values(name: str) -> pd.Series:
            return dataframe.get(name, pd.Series(0.0, index=dataframe.index)).astype(float)

        big_buy, big_sell = values("buy_big_quote"), values("sell_big_quote")
        whale_buy, whale_sell = values("buy_whale_quote"), values("sell_whale_quote")
        big_total, whale_total = big_buy + big_sell, whale_buy + whale_sell
        big_imb = pd.Series(
            np.divide(big_buy - big_sell, big_total, out=np.zeros(len(dataframe)), where=big_total > 0),
            index=dataframe.index,
        )
        whale_imb = pd.Series(
            np.divide(whale_buy - whale_sell, whale_total, out=np.zeros(len(dataframe)), where=whale_total > 0),
            index=dataframe.index,
        )

        whale_imb_sma = _sma(whale_imb, 48)
        prior_whale_sma = whale_imb_sma.shift(1).fillna(whale_imb_sma)
        big_imb_sma = _sma(big_imb, 24)
        volume_sma = _sma(volume, 96)
        tick_vol = 100.0 * values("abs_tick_move") / close
        tick_vol_sma = _sma(tick_vol, 12)

        ema50 = close.ewm(span=50, adjust=False).mean()
        ema200 = close.ewm(span=200, adjust=False).mean()
        prior_close = close.shift(1).fillna(close)
        prior_ema50 = ema50.shift(5).fillna(ema50.iloc[0])

        whale_cross = (whale_imb_sma > 0.15) & (prior_whale_sma <= 0.15)
        absorb_up = (big_imb_sma < -0.15) & (close > dataframe["open"]) & (close > prior_close)
        vol_spike_up = (volume > 3.0 * volume_sma) & (close > dataframe["open"])
        filters = (ema50 > ema200) & (tick_vol_sma < 16.2) & (ema50 > prior_ema50)

        previous_close = close.shift(1).fillna(close.iloc[0])
        true_range = pd.concat(
            [high - low, (high - previous_close).abs(), (low - previous_close).abs()], axis=1
        ).max(axis=1)

        dataframe["big_imb"] = big_imb
        dataframe["whale_imb"] = whale_imb
        dataframe["whale_imb_sma48"] = whale_imb_sma
        dataframe["big_imb_sma24"] = big_imb_sma
        dataframe["volume_sma96"] = volume_sma
        dataframe["tick_vol"] = tick_vol
        dataframe["tick_vol_sma12"] = tick_vol_sma
        dataframe["ema_fast"] = ema50
        dataframe["ema_slow"] = ema200
        dataframe["atr"] = true_range.ewm(alpha=1.0 / self.atr_period, adjust=False).mean()
        dataframe["trigger_whale_imb_cross"] = whale_cross
        dataframe["trigger_absorb_up"] = absorb_up
        dataframe["trigger_vol_spike_up"] = vol_spike_up
        dataframe["filters_pass"] = filters
        dataframe["entry_candidate"] = (whale_cross | absorb_up | vol_spike_up) & filters
        return dataframe

    def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        dataframe["enter_long"] = dataframe["entry_candidate"].astype(np.int8)
        return dataframe

    def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        # Independent slot exits are owned by the runtime's first-touch slot book.
        dataframe["exit_long"] = 0
        dataframe["exit_reason"] = ""
        dataframe["exit_price"] = np.nan
        return dataframe
