Timeframe
4h
Direction
Long Only
Stoploss
-12.0%
Trailing Stop
Yes
ROI
0m: 8.0%, 720m: 5.0%, 1440m: 3.0%, 2880m: 1.5%
Interface Version
3
Startup Candles
N/A
Indicators
7
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
"""
Conservative 4h dip-buyer for small accounts.
Thesis: in ranging / mildly bearish altcoin markets, buying deep RSI dips
on a 4h chart while the weekly trend is still up captures mean reversion
bounces with fewer fee-eating trades than low-TF momentum.
Uses position_adjustment to average down once if price drops another 6%,
which improves average entry without increasing per-trade risk beyond budget.
"""
from freqtrade.strategy import IStrategy
from pandas import DataFrame
import talib.abstract as ta
class DipBuyerStrategy(IStrategy):
INTERFACE_VERSION = 3
minimal_roi = {
"0": 0.08,
"720": 0.05,
"1440": 0.03,
"2880": 0.015,
}
stoploss = -0.12
trailing_stop = True
trailing_stop_positive = 0.025
trailing_stop_positive_offset = 0.05
trailing_only_offset_is_reached = True
timeframe = "4h"
process_only_new_candles = True
startup_candle_count: int = 200
position_adjustment_enable = True
max_entry_position_adjustment = 1
plot_config = {
"main_plot": {
"ema_50": {"color": "#f39c12"},
"ema_200": {"color": "#e74c3c"},
"bb_upper": {"color": "#3498db"},
"bb_middle": {"color": "#95a5a6"},
"bb_lower": {"color": "#3498db", "fill_to": "bb_upper", "fill_color": "rgba(52,152,219,0.08)"},
},
"subplots": {
"RSI": {
"rsi": {"color": "#9b59b6"},
"rsi_slow": {"color": "#8e44ad"},
},
"MACD": {
"macd": {"color": "#2ecc71"},
"macd_signal": {"color": "#e67e22"},
"macd_hist": {"color": "#7f8c8d", "type": "bar"},
},
"ADX": {
"adx": {"color": "#16a085"},
},
"ATR": {
"atr": {"color": "#c0392b"},
},
},
}
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
dataframe["rsi_slow"] = ta.RSI(dataframe, timeperiod=28)
dataframe["ema_50"] = ta.EMA(dataframe, timeperiod=50)
dataframe["ema_200"] = ta.EMA(dataframe, timeperiod=200)
bb = ta.BBANDS(dataframe, timeperiod=20, nbdevup=2.2, nbdevdn=2.2)
dataframe["bb_upper"] = bb["upperband"]
dataframe["bb_middle"] = bb["middleband"]
dataframe["bb_lower"] = bb["lowerband"]
macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
dataframe["macd"] = macd["macd"]
dataframe["macd_signal"] = macd["macdsignal"]
dataframe["macd_hist"] = macd["macdhist"]
dataframe["adx"] = ta.ADX(dataframe, timeperiod=14)
dataframe["atr"] = ta.ATR(dataframe, timeperiod=14)
dataframe["volume_sma"] = ta.SMA(dataframe["volume"], timeperiod=20)
dataframe["low_10"] = dataframe["low"].rolling(10).min()
dataframe["pct_from_low"] = (dataframe["close"] - dataframe["low_10"]) / dataframe["low_10"]
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(dataframe["rsi"] < 30) &
(dataframe["rsi_slow"] < 45) &
(dataframe["close"] < dataframe["bb_lower"]) &
(dataframe["close"] > dataframe["ema_200"] * 0.85) &
(dataframe["volume"] > dataframe["volume_sma"] * 0.6) &
(dataframe["volume"] > 0)
),
["enter_long", "enter_tag"]] = (1, "deep_dip")
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(dataframe["rsi"] > 70) &
(dataframe["close"] > dataframe["bb_middle"]) &
(dataframe["volume"] > 0)
),
["exit_long", "exit_tag"]] = (1, "rsi_overbought")
return dataframe
def adjust_trade_position(self, trade, current_time, current_rate,
current_profit, min_stake, max_stake,
current_entry_rate, current_exit_rate,
current_entry_profit, current_exit_profit, **kwargs):
if trade.nr_of_successful_entries >= 2:
return None
if current_profit > -0.06:
return None
filled_entries = trade.select_filled_orders(trade.entry_side)
if not filled_entries:
return None
try:
return filled_entries[0].stake_amount
except Exception:
return None