Beispiel #1
0
def test_auto_hyperopt_interface(default_conf):
    default_conf.update({'strategy': 'HyperoptableStrategy'})
    PairLocks.timeframe = default_conf['timeframe']
    strategy = StrategyResolver.load_strategy(default_conf)

    with pytest.raises(OperationalException):
        next(strategy.enumerate_parameters('deadBeef'))

    assert strategy.buy_rsi.value == strategy.buy_params['buy_rsi']
    # PlusDI is NOT in the buy-params, so default should be used
    assert strategy.buy_plusdi.value == 0.5
    assert strategy.sell_rsi.value == strategy.sell_params['sell_rsi']

    assert repr(strategy.sell_rsi) == 'IntParameter(74)'

    # Parameter is disabled - so value from sell_param dict will NOT be used.
    assert strategy.sell_minusdi.value == 0.5
    all_params = strategy.detect_all_parameters()
    assert isinstance(all_params, dict)
    assert len(all_params['buy']) == 2
    assert len(all_params['sell']) == 2
    # Number of Hyperoptable parameters
    assert all_params['count'] == 6

    strategy.__class__.sell_rsi = IntParameter([0, 10], default=5, space='buy')

    with pytest.raises(OperationalException,
                       match=r"Inconclusive parameter.*"):
        [x for x in strategy.detect_parameters('sell')]
Beispiel #2
0
def test_hyperopt_parameters():
    from skopt.space import Categorical, Integer, Real
    with pytest.raises(OperationalException, match=r"Name is determined.*"):
        IntParameter(low=0, high=5, default=1, name='hello')

    with pytest.raises(OperationalException,
                       match=r"IntParameter space must be.*"):
        IntParameter(low=0, default=5, space='buy')

    with pytest.raises(OperationalException,
                       match=r"RealParameter space must be.*"):
        RealParameter(low=0, default=5, space='buy')

    with pytest.raises(OperationalException,
                       match=r"DecimalParameter space must be.*"):
        DecimalParameter(low=0, default=5, space='buy')

    with pytest.raises(OperationalException,
                       match=r"IntParameter space invalid\."):
        IntParameter([0, 10], high=7, default=5, space='buy')

    with pytest.raises(OperationalException,
                       match=r"RealParameter space invalid\."):
        RealParameter([0, 10], high=7, default=5, space='buy')

    with pytest.raises(OperationalException,
                       match=r"DecimalParameter space invalid\."):
        DecimalParameter([0, 10], high=7, default=5, space='buy')

    with pytest.raises(OperationalException,
                       match=r"CategoricalParameter space must.*"):
        CategoricalParameter(['aa'], default='aa', space='buy')

    with pytest.raises(TypeError):
        BaseParameter(opt_range=[0, 1], default=1, space='buy')

    intpar = IntParameter(low=0, high=5, default=1, space='buy')
    assert intpar.value == 1
    assert isinstance(intpar.get_space(''), Integer)

    fltpar = RealParameter(low=0.0, high=5.5, default=1.0, space='buy')
    assert isinstance(fltpar.get_space(''), Real)
    assert fltpar.value == 1

    fltpar = DecimalParameter(low=0.0,
                              high=5.5,
                              default=1.0004,
                              decimals=3,
                              space='buy')
    assert isinstance(fltpar.get_space(''), Integer)
    assert fltpar.value == 1
    fltpar._set_value(2222)
    assert fltpar.value == 2.222

    catpar = CategoricalParameter(['buy_rsi', 'buy_macd', 'buy_none'],
                                  default='buy_macd',
                                  space='buy')
    assert isinstance(catpar.get_space(''), Categorical)
    assert catpar.value == 'buy_macd'
Beispiel #3
0
def test_auto_hyperopt_interface(default_conf):
    default_conf.update({'strategy': 'HyperoptableStrategy'})
    PairLocks.timeframe = default_conf['timeframe']
    strategy = StrategyResolver.load_strategy(default_conf)

    assert strategy.buy_rsi.value == strategy.buy_params['buy_rsi']
    # PlusDI is NOT in the buy-params, so default should be used
    assert strategy.buy_plusdi.value == 0.5
    assert strategy.sell_rsi.value == strategy.sell_params['sell_rsi']

    # Parameter is disabled - so value from sell_param dict will NOT be used.
    assert strategy.sell_minusdi.value == 0.5

    strategy.sell_rsi = IntParameter([0, 10], default=5, space='buy')

    with pytest.raises(OperationalException, match=r"Inconclusive parameter.*"):
        [x for x in strategy.enumerate_parameters('sell')]
