"""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 ZECVolumeFlow5M(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