Timeframe
1m
Direction
Long & Short
Stoploss
-2.0%
Trailing Stop
Yes
ROI
0m: 15.4%, 14m: 11.1%, 57m: 8.4%, 147m: 3.4%
Interface Version
3
Startup Candles
N/A
Indicators
4
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
import freqtrade.vendor.qtpylib.indicators as qtpylib
import numpy as np
import talib.abstract as ta
from freqtrade.strategy.interface import IStrategy
from freqtrade.strategy import merge_informative_pair
from pandas import DataFrame, Series
class Cluc7werk(IStrategy):
INTERFACE_VERSION = 3
can_short = True
# Buy hyperspace params:
buy_params = {
"bbdelta-close": 0.00732,
"bbdelta-tail": 0.94138,
"close-bblower": 0.0199,
"closedelta-close": 0.01825,
"fisher": -0.22987,
"volume": 16,
}
# Sell hyperspace params:
sell_params = {"sell-bbmiddle-close": 0.99184, "sell-fisher": 0.26832}
# Short entry hyperspace params (inverted long logic):
short_params = {
"short-fisher": 0.22987, # Overbought Fisher-RSI threshold (inverted from long)
"short-close-bbupper": 0.0199, # Distance above upper BB2
"short-bbdelta-close": 0.00732, # BB delta threshold
"short-closedelta-close": 0.01825,
"short-bbdelta-tail": 0.94138,
"short-volume": 16,
}
# Short exit hyperspace params:
short_exit_params = {
"exit-short-bbmiddle-close": 1.00816, # Inverted from sell-bbmiddle-close
"exit-short-fisher": -0.26832, # Inverted from sell-fisher
}
# ROI table:
minimal_roi = {"0": 0.15373, "14": 0.1105, "57": 0.08376, "147": 0.03427, "201": 0.01352, "366": 0.00667, "469": 0}
# Stoploss:
stoploss = -0.02
# Trailing stop:
trailing_stop = True
trailing_stop_positive = 0.01007
trailing_stop_positive_offset = 0.01258
trailing_only_offset_is_reached = False
timeframe = "1m"
startup_candle_count: int = 72
# Make sure these match or are not overridden in config
use_exit_signal = True
exit_profit_only = True
exit_profit_offset = 0.01
ignore_roi_if_entry_signal = True
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Set Up Bollinger Bands
upper_bb1, mid_bb1, lower_bb1 = ta.BBANDS(dataframe["close"], timeperiod=40)
upper_bb2, mid_bb2, lower_bb2 = ta.BBANDS(qtpylib.typical_price(dataframe), timeperiod=20)
dataframe["lower-bb1"] = lower_bb1
dataframe["upper-bb1"] = upper_bb1
dataframe["lower-bb2"] = lower_bb2
dataframe["upper-bb2"] = upper_bb2
dataframe["mid-bb2"] = mid_bb2
dataframe["bb1-delta"] = (mid_bb1 - dataframe["lower-bb1"]).abs()
dataframe["closedelta"] = (dataframe["close"] - dataframe["close"].shift()).abs()
dataframe["tail"] = (dataframe["close"] - dataframe["low"]).abs()
dataframe["upper-tail"] = (dataframe["high"] - dataframe["close"]).abs()
dataframe["ema_fast"] = ta.EMA(dataframe["close"], timeperiod=6)
dataframe["ema_slow"] = ta.EMA(dataframe["close"], timeperiod=48)
dataframe["volume_mean_slow"] = dataframe["volume"].rolling(window=24).mean()
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=9)
# # Inverse Fisher transform on RSI: values [-1.0, 1.0] (https://goo.gl/2JGGoy)
rsi = 0.1 * (dataframe["rsi"] - 50)
dataframe["fisher-rsi"] = (np.exp(2 * rsi) - 1) / (np.exp(2 * rsi) + 1)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
params = self.buy_params
short_params = self.short_params
# Long entries: oversold conditions (Fisher-RSI < threshold, price near lower BB)
dataframe.loc[
(dataframe["fisher-rsi"].lt(params["fisher"]))
& (
(
dataframe["bb1-delta"].gt(dataframe["close"] * params["bbdelta-close"])
& dataframe["closedelta"].gt(dataframe["close"] * params["closedelta-close"])
& dataframe["tail"].lt(dataframe["bb1-delta"] * params["bbdelta-tail"])
& dataframe["close"].lt(dataframe["lower-bb1"].shift())
& dataframe["close"].le(dataframe["close"].shift())
)
| (
(dataframe["close"] < dataframe["ema_slow"])
& (dataframe["close"] < params["close-bblower"] * dataframe["lower-bb2"])
& (dataframe["volume"] < (dataframe["volume_mean_slow"].shift(1) * params["volume"]))
)
),
"enter_long",
] = 1
# Short entries: overbought conditions (Fisher-RSI > threshold, price near upper BB)
dataframe.loc[
(dataframe["fisher-rsi"].gt(short_params["short-fisher"]))
& (
(
dataframe["bb1-delta"].gt(dataframe["close"] * short_params["short-bbdelta-close"])
& dataframe["closedelta"].gt(dataframe["close"] * short_params["short-closedelta-close"])
& dataframe["upper-tail"].lt(dataframe["bb1-delta"] * short_params["short-bbdelta-tail"])
& dataframe["close"].gt(dataframe["upper-bb1"].shift())
& dataframe["close"].ge(dataframe["close"].shift())
)
| (
(dataframe["close"] > dataframe["ema_slow"])
& (dataframe["close"] > (1 + short_params["short-close-bbupper"]) * dataframe["upper-bb2"])
& (dataframe["volume"] < (dataframe["volume_mean_slow"].shift(1) * short_params["short-volume"]))
)
),
"enter_short",
] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
params = self.sell_params
short_exit_params = self.short_exit_params
# Exit long: mean reversion above mid BB + overbought Fisher-RSI
dataframe.loc[
((dataframe["close"] * params["sell-bbmiddle-close"]) > dataframe["mid-bb2"])
& dataframe["ema_fast"].gt(dataframe["close"])
& dataframe["fisher-rsi"].gt(params["sell-fisher"])
& dataframe["volume"].gt(0),
"exit_long",
] = 1
# Exit short: mean reversion below mid BB + oversold Fisher-RSI
dataframe.loc[
((dataframe["close"] * short_exit_params["exit-short-bbmiddle-close"]) < dataframe["mid-bb2"])
& dataframe["ema_fast"].lt(dataframe["close"])
& dataframe["fisher-rsi"].lt(short_exit_params["exit-short-fisher"])
& dataframe["volume"].gt(0),
"exit_short",
] = 1
return dataframe