class MarketChyperHyperTestStrategy(IStrategy):

    # If enabled all Weighted Signal results will be added to the dataframe for easy debugging with BreakPoints
    # Warning: Disable this for anything else then debugging in an IDE! (Integrated Development Environment)
    debuggable_weighted_signal_dataframe = False

    # Ps: Documentation has been moved to the Buy/Sell HyperOpt Space Parameters sections below this copy-paste section
    ####################################################################################################################
    #                                    START OF HYPEROPT RESULTS COPY-PASTE SECTION                                  #
    ####################################################################################################################

    # Buy hyperspace params:
    buy_params = {
        'buy_downtrend_oslevel': -37,
        'buy_downtrend_rsi_div_value': 79,
        'buy_downtrend_rsi_divergence_weight': 50,
        'buy_downtrend_total_signal_needed': 70,
        'buy_downtrend_wavetrend_weight': 96,
        'buy_sideways_oslevel': -28,
        'buy_sideways_rsi_div_value': 45,
        'buy_sideways_rsi_divergence_weight': 35,
        'buy_sideways_total_signal_needed': 80,
        'buy_sideways_wavetrend_weight': 5,
        'buy_uptrend_oslevel': -43,
        'buy_uptrend_rsi_div_value': 93,
        'buy_uptrend_rsi_divergence_weight': 84,
        'buy_uptrend_total_signal_needed': 25,
        'buy_uptrend_wavetrend_weight': 91
    }

    # Sell hyperspace params:
    sell_params = {
        'sell_downtrend_oblevel': 75.67481,
        'sell_downtrend_rsi_divergence_weight': 90,
        'sell_downtrend_total_signal_needed': 51,
        'sell_downtrend_wavetrend_weight': 30,
        'sell_sideways_oblevel': 1.93351,
        'sell_sideways_rsi_divergence_weight': 59,
        'sell_sideways_total_signal_needed': 36,
        'sell_sideways_wavetrend_weight': 83,
        'sell_uptrend_oblevel': 37.98512,
        'sell_uptrend_rsi_divergence_weight': 99,
        'sell_uptrend_total_signal_needed': 93,
        'sell_uptrend_wavetrend_weight': 43
    }

    # ROI table:
    minimal_roi = {"0": 0.23733, "238": 0.20624, "846": 0.08939, "1834": 0}

    # Stoploss:
    stoploss = -0.12447

    # Trailing stop:
    trailing_stop = True
    trailing_stop_positive = 0.01658
    trailing_stop_positive_offset = 0.10224
    trailing_only_offset_is_reached = True

    ####################################################################################################################
    #                                     END OF HYPEROPT RESULTS COPY-PASTE SECTION                                   #
    ####################################################################################################################

    # Optimal timeframe for the strategy.
    timeframe = '30m'

    # Run "populate_indicators()" only for new candle.
    process_only_new_candles = False

    # These values can be overridden in the "ask_strategy" section in the config.
    use_sell_signal = True
    sell_profit_only = False
    ignore_roi_if_buy_signal = False

    # Number of candles the strategy requires before producing valid signals
    startup_candle_count: int = 400
    # SMA200 needs 200 candles before producing valid signals
    # EMA200 needs an extra 200 candles of SMA200 before producing valid signals

    # Optional order type mapping.
    order_types = {
        'buy': 'limit',
        'sell': 'limit',
        'stoploss': 'market',
        'stoploss_on_exchange': False
    }

    # Optional order time in force.
    order_time_in_force = {'buy': 'gtc', 'sell': 'gtc'}

    # Uptrend Trend Buy
    # -------------------
    # Total Buy Signal Percentage needed for a signal to be positive
    # im testing number of signals * 50 / 2
    buy___trades_when_downwards = \
        CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
    buy___trades_when_sideways = \
        CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
    buy___trades_when_upwards = \
        CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)

    buy_uptrend_total_signal_needed = IntParameter(0,
                                                   100,
                                                   default=65,
                                                   space='buy',
                                                   optimize=True,
                                                   load=True)
    #wave trend
    buy_uptrend_wavetrend_weight = \
        IntParameter(0, 100, default=0, space='buy', optimize=True, load=True)
    #rsi divs
    buy_uptrend_rsi_divergence_weight = \
        IntParameter(0, 100, default=0, space='buy', optimize=True, load=True)

    # buy_rsi_div_value (rsi used in condition of bullish div)
    buy_uptrend_rsi_div_value = \
        IntParameter(0, 100, default=0, space='buy', optimize=True, load=True)

    buy_uptrend_oslevel = \
        IntParameter(-100, 0, default=0, space='buy', optimize=True, load=True)

    # Sideways Trend Buy
    # -------------------
    buy_sideways_total_signal_needed = IntParameter(0,
                                                    100,
                                                    default=65,
                                                    space='buy',
                                                    optimize=True,
                                                    load=True)
    #wave trend
    buy_sideways_wavetrend_weight = \
        IntParameter(0, 100, default=0, space='buy', optimize=True, load=True)
    #rsi divs
    buy_sideways_rsi_divergence_weight = \
        IntParameter(0, 100, default=0, space='buy', optimize=True, load=True)

    # buy_rsi_div_value (rsi used in condition of bullish div)
    buy_sideways_rsi_div_value = \
        IntParameter(0, 100, default=0, space='buy', optimize=True, load=True)

    buy_sideways_oslevel = \
        IntParameter(-100, 0, default=0, space='buy', optimize=True, load=True)

    # Downtrend Trend Buy
    # -------------------
    buy_downtrend_total_signal_needed = IntParameter(0,
                                                     100,
                                                     default=65,
                                                     space='buy',
                                                     optimize=True,
                                                     load=True)
    #wave trend
    buy_downtrend_wavetrend_weight = \
        IntParameter(0, 100, default=0, space='buy', optimize=True, load=True)
    #rsi divs
    buy_downtrend_rsi_divergence_weight = \
        IntParameter(0, 100, default=0, space='buy', optimize=True, load=True)

    # buy_rsi_div_value (rsi used in condition of bullish div)
    buy_downtrend_rsi_div_value = \
        IntParameter(0, 100, default=0, space='buy', optimize=True, load=True)

    buy_downtrend_oslevel = \
        IntParameter(-100, 0, default=0, space='buy', optimize=True, load=True)

    #sell??
    sell___trades_when_downwards = \
        CategoricalParameter([True, False], default=True, space='sell', optimize=True, load=True)
    sell___trades_when_sideways = \
        CategoricalParameter([True, False], default=True, space='sell', optimize=True, load=True)
    sell___trades_when_upwards = \
        CategoricalParameter([True, False], default=True, space='sell', optimize=True, load=True)

    # Uptrend Trend Sell
    # --------------------

    # Total Sell Signal Percentage needed for a signal to be positive
    sell_uptrend_total_signal_needed = IntParameter(0,
                                                    100,
                                                    default=65,
                                                    space='sell',
                                                    optimize=True,
                                                    load=True)
    #wave trend
    sell_uptrend_wavetrend_weight = \
        IntParameter(0, 100, default=0, space='sell', optimize=True, load=True)
    #rsi divs
    sell_uptrend_rsi_divergence_weight = \
        IntParameter(0, 100, default=0, space='sell', optimize=True, load=True)

    sell_uptrend_oblevel = \
        RealParameter(0, 100, default=0, space='sell', optimize=True, load=True)

    # Sidewyas Trend Sell
    # --------------------

    # Total Sell Signal Percentage needed for a signal to be positive
    sell_sideways_total_signal_needed = IntParameter(0,
                                                     100,
                                                     default=65,
                                                     space='sell',
                                                     optimize=True,
                                                     load=True)
    #wave trend
    sell_sideways_wavetrend_weight = \
        IntParameter(0, 100, default=0, space='sell', optimize=True, load=True)
    #rsi divs
    sell_sideways_rsi_divergence_weight = \
        IntParameter(0, 100, default=0, space='sell', optimize=True, load=True)

    sell_sideways_oblevel = \
        RealParameter(0, 100, default=0, space='sell', optimize=True, load=True)

    # Downtrend Trend Sell
    # --------------------
    sell_downtrend_total_signal_needed = IntParameter(0,
                                                      100,
                                                      default=65,
                                                      space='sell',
                                                      optimize=True,
                                                      load=True)
    #wave trend
    sell_downtrend_wavetrend_weight = \
        IntParameter(0, 100, default=0, space='sell', optimize=True, load=True)
    #rsi divs
    sell_downtrend_rsi_divergence_weight = \
        IntParameter(0, 100, default=0, space='sell', optimize=True, load=True)

    sell_downtrend_oblevel = \
        RealParameter(0, 100, default=0, space='sell', optimize=True, load=True)

    # ---------------------------------------------------------------- #
    #                 Custom HyperOpt Space Parameters                 #
    # ---------------------------------------------------------------- #

    # class HyperOpt:
    #     # Define a custom stoploss space.
    #     @staticmethod
    #     def stoploss_space():
    #         return [Real(-0.01, -0.35, name='stoploss')]

    def informative_pairs(self):
        """
        Define additional, informative pair/interval combinations to be cached from the exchange.
        These pair/interval combinations are non-tradeable, unless they are part
        of the whitelist as well.
        For more information, please consult the documentation
        :return: List of tuples in the format (pair, interval)
            Sample: return [("ETH/USDT", "5m"),
                            ("BTC/USDT", "15m"),
                            ]
        """
        return []

    def populate_indicators(self, dataframe: DataFrame,
                            metadata: dict) -> DataFrame:
        """
        Adds several different TA indicators to the given DataFrame

        Performance Note: For the best performance be frugal on the number of indicators
        you are using. Let uncomment only the indicator you are using in your strategies
        or your hyperopt configuration, otherwise you will waste your memory and CPU usage.
        :param dataframe: Dataframe with data from the exchange
        :param metadata: Additional information, like the currently traded pair
        :return: a Dataframe with all mandatory indicators for the strategies
        """

        # Momentum Indicators (timeperiod is expressed in candles)
        # -------------------

        # ADX - Average Directional Index (The Trend Strength Indicator)
        dataframe['adx'] = ta.ADX(
            dataframe, timeperiod=14)  # 14 timeperiods is usually used for ADX

        # +DM (Positive Directional Indicator) = current high - previous high
        dataframe['plus_di'] = ta.PLUS_DI(dataframe, timeperiod=25)
        # -DM (Negative Directional Indicator) = previous low - current low
        dataframe['minus_di'] = ta.MINUS_DI(dataframe, timeperiod=25)

        # RSI - Relative Strength Index (Under bought / Over sold & Over bought / Under sold indicator Indicator)
        dataframe['rsi'] = ta.RSI(dataframe)

        # MACD - Moving Average Convergence Divergence
        macd = ta.MACD(dataframe)
        dataframe['macd'] = macd[
            'macd']  # MACD - Blue TradingView Line (Bullish if on top)
        dataframe['macdsignal'] = macd[
            'macdsignal']  # Signal - Orange TradingView Line (Bearish if on top)

        # Initialize total signal variables (should be 0 = false by default)
        dataframe['total_buy_signal_strength'] = dataframe[
            'total_sell_signal_strength'] = 0

        #divergences
        dataframe = self.divergences(dataframe)

        #get trend
        dataframe.loc[(dataframe['adx'] > 20) &
                      (dataframe['plus_di'] < dataframe['minus_di']),
                      'trend'] = 'downwards'
        dataframe.loc[dataframe['adx'] < 20, 'trend'] = 'sideways'
        dataframe.loc[(dataframe['adx'] > 20) &
                      (dataframe['plus_di'] > dataframe['minus_di']),
                      'trend'] = 'upwards'

        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame,
                           metadata: dict) -> DataFrame:
        """
        Based on TA indicators, populates the buy signal for the given dataframe
        :param dataframe: DataFrame populated with indicators
        :param metadata: Additional information, like the currently traded pair
        :return: DataFrame with buy column
        """
        dataframe = self.market_cipher(dataframe)

        #CALCULATE WT OVERSOLD
        dataframe.loc[(dataframe['trend'] == 'downwards'),
                      'wtOversold'] = (dataframe['wt2'] <=
                                       self.buy_downtrend_oslevel.value)
        dataframe.loc[(dataframe['trend'] == 'sideways'),
                      'wtOversold'] = (dataframe['wt2'] <=
                                       self.buy_sideways_oslevel.value)
        dataframe.loc[(dataframe['trend'] == 'upwards'),
                      'wtOversold'] = (dataframe['wt2'] <=
                                       self.buy_uptrend_oslevel.value)

        #SUM
        dataframe.loc[
            (dataframe['trend'] == 'downwards') &
            (dataframe['wtCrossUp'] & dataframe['wtOversold']),
            'buy_wavetrend_weight'] = self.buy_downtrend_wavetrend_weight.value
        dataframe.loc[
            (dataframe['trend'] == 'sideways') &
            (dataframe['wtCrossUp'] & dataframe['wtOversold']),
            'buy_wavetrend_weight'] = self.buy_sideways_wavetrend_weight.value
        dataframe.loc[
            (dataframe['trend'] == 'upwards') &
            (dataframe['wtCrossUp'] & dataframe['wtOversold']),
            'buy_wavetrend_weight'] = self.buy_uptrend_wavetrend_weight.value

        dataframe['total_buy_signal_strength'] += dataframe[
            'buy_wavetrend_weight']

        #rsi div and rsi vañur buy_rsi_div buy_rsi_div_weight
        dataframe.loc[(dataframe['trend'] == 'downwards') & (
            dataframe['bullish_div'] &
            (dataframe['rsi'] <= self.buy_downtrend_rsi_div_value.value)
        ), 'buy_rsi_divergence_weight'] = self.buy_downtrend_rsi_divergence_weight.value
        dataframe.loc[(dataframe['trend'] == 'sideways') & (
            dataframe['bullish_div'] &
            (dataframe['rsi'] <= self.buy_sideways_rsi_div_value.value)
        ), 'buy_rsi_divergence_weight'] = self.buy_sideways_rsi_divergence_weight.value
        dataframe.loc[(dataframe['trend'] == 'upwards') & (
            dataframe['bullish_div'] &
            (dataframe['rsi'] <= self.buy_uptrend_rsi_div_value.value)
        ), 'buy_rsi_divergence_weight'] = self.buy_uptrend_rsi_divergence_weight.value

        dataframe['total_buy_signal_strength'] += dataframe[
            'buy_rsi_divergence_weight']

        # Check if buy signal should be sent depending on the current trend
        # Check if buy signal should be sent depending on the current trend
        dataframe.loc[((dataframe['trend'] == 'downwards') &
                       (dataframe['total_buy_signal_strength'] >= self.
                        buy_downtrend_total_signal_needed.value)) |
                      ((dataframe['trend'] == 'sideways') &
                       (dataframe['total_buy_signal_strength'] >= self.
                        buy_sideways_total_signal_needed.value)) |
                      ((dataframe['trend'] == 'upwards') &
                       (dataframe['total_buy_signal_strength'] >= self.
                        buy_uptrend_total_signal_needed.value)), 'buy'] = 1

        # Override Buy Signal: When configured buy signals can be completely turned off for each kind of trend
        if not self.buy___trades_when_downwards.value:
            dataframe.loc[dataframe['trend'] == 'downwards', 'buy'] = 0
        if not self.buy___trades_when_sideways.value:
            dataframe.loc[dataframe['trend'] == 'sideways', 'buy'] = 0
        if not self.buy___trades_when_upwards.value:
            dataframe.loc[dataframe['trend'] == 'upwards', 'buy'] = 0

        return dataframe

        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame,
                            metadata: dict) -> DataFrame:
        dataframe = self.market_cipher(dataframe)

        #CALCULATE WT OVERSOLD
        dataframe.loc[(dataframe['trend'] == 'downwards'),
                      'wtOverbought'] = (dataframe['wt2'] >=
                                         self.sell_downtrend_oblevel.value)
        dataframe.loc[(dataframe['trend'] == 'sideways'),
                      'wtOverbought'] = (dataframe['wt2'] >=
                                         self.sell_sideways_oblevel.value)
        dataframe.loc[(dataframe['trend'] == 'upwards'),
                      'wtOverbought'] = (dataframe['wt2'] >=
                                         self.sell_uptrend_oblevel.value)

        #SUM
        dataframe.loc[(dataframe['trend'] == 'downwards') & (
            dataframe['wtCrossDown'] & dataframe['wtOverbought']
        ), 'sell_wavetrend_weight'] = self.sell_downtrend_wavetrend_weight.value
        dataframe.loc[(dataframe['trend'] == 'sideways') & (
            dataframe['wtCrossDown'] & dataframe['wtOverbought']
        ), 'sell_wavetrend_weight'] = self.sell_sideways_wavetrend_weight.value
        dataframe.loc[
            (dataframe['trend'] == 'upwards') &
            (dataframe['wtCrossDown'] & dataframe['wtOverbought']),
            'sell_wavetrend_weight'] = self.sell_uptrend_wavetrend_weight.value

        dataframe['total_sell_signal_strength'] += dataframe[
            'sell_wavetrend_weight']

        #rsi div and rsi vañur buy_rsi_div buy_rsi_div_weight
        dataframe.loc[(dataframe['trend'] == 'downwards') & (
            dataframe['bearish_div']
        ), 'sell_rsi_divergence_weight'] = self.sell_downtrend_rsi_divergence_weight.value
        dataframe.loc[(dataframe['trend'] == 'sideways') & (
            dataframe['bearish_div']
        ), 'sell_rsi_divergence_weight'] = self.sell_sideways_rsi_divergence_weight.value
        dataframe.loc[(dataframe['trend'] == 'upwards') & (
            dataframe['bearish_div']
        ), 'sell_rsi_divergence_weight'] = self.sell_uptrend_rsi_divergence_weight.value

        dataframe['total_sell_signal_strength'] += dataframe[
            'sell_rsi_divergence_weight']

        # Check if buy signal should be sent depending on the current trend
        # Check if buy signal should be sent depending on the current trend
        dataframe.loc[((dataframe['trend'] == 'downwards') &
                       (dataframe['total_sell_signal_strength'] >= self.
                        sell_downtrend_total_signal_needed.value)) |
                      ((dataframe['trend'] == 'sideways') &
                       (dataframe['total_sell_signal_strength'] >= self.
                        sell_sideways_total_signal_needed.value)) |
                      ((dataframe['trend'] == 'upwards') &
                       (dataframe['total_sell_signal_strength'] >= self.
                        sell_uptrend_total_signal_needed.value)), 'sell'] = 1

        return dataframe

    #wavetrend, market cypher
    def market_cipher(self, dataframe) -> DataFrame:
        self.n1 = 10  #WT Channel Length
        self.n2 = 21  #WT Average Length

        dataframe['ap'] = (dataframe['high'] + dataframe['low'] +
                           dataframe['close']) / 3
        dataframe['esa'] = ta.EMA(dataframe['ap'], self.n1)
        dataframe['d'] = ta.EMA((dataframe['ap'] - dataframe['esa']).abs(),
                                self.n1)
        dataframe['ci'] = (dataframe['ap'] -
                           dataframe['esa']) / (0.015 * dataframe['d'])
        dataframe['tci'] = ta.EMA(dataframe['ci'], self.n2)

        dataframe['wt1'] = dataframe['tci']
        dataframe['wt2'] = ta.SMA(dataframe['wt1'], 4)

        dataframe['wtVwap'] = dataframe['wt1'] - dataframe['wt2']

        dataframe['wtCrossUp'] = dataframe['wt2'] - dataframe['wt1'] <= 0
        dataframe['wtCrossDown'] = dataframe['wt2'] - dataframe['wt1'] >= 0
        dataframe['crossed_above'] = qtpylib.crossed_above(
            dataframe['wt2'], dataframe['wt1'])
        dataframe['crossed_below'] = qtpylib.crossed_below(
            dataframe['wt2'], dataframe['wt1'])

        return dataframe

    #rsi divergences  dataframe['bullish_div'] dataframe['bearish_div']
    def divergences(self, dataframe) -> DataFrame:
        dataframe['bullish_div'] = (
            (dataframe['close'].shift(4) > dataframe['close'].shift(2)) &
            (dataframe['close'].shift(3) > dataframe['close'].shift(2)) &
            (dataframe['close'].shift(2) < dataframe['close'].shift(1)) &
            (dataframe['close'].shift(2) < dataframe['close']))

        dataframe['bearish_div'] = (
            (dataframe['close'].shift(4) < dataframe['close'].shift(2)) &
            (dataframe['close'].shift(3) < dataframe['close'].shift(2)) &
            (dataframe['close'].shift(2) > dataframe['close'].shift(1)) &
            (dataframe['close'].shift(2) > dataframe['close']))

        return dataframe
