title: Freqtrade 2021.7 Hyperopt space defining issue
body: <p>I'm new to freqtrade. I want to optimize some parameters in my strategy. As far as I see, with freqtrade 2021 we can optimize parameters without defining a seperate hyperopt file. I have followed the example on <a href="https://www.freqtrade.io/en/stable/hyperopt/" rel="nofollow noreferrer">https://www.freqtrade.io/en/stable/hyperopt/</a> and have written code which is attached through the end of my question. However when I run hyperopt with command below</p>
  <p><em>freqtrade hyperopt --config config.json --hyperopt-loss SharpeHyperOptLoss --strategy MyFirstStrategy -e 500 --spaces all</em></p>
  <p>it outputs error message below:</p>
  <pre><code>2021-08-25 00:27:43,590 - freqtrade.configuration.config_validation - INFO - Validating configuration ...
  2021-08-25 00:27:43,595 - freqtrade.resolvers.iresolver - INFO - Using resolved pairlist StaticPairList from '/media/Priamos/Projects/AutoTrade/freqtrade/freqtrade/plugins/pairlist/StaticPairList.py'...
  2021-08-25 00:27:43,596 - freqtrade.resolvers.iresolver - INFO - Using resolved pairlist AgeFilter from '/media/Priamos/Projects/AutoTrade/freqtrade/freqtrade/plugins/pairlist/AgeFilter.py'...
  2021-08-25 00:27:43,598 - freqtrade.resolvers.iresolver - INFO - Using resolved pairlist PrecisionFilter from '/media/Priamos/Projects/AutoTrade/freqtrade/freqtrade/plugins/pairlist/PrecisionFilter.py'...
  2021-08-25 00:27:43,603 - freqtrade.resolvers.iresolver - INFO - Using resolved pairlist PriceFilter from '/media/Priamos/Projects/AutoTrade/freqtrade/freqtrade/plugins/pairlist/PriceFilter.py'...
  2021-08-25 00:27:43,605 - freqtrade.resolvers.iresolver - INFO - Using resolved pairlist SpreadFilter from '/media/Priamos/Projects/AutoTrade/freqtrade/freqtrade/plugins/pairlist/SpreadFilter.py'...
  2021-08-25 00:27:43,611 - freqtrade.resolvers.iresolver - INFO - Using resolved pairlist RangeStabilityFilter from '/media/Priamos/Projects/AutoTrade/freqtrade/freqtrade/plugins/pairlist/rangestabilityfilter.py'...
  2021-08-25 00:27:53,516 - freqtrade.resolvers.iresolver - INFO - Using resolved hyperoptloss SharpeHyperOptLoss from '/media/Priamos/Projects/AutoTrade/freqtrade/freqtrade/optimize/hyperopt_loss_sharpe.py'...
  2021-08-25 00:27:53,517 - freqtrade.optimize.hyperopt - INFO - Using optimizer random state: 56312
  2021-08-25 00:27:53,517 - freqtrade - ERROR - The 'buy' space is included into the hyperoptimization but indicator_space() method is not found in your custom Hyperopt class. You should either implement this method or remove the 'buy' space from hyperoptimization.
  </code></pre>
  <p>I have added the last few lines of output not to create congestion here.
  Why it says I need to define indicator_space() method I don't understand. Since I'm trying to use default hyperopt to optimize parameters which are defined in my sample strategy. Strategy code is below:</p>
  <pre><code>import numpy as np  # noqa
  import pandas as pd  # noqa
  from freqtrade.optimize.space import SKDecimal, Dimension, Integer
  from pandas import DataFrame
  from functools import reduce
  
  from typing import Any, Callable, Dict, List
  
  from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
                                  IStrategy, IntParameter)
  
  import talib.abstract as ta
  import freqtrade.vendor.qtpylib.indicators as qtpylib
  
  
  class MyFirstStrategy(IStrategy):
  
      # Strategy interface version - allow new iterations of the strategy interface.
      # Check the documentation or the Sample strategy to get the latest version.
      INTERFACE_VERSION = 2
  
      # Minimal ROI designed for the strategy.
      # This attribute will be overridden if the config file contains &quot;minimal_roi&quot;.
      minimal_roi = {
          &quot;0&quot;: 0.06337,
          &quot;27&quot;: 0.03385,
          &quot;86&quot;: 0.01406,
          &quot;120&quot;: 0
      }
  
  
      # Optimal stoploss designed for the strategy.
      # This attribute will be overridden if the config file contains &quot;stoploss&quot;.
      stoploss = -0.49122
  
  
      # Trailing stoploss
      trailing_stop = False
      # trailing_only_offset_is_reached = False
      # trailing_stop_positive = 0.01
      # trailing_stop_positive_offset = 0.0  # Disabled / not configured
  
      # Optimal timeframe for the strategy.
      timeframe = '1h'
  
      # Run &quot;populate_indicators()&quot; only for new candle.
      process_only_new_candles = False
  
      # These values can be overridden in the &quot;ask_strategy&quot; 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 = 30
  
      # Optional order type mapping.
      order_types = {
          'buy': 'limit',
          'sell': 'limit',
          'stoploss': 'limit',
          'stoploss_on_exchange': False
      }
  
      # Optional order time in force.
      order_time_in_force = {
          'buy': 'gtc',
          'sell': 'gtc'
      }
      
      plot_config = {
          # Main plot indicators (Moving averages, ...)
          'main_plot': {
              'tema': {},
              'sar': {'color': 'white'},
          },
          'subplots': {
              # Subplots - each dict defines one additional plot
              &quot;MACD&quot;: {
                  'macd': {'color': 'blue'},
                  'macdsignal': {'color': 'orange'},
              },
              &quot;RSI&quot;: {
                  'rsi': {'color': 'red'},
              }
          }
      }
      # BUY PARAMS
      buy_rsi = IntParameter(10, 50, default=30, space='buy')
      buy_rsi_enabled = CategoricalParameter([True, False], default=True, space='buy')
      buy_trigger = CategoricalParameter(['buy_bb_lowerband1', 'buy_bb_lowerband2', 'buy_bb_lowerband3', 'buy_bb_lowerband4'],
                                         default='buy_bb_lowerband2', space='buy')
  
      # SELL PARAMS
      sell_rsi = IntParameter(60, 90, default=30, space='sell')
      sell_rsi_enabled = CategoricalParameter([True, False], default=True, space='sell')
      sell_trigger = CategoricalParameter(['sell_bb_middle1', 'sell_bb_upper1',
                                           'sell_bb_middle2', 'sell_bb_upper2',
                                           'sell_bb_middle3', 'sell_bb_upper3',
                                           'sell_bb_middle4', 'sell_bb_upper4'], default='sell-bb_middle2', space='sell')
  
  
      def populate_indicators(self, dataframe: DataFrame, metadata: dict) -&gt; DataFrame:
          &quot;&quot;&quot;
          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
          &quot;&quot;&quot;
          
          dataframe['buy_rsi'] = ta.RSI(dataframe)
          dataframe['sell_rsi'] = ta.RSI(dataframe)
  
          # Overlap Studies
          # ------------------------------------
  
          # Bollinger Bands
          bollinger1 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=1)
          dataframe['buy_bb_lowerband1'] = bollinger1['lower']
          dataframe['buy_bb_middleband1'] = bollinger1['mid']
          dataframe['buy_bb_upperband1'] = bollinger1['upper']
  
          bollinger2 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
          dataframe['buy_bb_lowerband2'] = bollinger2['lower']
          dataframe['buy_bb_middleband2'] = bollinger2['mid']
          dataframe['buy_bb_upperband2'] = bollinger2['upper']
  
          bollinger3 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=3)
          dataframe['buy_bb_lowerband3'] = bollinger3['lower']
          dataframe['buy_bb_middleband3'] = bollinger3['mid']
          dataframe['buy_bb_upperband3'] = bollinger3['upper']
  
          bollinger4 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=4)
          dataframe['buy_bb_lowerband4'] = bollinger4['lower']
          dataframe['buy_bb_middleband4'] = bollinger4['mid']
          dataframe['buy_bb_upperband4'] = bollinger4['upper']
  
          return dataframe
  
      def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -&gt; DataFrame:
          &quot;&quot;&quot;
          Buy strategy Hyperopt will build and use.
          &quot;&quot;&quot;
          conditions = []
  
          # GUARDS AND TRENDS
          if self.buy_rsi_enabled.value:
              conditions.append(dataframe['buy_rsi'] &lt; self.buy_rsi.value)
  
          # TRIGGERS
          if self.buy_trigger.value:
              if self.buy_trigger.value == 'buy_bb_lowerband1':
                  conditions.append(dataframe['close'] &lt; dataframe['buy_bb_lowerband1'])
              if self.buy_trigger.value == 'buy_bb_lowerband2':
                  conditions.append(dataframe['close'] &lt; dataframe['buy_bb_lowerband2'])
              if self.buy_trigger.value == 'buy_bb_lowerband3':
                  conditions.append(dataframe['close'] &lt; dataframe['buy_bb_lowerband3'])
              if self.buy_trigger.value == 'buy_bb_lowerband4':
                  conditions.append(dataframe['close'] &lt; dataframe['buy_bb_lowerband4'])
  
          # Check that the candle had volume
          conditions.append(dataframe['volume'] &gt; 0)
  
          if conditions:
              dataframe.loc[
                  reduce(lambda x, y: x &amp; y, conditions),
                  'buy'] = 1
  
          return dataframe
  
      def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -&gt; DataFrame:
          &quot;&quot;&quot;
          Based on TA indicators, populates the sell 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
          &quot;&quot;&quot;
          conditions = []
  
          # GUARDS AND TRENDS
          if self.sell_rsi_enabled.value:
              conditions.append(dataframe['rsi'] &gt; self.sell_rsi.value)
  
          # TRIGGERS
          if self.sell_trigger.value:
              if self.sell_trigger.value == 'sell_bb_middle1':
                  conditions.append(dataframe['close'] &lt; dataframe['sell_bb_middle1'])
              if self.sell_trigger.value == 'sell_bb_middle2':
                  conditions.append(dataframe['close'] &lt; dataframe['sell_bb_middle2'])
              if self.sell_trigger.value == 'sell_bb_middle3':
                  conditions.append(dataframe['close'] &lt; dataframe['sell_bb_middle3'])
              if self.sell_trigger.value == 'sell_bb_middle4':
                  conditions.append(dataframe['close'] &lt; dataframe['sell_bb_middle4'])
              if self.sell_trigger.value == 'sell_bb_upper1':
                  conditions.append(dataframe['close'] &lt; dataframe['sell_bb_upper1'])
              if self.sell_trigger.value == 'sell_bb_upper2':
                  conditions.append(dataframe['close'] &lt; dataframe['sell_bb_upper2'])
              if self.sell_trigger.value == 'sell_bb_upper3':
                  conditions.append(dataframe['close'] &lt; dataframe['sell_bb_upper3'])
              if self.sell_trigger.value == 'sell_bb_upper4':
                  conditions.append(dataframe['close'] &lt; dataframe['sell_bb_upper4'])
  
          # Check that the candle had volume
          conditions.append(dataframe['volume'] &gt; 0)
  
          if conditions:
              dataframe.loc[
                  reduce(lambda x, y: x &amp; y, conditions),
                  'buy'] = 1
  
          return dataframe
  </code></pre>
  <h1>What is my aim?</h1>
  <p>I'm trying to optimize parameters in my strategy. Trying to use default hyperopt without defining an explicit hyperopt file. Optimization code is implemented in Strategy.</p>
  <h1>Define the problem:</h1>
  <p>I have included error messages above which eventually says &quot;freqtrade - ERROR - The 'buy' space is included into the hyperoptimization but indicator_space() method is not found in your custom Hyperopt class. You should either implement this method or remove the 'buy' space from hyperoptimization.&quot;</p>
  <h1>How to replicate the problem:</h1>
  <p>Use command:
  <em>freqtrade hyperopt --config config.json --hyperopt-loss SharpeHyperOptLoss --strategy MyFirstStrategy -e 500 --spaces all</em></p>
  <h1>System:</h1>
  <p>Ubuntu 21.04 (with VMware virtual machine)
  Python 3.9
  Pycharm 2021.2 Community Edition</p>
  <p>Thanks in advance for any help or clarification provided.</p>