Research-only V44 diagnostic strategy.
Timeframe
5m
Direction
Long & Short
Stoploss
-2.0%
Trailing Stop
Yes
ROI
0m: 2.2%, 45m: 1.2%, 120m: 0.6%, 240m: 0.2%
Interface Version
3
Startup Candles
260
Indicators
4
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
# pragma pylint: disable=missing-docstring, invalid-name
# flake8: noqa: F401
from pandas import DataFrame
from freqtrade.strategy import IStrategy
import talib.abstract as ta
class AJ_SMC_FVG_OB_V44_SWEEP_BREAKDOWN_VARIANT_B(IStrategy):
"""
Research-only V44 diagnostic strategy.
Tests only the V44 Variant B timing model selected by the sweep/rejection
timing diagnostic. This is not recovered V41, not V42 tuning, not live, and
must not be used for dry-run without a separate adoption decision.
"""
INTERFACE_VERSION = 3
timeframe = "5m"
can_short = True
minimal_roi = {
"0": 0.022,
"45": 0.012,
"120": 0.006,
"240": 0.002,
}
stoploss = -0.020
trailing_stop = True
trailing_stop_positive = 0.006
trailing_stop_positive_offset = 0.014
trailing_only_offset_is_reached = True
process_only_new_candles = True
use_exit_signal = False
exit_profit_only = False
ignore_roi_if_entry_signal = False
startup_candle_count = 260
order_types = {
"entry": "limit",
"exit": "limit",
"stoploss": "market",
"stoploss_on_exchange": False,
}
order_time_in_force = {
"entry": "GTC",
"exit": "GTC",
}
protections = [
{
"method": "CooldownPeriod",
"stop_duration_candles": 4,
},
{
"method": "StoplossGuard",
"lookback_period_candles": 60,
"trade_limit": 2,
"stop_duration_candles": 24,
"only_per_pair": False,
},
]
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe["ema_21"] = ta.EMA(dataframe, timeperiod=21)
dataframe["ema_55"] = ta.EMA(dataframe, timeperiod=55)
dataframe["ema_200"] = ta.EMA(dataframe, timeperiod=200)
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
dataframe["adx"] = ta.ADX(dataframe, timeperiod=14)
dataframe["minus_di"] = ta.MINUS_DI(dataframe, timeperiod=14)
dataframe["plus_di"] = ta.PLUS_DI(dataframe, timeperiod=14)
dataframe["atr"] = ta.ATR(dataframe, timeperiod=14)
dataframe["volume_mean_30"] = dataframe["volume"].rolling(30).mean()
dataframe["candle_range"] = dataframe["high"] - dataframe["low"]
dataframe["body"] = (dataframe["close"] - dataframe["open"]).abs()
dataframe["upper_wick"] = dataframe["high"] - dataframe[["open", "close"]].max(axis=1)
dataframe["lower_wick"] = dataframe[["open", "close"]].min(axis=1) - dataframe["low"]
dataframe["close_position"] = (
(dataframe["close"] - dataframe["low"]) / dataframe["candle_range"].replace(0, None)
)
dataframe["prior_high_72"] = dataframe["high"].rolling(72).max().shift(1)
dataframe["prior_low_8"] = dataframe["low"].rolling(8).min().shift(1)
dataframe["liquidity_sweep"] = (
(dataframe["high"] > dataframe["prior_high_72"] * 1.001)
& (dataframe["close"] < dataframe["prior_high_72"])
& (dataframe["upper_wick"] > dataframe["body"] * 1.4)
& (dataframe["close_position"] <= 0.45)
)
dataframe["sweep_recent_3"] = (
dataframe["liquidity_sweep"].rolling(3).max().shift(1).fillna(0).astype(bool)
)
dataframe["breakdown_confirmation"] = (
(dataframe["close"] < dataframe["prior_low_8"])
& (dataframe["close"] < dataframe["ema_21"])
)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe["enter_short"] = 0
dataframe["enter_tag"] = None
short_entry = (
dataframe["sweep_recent_3"]
& dataframe["breakdown_confirmation"]
& (dataframe["volume"] > 0)
)
dataframe.loc[short_entry, "enter_short"] = 1
dataframe.loc[short_entry, "enter_tag"] = "V44_SWEEP_BREAKDOWN_B"
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe["exit_short"] = 0
return dataframe