Beispiel #5
0
def test_hyperopt_parameters():
    from skopt.space import Categorical, Integer, Real
    with pytest.raises(OperationalException, match=r"Name is determined.*"):
        IntParameter(low=0, high=5, default=1, name='hello')

    with pytest.raises(OperationalException,
                       match=r"IntParameter space must be.*"):
        IntParameter(low=0, default=5, space='buy')

    with pytest.raises(OperationalException,
                       match=r"RealParameter space must be.*"):
        RealParameter(low=0, default=5, space='buy')

    with pytest.raises(OperationalException,
                       match=r"DecimalParameter space must be.*"):
        DecimalParameter(low=0, default=5, space='buy')

    with pytest.raises(OperationalException,
                       match=r"IntParameter space invalid\."):
        IntParameter([0, 10], high=7, default=5, space='buy')

    with pytest.raises(OperationalException,
                       match=r"RealParameter space invalid\."):
        RealParameter([0, 10], high=7, default=5, space='buy')

    with pytest.raises(OperationalException,
                       match=r"DecimalParameter space invalid\."):
        DecimalParameter([0, 10], high=7, default=5, space='buy')

    with pytest.raises(OperationalException,
                       match=r"CategoricalParameter space must.*"):
        CategoricalParameter(['aa'], default='aa', space='buy')

    with pytest.raises(TypeError):
        BaseParameter(opt_range=[0, 1], default=1, space='buy')

    intpar = IntParameter(low=0, high=5, default=1, space='buy')
    assert intpar.value == 1
    assert isinstance(intpar.get_space(''), Integer)
    assert isinstance(intpar.range, range)
    assert len(list(intpar.range)) == 1
    # Range contains ONLY the default / value.
    assert list(intpar.range) == [intpar.value]
    intpar.in_space = True

    assert len(list(intpar.range)) == 6
    assert list(intpar.range) == [0, 1, 2, 3, 4, 5]

    fltpar = RealParameter(low=0.0, high=5.5, default=1.0, space='buy')
    assert isinstance(fltpar.get_space(''), Real)
    assert fltpar.value == 1

    fltpar = DecimalParameter(low=0.0,
                              high=5.5,
                              default=1.0004,
                              decimals=3,
                              space='buy')
    assert isinstance(fltpar.get_space(''), Integer)
    assert fltpar.value == 1

    catpar = CategoricalParameter(['buy_rsi', 'buy_macd', 'buy_none'],
                                  default='buy_macd',
                                  space='buy')
    assert isinstance(catpar.get_space(''), Categorical)
    assert catpar.value == 'buy_macd'
