💬 Forum

CombinedBinHAndClucHyperStrategy

remiotore/ccxt-freqtrade/strategies/CombinedBinHAndClucHyperStrategy_converted.py · ★3 · ⑂2 · first seen 2026-07-28 · repo updated 2026-01-11

Basics mode: spot timeframe: 5m interface version: 3
Settings stoploss: -0.05 has minimal roi startup candle count: 50 hyperopt hyperopt params: 5
Indicators Bollinger_Bands EMA talib
Concepts ml
Other ml scikit-optimize mergedeep
15 related strategies ( identical code, similar name)

Each tile is a different kind of check — from an instant code lint to full sandboxed backtests and forward tests on recent data. Not sure what a check actually proves? See the FAQ →

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import freqtrade.vendor.qtpylib.indicators as qtpylib
import numpy as np
import talib.abstract as ta
import logging
from pandas import DataFrame
from freqtrade.strategy import IStrategy, IntParameter, RealParameter
from typing import Dict, List
from skopt.space import Dimension
logger = logging.getLogger(__name__)

class CombinedBinHAndClucHyperStrategy(IStrategy):
    INTERFACE_VERSION = 3
    '\n    enhanced auto hyperoptable version based on\n    https://github.com/freqtrade/freqtrade-strategies/blob/master/user_data/strategies/berlinguyinca/CombinedBinHAndCluc.py\n\n    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n    !!! as of today (14.04.2021) you need the freqtrade/develop version to be able     !!!\n    !!! to run hyperopt/backtest with this new strategy format                         !!!\n    !!!                                                                                !!!\n    !!! please check https://github.com/freqtrade/freqtrade/pull/4596 for further      !!!\n    !!! information about the new auto-hyperoptable strategies!                        !!!\n    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n    Based on a backtesting:\n    - the best perfomance is reached with "max_open_trades" = 2 (in average for any market),\n      so it is better to increase "stake_amount" value rather then "max_open_trades" to get more profit\n    \n    - if the market is constantly green(like in JAN 2018) the best performance is reached with\n      "max_open_trades" = 2 and minimal_roi = 0.01\n    '
    minimal_roi = {'0': 0.01}
    stoploss = -0.05
    timeframe = '5m'
    startup_candle_count = 50
    buy_params = {'buy_bin_bbdelta_close': 0.008, 'buy_bin_closedelta_close': 0.0175, 'buy_bin_tail_bbdelta': 0.25, 'buy_cluc_close_bblowerband': 0.985, 'buy_cluc_volume': 20}
    sell_params = {}  # not used but defined for security reasons
    buy_bin_bbdelta_close = RealParameter(0.0, 0.02, default=0.008, space='buy', optimize=True, load=True)
    buy_bin_closedelta_close = RealParameter(0.0, 0.03, default=0.0175, space='buy', optimize=True, load=True)
    buy_bin_tail_bbdelta = RealParameter(0.0, 1.0, default=0.25, space='buy', optimize=True, load=True)
    buy_cluc_close_bblowerband = RealParameter(0.0, 1.5, default=1.5, space='buy', optimize=True, load=True)
    buy_cluc_volume = IntParameter(10, 40, default=20, space='buy', optimize=True, load=True)
    use_exit_signal = True
    exit_profit_only = True
    ignore_roi_if_entry_signal = False

    def __init__(self, config: dict) -> None:
        super().__init__(config)
        try:
            from mergedeep import merge
        except ImportError as error:
            logger.info('could not import mergedeep, please check if pip is installed: %s', error)
            logger.info('therefor we are not able to merge parameters from config')
        else:
            logger.info('mergedeep found, so attempting to find strategy parameters in config file')
            if self.config.get('strategy_parameters', {}).get(self.__class__.__name__, False):
                cfg_strategy_parameters = self.config.get('strategy_parameters', {}).get(self.__class__.__name__, False)
                logger.info('strategy_parameters from config: %s', repr(cfg_strategy_parameters))
                if cfg_strategy_parameters.get('buy_params', {}):
                    logger.info('merging buy_params from config: %s', cfg_strategy_parameters.get('buy_params'))
                    merge(self.buy_params, cfg_strategy_parameters.get('buy_params'))
                if cfg_strategy_parameters.get('sell_params', {}):
                    logger.info('merging sell_params from config: %s', cfg_strategy_parameters.get('sell_params'))
                    merge(self.sell_params, cfg_strategy_parameters.get('sell_params'))
            else:
                logger.info('no strategy_parameters found in config')
            logger.info('final buy_params: %s', repr(self.buy_params))
            logger.info('final sell_params: %s', repr(self.sell_params))

    @staticmethod
    def bollinger_bands(stock_price, window_size, num_of_std):
        rolling_mean = stock_price.rolling(window=window_size).mean()
        rolling_std = stock_price.rolling(window=window_size).std()
        lower_band = rolling_mean - rolling_std * num_of_std
        return (np.nan_to_num(rolling_mean), np.nan_to_num(lower_band))

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        mid, lower = self.bollinger_bands(dataframe['close'], window_size=40, num_of_std=2)
        dataframe['lower'] = lower
        dataframe['bbdelta'] = (mid - dataframe['lower']).abs()
        dataframe['closedelta'] = (dataframe['close'] - dataframe['close'].shift()).abs()
        dataframe['tail'] = (dataframe['close'] - dataframe['low']).abs()
        bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
        dataframe['bb_lowerband'] = bollinger['lower']
        dataframe['bb_middleband'] = bollinger['mid']
        dataframe['bb_upperband'] = bollinger['upper']
        dataframe['ema_slow'] = ta.EMA(dataframe, timeperiod=50)
        dataframe['volume_mean_slow'] = dataframe['volume'].rolling(window=30).mean()
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:  # strategy BinHV45
        # strategy ClucMay72018
        dataframe.loc[dataframe['lower'].shift().gt(0) & dataframe['bbdelta'].gt(dataframe['close'] * self.buy_bin_closedelta_close.value) & dataframe['closedelta'].gt(dataframe['close'] * self.buy_bin_closedelta_close.value) & dataframe['tail'].lt(dataframe['bbdelta'] * self.buy_bin_tail_bbdelta.value) & dataframe['close'].lt(dataframe['lower'].shift()) & dataframe['close'].le(dataframe['close'].shift()) | (dataframe['close'] < dataframe['ema_slow']) & (dataframe['close'] < self.buy_cluc_close_bblowerband.value * dataframe['bb_lowerband']) & (dataframe['volume'] < dataframe['volume_mean_slow'].shift(1) * self.buy_cluc_volume.value), 'enter_long'] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[dataframe['close'] > dataframe['bb_middleband'], 'exit_long'] = 1
        return dataframe

    class HyperOpt:

        @staticmethod
        def sell_indicator_space() -> List[Dimension]:
            return []