Beispiel #6
0
class mabStra(IStrategy):

    # #################### RESULTS PASTE PLACE ####################
    # ROI table:
    minimal_roi = {"0": 0.598, "644": 0.166, "3269": 0.115, "7289": 0}

    # Stoploss:
    stoploss = -0.128
    # Buy hypers
    timeframe = '4h'

    # #################### END OF RESULT PLACE ####################

    # buy params
    buy_mojo_ma_timeframe = IntParameter(2, 100, default=7, space='buy')
    buy_fast_ma_timeframe = IntParameter(2, 100, default=14, space='buy')
    buy_slow_ma_timeframe = IntParameter(2, 100, default=28, space='buy')
    buy_div_max = DecimalParameter(0,
                                   2,
                                   decimals=4,
                                   default=2.25446,
                                   space='buy')
    buy_div_min = DecimalParameter(0,
                                   2,
                                   decimals=4,
                                   default=0.29497,
                                   space='buy')
    # sell params
    sell_mojo_ma_timeframe = IntParameter(2, 100, default=7, space='sell')
    sell_fast_ma_timeframe = IntParameter(2, 100, default=14, space='sell')
    sell_slow_ma_timeframe = IntParameter(2, 100, default=28, space='sell')
    sell_div_max = DecimalParameter(0,
                                    2,
                                    decimals=4,
                                    default=1.54593,
                                    space='sell')
    sell_div_min = DecimalParameter(0,
                                    2,
                                    decimals=4,
                                    default=2.81436,
                                    space='sell')

    def populate_indicators(self, dataframe: DataFrame,
                            metadata: dict) -> DataFrame:
        # SMA - ex Moving Average
        dataframe['buy-mojoMA'] = ta.SMA(
            dataframe, timeperiod=self.buy_mojo_ma_timeframe.value)
        dataframe['buy-fastMA'] = ta.SMA(
            dataframe, timeperiod=self.buy_fast_ma_timeframe.value)
        dataframe['buy-slowMA'] = ta.SMA(
            dataframe, timeperiod=self.buy_slow_ma_timeframe.value)
        dataframe['sell-mojoMA'] = ta.SMA(
            dataframe, timeperiod=self.sell_mojo_ma_timeframe.value)
        dataframe['sell-fastMA'] = ta.SMA(
            dataframe, timeperiod=self.sell_fast_ma_timeframe.value)
        dataframe['sell-slowMA'] = ta.SMA(
            dataframe, timeperiod=self.sell_slow_ma_timeframe.value)
        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame,
                           metadata: dict) -> DataFrame:

        dataframe.loc[(
            (dataframe['buy-mojoMA'].div(dataframe['buy-fastMA']) > self.
             buy_div_min.value) &
            (dataframe['buy-mojoMA'].div(dataframe['buy-fastMA']) < self.
             buy_div_max.value) &
            (dataframe['buy-fastMA'].div(dataframe['buy-slowMA']) > self.
             buy_div_min.value) &
            (dataframe['buy-fastMA'].div(dataframe['buy-slowMA']) < self.
             buy_div_max.value)), 'buy'] = 1

        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame,
                            metadata: dict) -> DataFrame:
        dataframe.loc[(
            (dataframe['sell-fastMA'].div(dataframe['sell-mojoMA']) > self.
             sell_div_min.value) &
            (dataframe['sell-fastMA'].div(dataframe['sell-mojoMA']) < self.
             sell_div_max.value) &
            (dataframe['sell-slowMA'].div(dataframe['sell-fastMA']) > self.
             sell_div_min.value) &
            (dataframe['sell-slowMA'].div(dataframe['sell-fastMA']) < self.
             sell_div_max.value)), 'sell'] = 1
        return dataframe
Beispiel #7
0
class Heracles(IStrategy):
    ########################################## RESULT PASTE PLACE ##########################################
    # 10/100:     25 trades. 18/4/3 Wins/Draws/Losses. Avg profit   5.92%. Median profit   6.33%. Total profit  0.04888306 BTC (  48.88Σ%). Avg duration 4 days, 6:24:00 min. Objective: -11.42103

    # Buy hyperspace params:
    buy_params = {
        "buy_crossed_indicator_shift": 9,
        "buy_div_max": 0.75,
        "buy_div_min": 0.16,
        "buy_indicator_shift": 15,
    }

    # Sell hyperspace params:
    sell_params = {}

    # ROI table:
    minimal_roi = {"0": 0.598, "644": 0.166, "3269": 0.115, "7289": 0}

    # Stoploss:
    stoploss = -0.256

    # Optimal timeframe use it in your config
    timeframe = '4h'

    ########################################## END RESULT PASTE PLACE ######################################

    # buy params
    buy_div_min = DecimalParameter(0, 1, default=0.16, decimals=2, space='buy')
    buy_div_max = DecimalParameter(0, 1, default=0.75, decimals=2, space='buy')
    buy_indicator_shift = IntParameter(0, 20, default=16, space='buy')
    buy_crossed_indicator_shift = IntParameter(0, 20, default=9, space='buy')

    def populate_indicators(self, dataframe: DataFrame,
                            metadata: dict) -> DataFrame:
        dataframe = dropna(dataframe)

        dataframe['volatility_kcw'] = ta.volatility.keltner_channel_wband(
            dataframe['high'],
            dataframe['low'],
            dataframe['close'],
            window=20,
            window_atr=10,
            fillna=False,
            original_version=True)

        dataframe['volatility_dcp'] = ta.volatility.donchian_channel_pband(
            dataframe['high'],
            dataframe['low'],
            dataframe['close'],
            window=10,
            offset=0,
            fillna=False)

        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame,
                           metadata: dict) -> DataFrame:
        """
        Buy strategy Hyperopt will build and use.
        """
        conditions = []

        IND = 'volatility_dcp'
        CRS = 'volatility_kcw'
        DFIND = dataframe[IND]
        DFCRS = dataframe[CRS]

        d = DFIND.shift(self.buy_indicator_shift.value).div(
            DFCRS.shift(self.buy_crossed_indicator_shift.value))

        # print(d.min(), "\t", d.max())
        conditions.append(
            d.between(self.buy_div_min.value, self.buy_div_max.value))

        if conditions:
            dataframe.loc[reduce(lambda x, y: x & y, conditions), 'buy'] = 1

        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame,
                            metadata: dict) -> DataFrame:
        """
        Sell strategy Hyperopt will build and use.
        """
        dataframe.loc[:, 'sell'] = 0
        return dataframe
class Supertrend(IStrategy):
    # Buy params, Sell params, ROI, Stoploss and Trailing Stop are values generated by 'freqtrade hyperopt --strategy Supertrend --hyperopt-loss ShortTradeDurHyperOptLoss --timerange=20210101- --timeframe=1h --spaces all'
    # It's encourage you find the values that better suites your needs and risk management strategies

    # Buy hyperspace params:
    buy_params = {
        "buy_m1": 4,
        "buy_m2": 7,
        "buy_m3": 1,
        "buy_p1": 8,
        "buy_p2": 9,
        "buy_p3": 8,
    }

    # Sell hyperspace params:
    sell_params = {
        "sell_m1": 1,
        "sell_m2": 3,
        "sell_m3": 6,
        "sell_p1": 16,
        "sell_p2": 18,
        "sell_p3": 18,
    }

    # ROI table:
    minimal_roi = {"0": 0.087, "372": 0.058, "861": 0.029, "2221": 0}

    # Stoploss:
    stoploss = -0.265

    # Trailing stop:
    trailing_stop = True
    trailing_stop_positive = 0.05
    trailing_stop_positive_offset = 0.144
    trailing_only_offset_is_reached = False

    timeframe = '1h'

    startup_candle_count = 18

    buy_m1 = IntParameter(1, 7, default=4)
    buy_m2 = IntParameter(1, 7, default=4)
    buy_m3 = IntParameter(1, 7, default=4)
    buy_p1 = IntParameter(7, 21, default=14)
    buy_p2 = IntParameter(7, 21, default=14)
    buy_p3 = IntParameter(7, 21, default=14)

    sell_m1 = IntParameter(1, 7, default=4)
    sell_m2 = IntParameter(1, 7, default=4)
    sell_m3 = IntParameter(1, 7, default=4)
    sell_p1 = IntParameter(7, 21, default=14)
    sell_p2 = IntParameter(7, 21, default=14)
    sell_p3 = IntParameter(7, 21, default=14)

    def populate_indicators(self, dataframe: DataFrame,
                            metadata: dict) -> DataFrame:
        for multiplier in self.buy_m1.range:
            for period in self.buy_p1.range:
                dataframe[
                    f'supertrend_1_buy_{multiplier}_{period}'] = self.supertrend(
                        dataframe, multiplier, period)['STX']

        for multiplier in self.buy_m2.range:
            for period in self.buy_p2.range:
                dataframe[
                    f'supertrend_2_buy_{multiplier}_{period}'] = self.supertrend(
                        dataframe, multiplier, period)['STX']

        for multiplier in self.buy_m3.range:
            for period in self.buy_p3.range:
                dataframe[
                    f'supertrend_3_buy_{multiplier}_{period}'] = self.supertrend(
                        dataframe, multiplier, period)['STX']

        for multiplier in self.sell_m1.range:
            for period in self.sell_p1.range:
                dataframe[
                    f'supertrend_1_sell_{multiplier}_{period}'] = self.supertrend(
                        dataframe, multiplier, period)['STX']

        for multiplier in self.sell_m2.range:
            for period in self.sell_p2.range:
                dataframe[
                    f'supertrend_2_sell_{multiplier}_{period}'] = self.supertrend(
                        dataframe, multiplier, period)['STX']

        for multiplier in self.sell_m3.range:
            for period in self.sell_p3.range:
                dataframe[
                    f'supertrend_3_sell_{multiplier}_{period}'] = self.supertrend(
                        dataframe, multiplier, period)['STX']

        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame,
                           metadata: dict) -> DataFrame:
        dataframe.loc[(
            (dataframe[
                f'supertrend_1_buy_{self.buy_m1.value}_{self.buy_p1.value}'] ==
             'up') &
            (dataframe[
                f'supertrend_2_buy_{self.buy_m2.value}_{self.buy_p2.value}'] ==
             'up') &
            (dataframe[
                f'supertrend_3_buy_{self.buy_m3.value}_{self.buy_p3.value}'] ==
             'up') &  # The three indicators are 'up' for the current candle
            (dataframe['volume'] > 0)  # There is at least some trading volume
        ), 'buy'] = 1

        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame,
                            metadata: dict) -> DataFrame:
        dataframe.loc[(
            (dataframe[
                f'supertrend_1_sell_{self.sell_m1.value}_{self.sell_p1.value}']
             == 'down') &
            (dataframe[
                f'supertrend_2_sell_{self.sell_m2.value}_{self.sell_p2.value}']
             == 'down') &
            (dataframe[
                f'supertrend_3_sell_{self.sell_m3.value}_{self.sell_p3.value}']
             == 'down')
            &  # The three indicators are 'down' for the current candle
            (dataframe['volume'] > 0)  # There is at least some trading volume
        ), 'sell'] = 1

        return dataframe

    """
        Supertrend Indicator; adapted for freqtrade
        from: https://github.com/freqtrade/freqtrade-strategies/issues/30
    """

    def supertrend(self, dataframe: DataFrame, multiplier, period):
        df = dataframe.copy()

        df['TR'] = ta.TRANGE(df)
        df['ATR'] = ta.SMA(df['TR'], period)

        st = 'ST_' + str(period) + '_' + str(multiplier)
        stx = 'STX_' + str(period) + '_' + str(multiplier)

        # Compute basic upper and lower bands
        df['basic_ub'] = (df['high'] + df['low']) / 2 + multiplier * df['ATR']
        df['basic_lb'] = (df['high'] + df['low']) / 2 - multiplier * df['ATR']

        # Compute final upper and lower bands
        df['final_ub'] = 0.00
        df['final_lb'] = 0.00
        for i in range(period, len(df)):
            df['final_ub'].iat[i] = df['basic_ub'].iat[
                i] if df['basic_ub'].iat[i] < df['final_ub'].iat[
                    i - 1] or df['close'].iat[i - 1] > df['final_ub'].iat[
                        i - 1] else df['final_ub'].iat[i - 1]
            df['final_lb'].iat[i] = df['basic_lb'].iat[
                i] if df['basic_lb'].iat[i] > df['final_lb'].iat[
                    i - 1] or df['close'].iat[i - 1] < df['final_lb'].iat[
                        i - 1] else df['final_lb'].iat[i - 1]

        # Set the Supertrend value
        df[st] = 0.00
        for i in range(period, len(df)):
            df[st].iat[i] = df['final_ub'].iat[i] if df[st].iat[i - 1] == df['final_ub'].iat[i - 1] and df['close'].iat[i] <= df['final_ub'].iat[i] else \
                            df['final_lb'].iat[i] if df[st].iat[i - 1] == df['final_ub'].iat[i - 1] and df['close'].iat[i] >  df['final_ub'].iat[i] else \
                            df['final_lb'].iat[i] if df[st].iat[i - 1] == df['final_lb'].iat[i - 1] and df['close'].iat[i] >= df['final_lb'].iat[i] else \
                            df['final_ub'].iat[i] if df[st].iat[i - 1] == df['final_lb'].iat[i - 1] and df['close'].iat[i] <  df['final_lb'].iat[i] else 0.00
        # Mark the trend direction up/down
        df[stx] = np.where((df[st] > 0.00),
                           np.where((df['close'] < df[st]), 'down', 'up'),
                           np.NaN)

        # Remove basic and final bands from the columns
        df.drop(['basic_ub', 'basic_lb', 'final_ub', 'final_lb'],
                inplace=True,
                axis=1)

        df.fillna(0, inplace=True)

        return DataFrame(index=df.index, data={'ST': df[st], 'STX': df[stx]})
class mabStra(IStrategy):
    # buy params
    buy_mojo_ma_timeframe = IntParameter(2, 100, default=7, space='buy')
    buy_fast_ma_timeframe = IntParameter(2, 100, default=14, space='buy')
    buy_slow_ma_timeframe = IntParameter(2, 100, default=28, space='buy')
    buy_div_max = DecimalParameter(0, 2, decimals=4, default=2.25446, space='buy')
    buy_div_min = DecimalParameter(0, 2, decimals=4, default=0.29497, space='buy')
    # sell params
    sell_mojo_ma_timeframe = IntParameter(2, 100, default=7, space='sell')
    sell_fast_ma_timeframe = IntParameter(2, 100, default=14, space='sell')
    sell_slow_ma_timeframe = IntParameter(2, 100, default=28, space='sell')
    sell_div_max = DecimalParameter(0, 2, decimals=4, default=1.54593, space='sell')
    sell_div_min = DecimalParameter(0, 2, decimals=4, default=2.81436, space='sell')

    stoploss = -0.1

    # Optimal timeframe use it in your config
    timeframe = '4h'

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # SMA - ex Moving Average
        dataframe['buy-mojoMA'] = ta.SMA(dataframe,
                                         timeperiod=self.buy_mojo_ma_timeframe.value)
        dataframe['buy-fastMA'] = ta.SMA(dataframe,
                                         timeperiod=self.buy_fast_ma_timeframe.value)
        dataframe['buy-slowMA'] = ta.SMA(dataframe,
                                         timeperiod=self.buy_slow_ma_timeframe.value)
        dataframe['sell-mojoMA'] = ta.SMA(dataframe,
                                          timeperiod=self.sell_mojo_ma_timeframe.value)
        dataframe['sell-fastMA'] = ta.SMA(dataframe,
                                          timeperiod=self.sell_fast_ma_timeframe.value)
        dataframe['sell-slowMA'] = ta.SMA(dataframe,
                                          timeperiod=self.sell_slow_ma_timeframe.value)
        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:

        dataframe.loc[
            (
                (dataframe['buy-mojoMA'].div(dataframe['buy-fastMA'])
                    > self.buy_div_min.value) &
                (dataframe['buy-mojoMA'].div(dataframe['buy-fastMA'])
                    < self.buy_div_max.value) &
                (dataframe['buy-fastMA'].div(dataframe['buy-slowMA'])
                    > self.buy_div_min.value) &
                (dataframe['buy-fastMA'].div(dataframe['buy-slowMA'])
                    < self.buy_div_max.value)
            ),
            'buy'] = 1

        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe['sell-fastMA'].div(dataframe['sell-mojoMA'])
                    > self.sell_div_min.value) &
                (dataframe['sell-fastMA'].div(dataframe['sell-mojoMA'])
                    < self.sell_div_max.value) &
                (dataframe['sell-slowMA'].div(dataframe['sell-fastMA'])
                    > self.sell_div_min.value) &
                (dataframe['sell-slowMA'].div(dataframe['sell-fastMA'])
                    < self.sell_div_max.value)
            ),
            'sell'] = 1
        return dataframe
class Diamond(IStrategy):
    # ###################### RESULT PLACE ######################
    #    Config: 5 x UNLIMITED STOCK costume pair list,
    #    hyperopt : 5000 x SortinoHyperOptLossDaily,
    #    34/5000: 297 trades. 136/156/5 Wins/Draws/Losses. Avg profit   0.49%. Median profit   0.00%. Total profit  45.84477237 USDT (  33.96Σ%). Avg duration 11:54:00 min. Objective: -46.50379

    # Buy hyperspace params:
    buy_params = {
        "buy_fast_key": "high",
        "buy_horizontal_push": 7,
        "buy_slow_key": "volume",
        "buy_vertical_push": 0.942,
    }

    # Sell hyperspace params:
    sell_params = {
        "sell_fast_key": "high",
        "sell_horizontal_push": 10,
        "sell_slow_key": "low",
        "sell_vertical_push": 1.184,
    }

    # ROI table:
    minimal_roi = {"0": 0.242, "13": 0.044, "51": 0.02, "170": 0}

    # Stoploss:
    stoploss = -0.271

    # Trailing stop:
    trailing_stop = True
    trailing_stop_positive = 0.011
    trailing_stop_positive_offset = 0.054
    trailing_only_offset_is_reached = False
    # timeframe
    timeframe = '5m'
    # #################### END OF RESULT PLACE ####################

    buy_vertical_push = DecimalParameter(0.5,
                                         1.5,
                                         decimals=3,
                                         default=1,
                                         space='buy')
    buy_horizontal_push = IntParameter(0, 10, default=0, space='buy')
    buy_fast_key = CategoricalParameter(
        [
            'open',
            'high',
            'low',
            'close',
            'volume',
            #  you can not enable this lines befour you
            #  populate an indicator for them and set
            #  the same key name for it
            #  'ma_fast', 'ma_slow', {...}
        ],
        default='ma_fast',
        space='buy')
    buy_slow_key = CategoricalParameter(
        [
            'open',
            'high',
            'low',
            'close',
            'volume',
            #  'ma_fast', 'ma_slow', {...}
        ],
        default='ma_slow',
        space='buy')

    sell_vertical_push = DecimalParameter(0.5,
                                          1.5,
                                          decimals=3,
                                          default=1,
                                          space='sell')
    sell_horizontal_push = IntParameter(0, 10, default=0, space='sell')
    sell_fast_key = CategoricalParameter(
        [
            'open',
            'high',
            'low',
            'close',
            'volume',
            #  'ma_fast', 'ma_slow', {...}
        ],
        default='ma_fast',
        space='sell')
    sell_slow_key = CategoricalParameter(
        [
            'open',
            'high',
            'low',
            'close',
            'volume',
            #  'ma_fast', 'ma_slow', {...}
        ],
        default='ma_slow',
        space='sell')

    def populate_indicators(self, dataframe: DataFrame,
                            metadata: dict) -> DataFrame:
        # you can add new indicators and enable them inside
        # hyperoptable categorical params on the top
        # dataframe['ma_fast'] = ta.SMA(dataframe, timeperiod=9)
        # dataframe['ma_slow'] = ta.SMA(dataframe, timeperiod=18)
        # dataframe['{...}'] = ta.{...}(dataframe, timeperiod={...})
        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame,
                           metadata: dict) -> DataFrame:
        conditions = []
        conditions.append(
            qtpylib.crossed_above(
                dataframe[self.buy_fast_key.value].shift(
                    self.buy_horizontal_push.value),
                dataframe[self.buy_slow_key.value] *
                self.buy_vertical_push.value))

        if conditions:
            dataframe.loc[reduce(lambda x, y: x & y, conditions), 'buy'] = 1

        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame,
                            metadata: dict) -> DataFrame:
        conditions = []
        conditions.append(
            qtpylib.crossed_below(
                dataframe[self.sell_fast_key.value].shift(
                    self.sell_horizontal_push.value),
                dataframe[self.sell_slow_key.value] *
                self.sell_vertical_push.value))
        if conditions:
            dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1
        return dataframe
Beispiel #11
0
class MultiMa(IStrategy):

    buy_ma_count = IntParameter(2, 10, default=10, space='buy')
    buy_ma_gap = IntParameter(2, 10, default=2, space='buy')
    buy_ma_shift = IntParameter(0, 10, default=0, space='buy')
    # buy_ma_rolling = IntParameter(0, 10, default=0, space='buy')

    sell_ma_count = IntParameter(2, 10, default=10, space='sell')
    sell_ma_gap = IntParameter(2, 10, default=2, space='sell')
    sell_ma_shift = IntParameter(0, 10, default=0, space='sell')
    # sell_ma_rolling = IntParameter(0, 10, default=0, space='sell')

    # ROI table:
    minimal_roi = {"0": 0.30873, "569": 0.16689, "3211": 0.06473, "7617": 0}

    # Stoploss:
    stoploss = -0.1

    # Buy hypers
    timeframe = '4h'

    def populate_indicators(self, dataframe: DataFrame,
                            metadata: dict) -> DataFrame:

        # We will dinamicly generate the indicators
        # cuz this method just run one time in hyperopts
        # if you have static timeframes you can move first loop of buy and sell trends populators inside this method

        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame,
                           metadata: dict) -> DataFrame:

        for i in self.buy_ma_count.range:
            dataframe[f'buy-ma-{i+1}'] = ta.SMA(
                dataframe, timeperiod=int((i + 1) * self.buy_ma_gap.value))

        conditions = []

        for i in self.buy_ma_count.range:
            if i > 1:
                shift = self.buy_ma_shift.value
                for shift in self.buy_ma_shift.range:
                    conditions.append(dataframe[f'buy-ma-{i}'].shift(shift) >
                                      dataframe[f'buy-ma-{i-1}'].shift(shift))
        if conditions:
            dataframe.loc[reduce(lambda x, y: x & y, conditions), 'buy'] = 1

        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame,
                            metadata: dict) -> DataFrame:
        for i in self.sell_ma_count.range:
            dataframe[f'sell-ma-{i+1}'] = ta.SMA(
                dataframe, timeperiod=int((i + 1) * self.sell_ma_gap.value))

        conditions = []

        for i in self.sell_ma_count.range:
            if i > 1:
                shift = self.sell_ma_shift.value
                for shift in self.sell_ma_shift.range:
                    conditions.append(dataframe[f'sell-ma-{i}'].shift(shift) <
                                      dataframe[f'sell-ma-{i-1}'].shift(shift))
        if conditions:
            dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1
        return dataframe