Exemplo n.º 1
0
def test_params_print(capsys):

    params = {
        "buy": {
            "buy_rsi": 30
        },
        "sell": {
            "sell_rsi": 70
        },
    }
    non_optimized = {
        "buy": {
            "buy_adx": 44
        },
        "sell": {
            "sell_adx": 65
        },
        "stoploss": {
            "stoploss": -0.05,
        },
        "roi": {
            "0": 0.05,
            "20": 0.01,
        },
        "trailing": {
            "trailing_stop": False,
            "trailing_stop_positive": 0.05,
            "trailing_stop_positive_offset": 0.1,
            "trailing_only_offset_is_reached": True
        },

    }
    HyperoptTools._params_pretty_print(params, 'buy', 'No header', non_optimized)

    captured = capsys.readouterr()
    assert re.search("# No header", captured.out)
    assert re.search('"buy_rsi": 30,\n', captured.out)
    assert re.search('"buy_adx": 44,  # value loaded.*\n', captured.out)
    assert not re.search("sell", captured.out)

    HyperoptTools._params_pretty_print(params, 'sell', 'Sell Header', non_optimized)
    captured = capsys.readouterr()
    assert re.search("# Sell Header", captured.out)
    assert re.search('"sell_rsi": 70,\n', captured.out)
    assert re.search('"sell_adx": 65,  # value loaded.*\n', captured.out)

    HyperoptTools._params_pretty_print(params, 'roi', 'ROI Table:', non_optimized)
    captured = capsys.readouterr()
    assert re.search("# ROI Table:  # value loaded.*\n", captured.out)
    assert re.search('minimal_roi = {\n', captured.out)
    assert re.search('"20": 0.01\n', captured.out)

    HyperoptTools._params_pretty_print(params, 'trailing', 'Trailing stop:', non_optimized)
    captured = capsys.readouterr()
    assert re.search("# Trailing stop:", captured.out)
    assert re.search('trailing_stop = False  # value loaded.*\n', captured.out)
    assert re.search('trailing_stop_positive = 0.05  # value loaded.*\n', captured.out)
    assert re.search('trailing_stop_positive_offset = 0.1  # value loaded.*\n', captured.out)
    assert re.search('trailing_only_offset_is_reached = True  # value loaded.*\n', captured.out)
Exemplo n.º 2
0
    def _load_params(self,
                     params: Dict,
                     space: str,
                     hyperopt: bool = False) -> None:
        """
        Set optimizable parameter values.
        :param params: Dictionary with new parameter values.
        """
        if not params:
            logger.info(f"No params for {space} found, using default values.")
        param_container: List[BaseParameter] = getattr(self,
                                                       f"ft_{space}_params")

        for attr_name, attr in self.detect_parameters(space):
            attr.name = attr_name
            attr.in_space = hyperopt and HyperoptTools.has_space(
                self.config, space)
            if not attr.category:
                attr.category = space

            param_container.append(attr)

            if params and attr_name in params:
                if attr.load:
                    attr.value = params[attr_name]
                    logger.info(
                        f'Strategy Parameter: {attr_name} = {attr.value}')
                else:
                    logger.warning(
                        f'Parameter "{attr_name}" exists, but is disabled. '
                        f'Default value "{attr.value}" used.')
            else:
                logger.info(
                    f'Strategy Parameter(default): {attr_name} = {attr.value}')
Exemplo n.º 3
0
    def __init__(self, config: Dict[str, Any]) -> None:
        self.buy_space: List[Dimension] = []
        self.sell_space: List[Dimension] = []
        self.protection_space: List[Dimension] = []
        self.roi_space: List[Dimension] = []
        self.stoploss_space: List[Dimension] = []
        self.trailing_space: List[Dimension] = []
        self.dimensions: List[Dimension] = []

        self.config = config

        self.backtesting = Backtesting(self.config)
        self.pairlist = self.backtesting.pairlists.whitelist

        if not self.config.get('hyperopt'):
            self.custom_hyperopt = HyperOptAuto(self.config)
        else:
            raise OperationalException(
                "Using separate Hyperopt files has been removed in 2021.9. Please convert "
                "your existing Hyperopt file to the new Hyperoptable strategy interface")

        self.backtesting._set_strategy(self.backtesting.strategylist[0])
        self.custom_hyperopt.strategy = self.backtesting.strategy

        self.custom_hyperoptloss = HyperOptLossResolver.load_hyperoptloss(self.config)
        self.calculate_loss = self.custom_hyperoptloss.hyperopt_loss_function
        time_now = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
        strategy = str(self.config['strategy'])
        self.results_file: Path = (self.config['user_data_dir'] / 'hyperopt_results' /
                                   f'strategy_{strategy}_{time_now}.fthypt')
        self.data_pickle_file = (self.config['user_data_dir'] /
                                 'hyperopt_results' / 'hyperopt_tickerdata.pkl')
        self.total_epochs = config.get('epochs', 0)

        self.current_best_loss = 100

        self.clean_hyperopt()

        self.num_epochs_saved = 0
        self.current_best_epoch: Optional[Dict[str, Any]] = None

        # Use max_open_trades for hyperopt as well, except --disable-max-market-positions is set
        if self.config.get('use_max_market_positions', True):
            self.max_open_trades = self.config['max_open_trades']
        else:
            logger.debug('Ignoring max_open_trades (--disable-max-market-positions was used) ...')
            self.max_open_trades = 0
        self.position_stacking = self.config.get('position_stacking', False)

        if HyperoptTools.has_space(self.config, 'sell'):
            # Make sure use_sell_signal is enabled
            if 'ask_strategy' not in self.config:
                self.config['ask_strategy'] = {}
            self.config['ask_strategy']['use_sell_signal'] = True

        self.print_all = self.config.get('print_all', False)
        self.hyperopt_table_header = 0
        self.print_colorized = self.config.get('print_colorized', False)
        self.print_json = self.config.get('print_json', False)
Exemplo n.º 4
0
def test_read_results_returns_epochs(mocker, hyperopt, testdatadir, caplog) -> None:
    epochs = create_results(mocker, hyperopt, testdatadir)
    mock_load = mocker.patch('freqtrade.optimize.hyperopt_tools.load', return_value=epochs)
    results_file = testdatadir / 'optimize' / 'ut_results.pickle'
    hyperopt_epochs = HyperoptTools._read_results(results_file)
    assert log_has(f"Reading epochs from '{results_file}'", caplog)
    assert hyperopt_epochs == epochs
    mock_load.assert_called_once()
Exemplo n.º 5
0
def test_load_previous_results(testdatadir, caplog) -> None:

    results_file = testdatadir / 'hyperopt_results_SampleStrategy.pickle'

    hyperopt_epochs = HyperoptTools.load_previous_results(results_file)

    assert len(hyperopt_epochs) == 5
    assert log_has_re(r"Reading pickled epochs from .*", caplog)

    caplog.clear()

    # Modern version
    results_file = testdatadir / 'strategy_SampleStrategy.fthypt'

    hyperopt_epochs = HyperoptTools.load_previous_results(results_file)

    assert len(hyperopt_epochs) == 5
    assert log_has_re(r"Reading epochs from .*", caplog)
Exemplo n.º 6
0
 def _get_no_optimize_details(self) -> Dict[str, Any]:
     """
     Get non-optimized parameters
     """
     result: Dict[str, Any] = {}
     strategy = self.backtesting.strategy
     if not HyperoptTools.has_space(self.config, 'roi'):
         result['roi'] = {str(k): v for k, v in strategy.minimal_roi.items()}
     if not HyperoptTools.has_space(self.config, 'stoploss'):
         result['stoploss'] = {'stoploss': strategy.stoploss}
     if not HyperoptTools.has_space(self.config, 'trailing'):
         result['trailing'] = {
             'trailing_stop': strategy.trailing_stop,
             'trailing_stop_positive': strategy.trailing_stop_positive,
             'trailing_stop_positive_offset': strategy.trailing_stop_positive_offset,
             'trailing_only_offset_is_reached': strategy.trailing_only_offset_is_reached,
         }
     return result
Exemplo n.º 7
0
def test_try_export_params(default_conf, tmpdir, caplog, mocker):
    default_conf['disableparamexport'] = False
    export_mock = mocker.patch("freqtrade.optimize.hyperopt_tools.HyperoptTools.export_params")

    filename = Path(tmpdir) / f"{CURRENT_TEST_STRATEGY}.json"
    assert not filename.is_file()
    params = {
        "params_details": {
            "buy": {
                "buy_rsi": 30
            },
            "sell": {
                "sell_rsi": 70
            },
            "roi": {
                "0": 0.528,
                "346": 0.08499,
                "507": 0.049,
                "1595": 0
            }
        },
        "params_not_optimized": {
            "stoploss": -0.05,
            "trailing": {
                "trailing_stop": False,
                "trailing_stop_positive": 0.05,
                "trailing_stop_positive_offset": 0.1,
                "trailing_only_offset_is_reached": True
            },
        },
        FTHYPT_FILEVERSION: 2,

    }
    HyperoptTools.try_export_params(default_conf, "StrategyTestVXXX", params)

    assert log_has("Strategy not found, not exporting parameter file.", caplog)
    assert export_mock.call_count == 0
    caplog.clear()

    HyperoptTools.try_export_params(default_conf, CURRENT_TEST_STRATEGY, params)

    assert export_mock.call_count == 1
    assert export_mock.call_args_list[0][0][1] == CURRENT_TEST_STRATEGY
    assert export_mock.call_args_list[0][0][2].name == 'strategy_test_v3.json'
Exemplo n.º 8
0
def test_export_params(tmpdir):

    filename = Path(tmpdir) / f"{CURRENT_TEST_STRATEGY}.json"
    assert not filename.is_file()
    params = {
        "params_details": {
            "buy": {
                "buy_rsi": 30
            },
            "sell": {
                "sell_rsi": 70
            },
            "roi": {
                "0": 0.528,
                "346": 0.08499,
                "507": 0.049,
                "1595": 0
            }
        },
        "params_not_optimized": {
            "stoploss": -0.05,
            "trailing": {
                "trailing_stop": False,
                "trailing_stop_positive": 0.05,
                "trailing_stop_positive_offset": 0.1,
                "trailing_only_offset_is_reached": True
            },
        }

    }
    HyperoptTools.export_params(params, CURRENT_TEST_STRATEGY, filename)

    assert filename.is_file()

    with filename.open('r') as f:
        content = rapidjson.load(f)
    assert content['strategy_name'] == CURRENT_TEST_STRATEGY
    assert 'params' in content
    assert "buy" in content["params"]
    assert "sell" in content["params"]
    assert "roi" in content["params"]
    assert "stoploss" in content["params"]
    assert "trailing" in content["params"]
Exemplo n.º 9
0
def test_load_previous_results(mocker, hyperopt, testdatadir, caplog) -> None:
    epochs = create_results(mocker, hyperopt, testdatadir)
    mock_load = mocker.patch('joblib.load', return_value=epochs)
    mocker.patch.object(Path, 'is_file', MagicMock(return_value=True))
    statmock = MagicMock()
    statmock.st_size = 5
    # mocker.patch.object(Path, 'stat', MagicMock(return_value=statmock))

    results_file = testdatadir / 'optimize' / 'ut_results.pickle'

    hyperopt_epochs = HyperoptTools.load_previous_results(results_file)

    assert hyperopt_epochs == epochs
    mock_load.assert_called_once()

    del epochs[0]['is_best']
    mock_load = mocker.patch('joblib.load', return_value=epochs)

    with pytest.raises(OperationalException):
        HyperoptTools.load_previous_results(results_file)
Exemplo n.º 10
0
def test__pprint_dict():
    params = {
        'buy_std': 1.2,
        'buy_rsi': 31,
        'buy_enable': True,
        'buy_what': 'asdf'
    }
    non_params = {'buy_notoptimied': 55}

    x = HyperoptTools._pprint_dict(params, non_params)
    assert x == """{
Exemplo n.º 11
0
def test_format_results(hyperopt):
    # Test with BTC as stake_currency
    trades = [
        ('ETH/BTC', 2, 2, 123),
        ('LTC/BTC', 1, 1, 123),
        ('XPR/BTC', -1, -2, -246)
    ]
    labels = ['currency', 'profit_ratio', 'profit_abs', 'trade_duration']
    df = pd.DataFrame.from_records(trades, columns=labels)
    results_metrics = hyperopt._calculate_results_metrics(df)
    results_explanation = hyperopt._format_results_explanation_string(results_metrics)
    total_profit = results_metrics['total_profit']

    results = {
        'loss': 0.0,
        'params_dict': None,
        'params_details': None,
        'results_metrics': results_metrics,
        'results_explanation': results_explanation,
        'total_profit': total_profit,
        'current_epoch': 1,
        'is_initial_point': True,
    }

    result = HyperoptTools._format_explanation_string(results, 1)
    assert result.find(' 66.67%')
    assert result.find('Total profit 1.00000000 BTC')
    assert result.find('2.0000Σ %')

    # Test with EUR as stake_currency
    trades = [
        ('ETH/EUR', 2, 2, 123),
        ('LTC/EUR', 1, 1, 123),
        ('XPR/EUR', -1, -2, -246)
    ]
    df = pd.DataFrame.from_records(trades, columns=labels)
    results_metrics = hyperopt._calculate_results_metrics(df)
    results['total_profit'] = results_metrics['total_profit']
    result = HyperoptTools._format_explanation_string(results, 1)
    assert result.find('Total profit 1.00000000 EUR')
Exemplo n.º 12
0
    def init_spaces(self):
        """
        Assign the dimensions in the hyperoptimization space.
        """
        if HyperoptTools.has_space(self.config, 'protection'):
            # Protections can only be optimized when using the Parameter interface
            logger.debug("Hyperopt has 'protection' space")
            # Enable Protections if protection space is selected.
            self.config['enable_protections'] = True
            self.protection_space = self.custom_hyperopt.protection_space()

        if HyperoptTools.has_space(self.config, 'buy'):
            logger.debug("Hyperopt has 'buy' space")
            self.buy_space = self.custom_hyperopt.buy_indicator_space()

        if HyperoptTools.has_space(self.config, 'sell'):
            logger.debug("Hyperopt has 'sell' space")
            self.sell_space = self.custom_hyperopt.sell_indicator_space()

        if HyperoptTools.has_space(self.config, 'roi'):
            logger.debug("Hyperopt has 'roi' space")
            self.roi_space = self.custom_hyperopt.roi_space()

        if HyperoptTools.has_space(self.config, 'stoploss'):
            logger.debug("Hyperopt has 'stoploss' space")
            self.stoploss_space = self.custom_hyperopt.stoploss_space()

        if HyperoptTools.has_space(self.config, 'trailing'):
            logger.debug("Hyperopt has 'trailing' space")
            self.trailing_space = self.custom_hyperopt.trailing_space()
        self.dimensions = (self.buy_space + self.sell_space +
                           self.protection_space + self.roi_space +
                           self.stoploss_space + self.trailing_space)
Exemplo n.º 13
0
def start_hyperopt_list(args: Dict[str, Any]) -> None:
    """
    List hyperopt epochs previously evaluated
    """
    from freqtrade.optimize.hyperopt_tools import HyperoptTools

    config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)

    print_colorized = config.get('print_colorized', False)
    print_json = config.get('print_json', False)
    export_csv = config.get('export_csv', None)
    no_details = config.get('hyperopt_list_no_details', False)
    no_header = False

    filteroptions = {
        'only_best': config.get('hyperopt_list_best', False),
        'only_profitable': config.get('hyperopt_list_profitable', False),
        'filter_min_trades': config.get('hyperopt_list_min_trades', 0),
        'filter_max_trades': config.get('hyperopt_list_max_trades', 0),
        'filter_min_avg_time': config.get('hyperopt_list_min_avg_time', None),
        'filter_max_avg_time': config.get('hyperopt_list_max_avg_time', None),
        'filter_min_avg_profit': config.get('hyperopt_list_min_avg_profit', None),
        'filter_max_avg_profit': config.get('hyperopt_list_max_avg_profit', None),
        'filter_min_total_profit': config.get('hyperopt_list_min_total_profit', None),
        'filter_max_total_profit': config.get('hyperopt_list_max_total_profit', None),
        'filter_min_objective': config.get('hyperopt_list_min_objective', None),
        'filter_max_objective': config.get('hyperopt_list_max_objective', None),
    }

    results_file = get_latest_hyperopt_file(
        config['user_data_dir'] / 'hyperopt_results',
        config.get('hyperoptexportfilename'))

    # Previous evaluations
    epochs = HyperoptTools.load_previous_results(results_file)
    total_epochs = len(epochs)

    epochs = hyperopt_filter_epochs(epochs, filteroptions)

    if print_colorized:
        colorama_init(autoreset=True)

    if not export_csv:
        try:
            print(HyperoptTools.get_result_table(config, epochs, total_epochs,
                                                 not filteroptions['only_best'],
                                                 print_colorized, 0))
        except KeyboardInterrupt:
            print('User interrupted..')

    if epochs and not no_details:
        sorted_epochs = sorted(epochs, key=itemgetter('loss'))
        results = sorted_epochs[0]
        HyperoptTools.show_epoch_details(results, total_epochs, print_json, no_header)

    if epochs and export_csv:
        HyperoptTools.export_csv_file(
            config, epochs, total_epochs, not filteroptions['only_best'], export_csv
        )
Exemplo n.º 14
0
def test_print_epoch_details(capsys):
    test_result = {
        'params_details': {
            'trailing': {
                'trailing_stop': True,
                'trailing_stop_positive': 0.02,
                'trailing_stop_positive_offset': 0.04,
                'trailing_only_offset_is_reached': True
            },
            'roi': {
                0: 0.18,
                90: 0.14,
                225: 0.05,
                430: 0
            },
        },
        'results_explanation': 'foo result',
        'is_initial_point': False,
        'total_profit': 0,
        'current_epoch': 2,  # This starts from 1 (in a human-friendly manner)
        'is_best': True
    }

    HyperoptTools.print_epoch_details(test_result, 5, False, no_header=True)
    captured = capsys.readouterr()
    assert '# Trailing stop:' in captured.out
    # re.match(r"Pairs for .*", captured.out)
    assert re.search(r'^\s+trailing_stop = True$', captured.out, re.MULTILINE)
    assert re.search(r'^\s+trailing_stop_positive = 0.02$', captured.out,
                     re.MULTILINE)
    assert re.search(r'^\s+trailing_stop_positive_offset = 0.04$',
                     captured.out, re.MULTILINE)
    assert re.search(r'^\s+trailing_only_offset_is_reached = True$',
                     captured.out, re.MULTILINE)

    assert '# ROI table:' in captured.out
    assert re.search(r'^\s+minimal_roi = \{$', captured.out, re.MULTILINE)
    assert re.search(r'^\s+\"90\"\:\s0.14,\s*$', captured.out, re.MULTILINE)
Exemplo n.º 15
0
def test_save_results_saves_epochs(hyperopt, tmpdir, caplog) -> None:

    hyperopt.results_file = Path(tmpdir / 'ut_results.fthypt')

    hyperopt_epochs = HyperoptTools.load_filtered_results(
        hyperopt.results_file, {})
    assert log_has_re("Hyperopt file .* not found.", caplog)
    assert hyperopt_epochs == ([], 0)

    # Test writing to temp dir and reading again
    epochs = create_results()

    caplog.set_level(logging.DEBUG)

    for epoch in epochs:
        hyperopt._save_result(epoch)
    assert log_has(f"1 epoch saved to '{hyperopt.results_file}'.", caplog)

    hyperopt._save_result(epochs[0])
    assert log_has(f"2 epochs saved to '{hyperopt.results_file}'.", caplog)

    hyperopt_epochs = HyperoptTools.load_filtered_results(
        hyperopt.results_file, {})
    assert len(hyperopt_epochs) == 2
    assert hyperopt_epochs[1] == 2
    assert len(hyperopt_epochs[0]) == 2

    result_gen = HyperoptTools._read_results(hyperopt.results_file, 1)
    epoch = next(result_gen)
    assert len(epoch) == 1
    assert epoch[0] == epochs[0]
    epoch = next(result_gen)
    assert len(epoch) == 1
    epoch = next(result_gen)
    assert len(epoch) == 0
    with pytest.raises(StopIteration):
        next(result_gen)
Exemplo n.º 16
0
    def print_results(self, results) -> None:
        """
        Log results if it is better than any previous evaluation
        TODO: this should be moved to HyperoptTools too
        """
        is_best = results['is_best']

        if self.print_all or is_best:
            print(
                HyperoptTools.get_result_table(self.config, results,
                                               self.total_epochs,
                                               self.print_all,
                                               self.print_colorized,
                                               self.hyperopt_table_header))
            self.hyperopt_table_header = 2
Exemplo n.º 17
0
def test_save_results_saves_epochs(hyperopt, tmpdir, caplog) -> None:
    # Test writing to temp dir and reading again
    epochs = create_results()
    hyperopt.results_file = Path(tmpdir / 'ut_results.fthypt')

    caplog.set_level(logging.DEBUG)

    for epoch in epochs:
        hyperopt._save_result(epoch)
    assert log_has(f"1 epoch saved to '{hyperopt.results_file}'.", caplog)

    hyperopt._save_result(epochs[0])
    assert log_has(f"2 epochs saved to '{hyperopt.results_file}'.", caplog)

    hyperopt_epochs = HyperoptTools.load_previous_results(hyperopt.results_file)
    assert len(hyperopt_epochs) == 2
Exemplo n.º 18
0
    def generate_optimizer(self, raw_params: List[Any], iteration=None) -> Dict:
        """
        Used Optimize function.
        Called once per epoch to optimize whatever is configured.
        Keep this function as optimized as possible!
        """
        backtest_start_time = datetime.now(timezone.utc)
        params_dict = self._get_params_dict(self.dimensions, raw_params)

        # Apply parameters
        if HyperoptTools.has_space(self.config, 'buy'):
            self.assign_params(params_dict, 'buy')

        if HyperoptTools.has_space(self.config, 'sell'):
            self.assign_params(params_dict, 'sell')

        if HyperoptTools.has_space(self.config, 'protection'):
            self.assign_params(params_dict, 'protection')

        if HyperoptTools.has_space(self.config, 'roi'):
            self.backtesting.strategy.minimal_roi = (  # type: ignore
                self.custom_hyperopt.generate_roi_table(params_dict))

        if HyperoptTools.has_space(self.config, 'stoploss'):
            self.backtesting.strategy.stoploss = params_dict['stoploss']

        if HyperoptTools.has_space(self.config, 'trailing'):
            d = self.custom_hyperopt.generate_trailing_params(params_dict)
            self.backtesting.strategy.trailing_stop = d['trailing_stop']
            self.backtesting.strategy.trailing_stop_positive = d['trailing_stop_positive']
            self.backtesting.strategy.trailing_stop_positive_offset = \
                d['trailing_stop_positive_offset']
            self.backtesting.strategy.trailing_only_offset_is_reached = \
                d['trailing_only_offset_is_reached']

        with self.data_pickle_file.open('rb') as f:
            processed = load(f, mmap_mode='r')
        bt_results = self.backtesting.backtest(
            processed=processed,
            start_date=self.min_date,
            end_date=self.max_date,
            max_open_trades=self.max_open_trades,
            position_stacking=self.position_stacking,
            enable_protections=self.config.get('enable_protections', False),
        )
        backtest_end_time = datetime.now(timezone.utc)
        bt_results.update({
            'backtest_start_time': int(backtest_start_time.timestamp()),
            'backtest_end_time': int(backtest_end_time.timestamp()),
        })

        return self._get_results_dict(bt_results, self.min_date, self.max_date,
                                      params_dict,
                                      processed=processed)
Exemplo n.º 19
0
    def _get_results_dict(self, backtesting_results, min_date, max_date,
                          params_dict,
                          processed: Dict[str, DataFrame]) -> Dict[str, Any]:
        params_details = self._get_params_details(params_dict)

        strat_stats = generate_strategy_stats(
            processed,
            self.backtesting.strategy.get_strategy_name(),
            backtesting_results,
            min_date,
            max_date,
            market_change=0)
        results_explanation = HyperoptTools.format_results_explanation_string(
            strat_stats, self.config['stake_currency'])

        not_optimized = self.backtesting.strategy.get_no_optimize_params()
        not_optimized = deep_merge_dicts(not_optimized,
                                         self._get_no_optimize_details())

        trade_count = strat_stats['total_trades']
        total_profit = strat_stats['profit_total']

        # If this evaluation contains too short amount of trades to be
        # interesting -- consider it as 'bad' (assigned max. loss value)
        # in order to cast this hyperspace point away from optimization
        # path. We do not want to optimize 'hodl' strategies.
        loss: float = MAX_LOSS
        if trade_count >= self.config['hyperopt_min_trades']:
            loss = self.calculate_loss(results=backtesting_results['results'],
                                       trade_count=trade_count,
                                       min_date=min_date,
                                       max_date=max_date,
                                       config=self.config,
                                       processed=processed,
                                       backtest_stats=strat_stats)
        return {
            'loss': loss,
            'params_dict': params_dict,
            'params_details': params_details,
            'params_not_optimized': not_optimized,
            'results_metrics': strat_stats,
            'results_explanation': results_explanation,
            'total_profit': total_profit,
        }
Exemplo n.º 20
0
    def _get_params_details(self, params: Dict) -> Dict:
        """
        Return the params for each space
        """
        result: Dict = {}

        if HyperoptTools.has_space(self.config, 'buy'):
            result['buy'] = {p.name: params.get(p.name) for p in self.buy_space}
        if HyperoptTools.has_space(self.config, 'sell'):
            result['sell'] = {p.name: params.get(p.name) for p in self.sell_space}
        if HyperoptTools.has_space(self.config, 'protection'):
            result['protection'] = {p.name: params.get(p.name) for p in self.protection_space}
        if HyperoptTools.has_space(self.config, 'roi'):
            result['roi'] = {str(k): v for k, v in
                             self.custom_hyperopt.generate_roi_table(params).items()}
        if HyperoptTools.has_space(self.config, 'stoploss'):
            result['stoploss'] = {p.name: params.get(p.name) for p in self.stoploss_space}
        if HyperoptTools.has_space(self.config, 'trailing'):
            result['trailing'] = self.custom_hyperopt.generate_trailing_params(params)

        return result
Exemplo n.º 21
0
    def start(self) -> None:
        self.random_state = self._set_random_state(
            self.config.get('hyperopt_random_state', None))
        logger.info(f"Using optimizer random state: {self.random_state}")
        self.hyperopt_table_header = -1
        # Initialize spaces ...
        self.init_spaces()

        self.prepare_hyperopt_data()

        # We don't need exchange instance anymore while running hyperopt
        self.backtesting.exchange.close()
        self.backtesting.exchange._api = None  # type: ignore
        self.backtesting.exchange._api_async = None  # type: ignore
        # self.backtesting.exchange = None  # type: ignore
        self.backtesting.pairlists = None  # type: ignore

        cpus = cpu_count()
        logger.info(f"Found {cpus} CPU cores. Let's make them scream!")
        config_jobs = self.config.get('hyperopt_jobs', -1)
        logger.info(f'Number of parallel jobs set as: {config_jobs}')

        self.opt = self.get_optimizer(self.dimensions, config_jobs)

        if self.print_colorized:
            colorama_init(autoreset=True)

        try:
            with Parallel(n_jobs=config_jobs) as parallel:
                jobs = parallel._effective_n_jobs()
                logger.info(
                    f'Effective number of parallel workers used: {jobs}')

                # Define progressbar
                if self.print_colorized:
                    widgets = [
                        ' [Epoch ',
                        progressbar.Counter(),
                        ' of ',
                        str(self.total_epochs),
                        ' (',
                        progressbar.Percentage(),
                        ')] ',
                        progressbar.Bar(marker=progressbar.AnimatedMarker(
                            fill='\N{FULL BLOCK}',
                            fill_wrap=Fore.GREEN + '{}' + Fore.RESET,
                            marker_wrap=Style.BRIGHT + '{}' + Style.RESET_ALL,
                        )),
                        ' [',
                        progressbar.ETA(),
                        ', ',
                        progressbar.Timer(),
                        ']',
                    ]
                else:
                    widgets = [
                        ' [Epoch ',
                        progressbar.Counter(),
                        ' of ',
                        str(self.total_epochs),
                        ' (',
                        progressbar.Percentage(),
                        ')] ',
                        progressbar.Bar(marker=progressbar.AnimatedMarker(
                            fill='\N{FULL BLOCK}', )),
                        ' [',
                        progressbar.ETA(),
                        ', ',
                        progressbar.Timer(),
                        ']',
                    ]
                with progressbar.ProgressBar(max_value=self.total_epochs,
                                             redirect_stdout=False,
                                             redirect_stderr=False,
                                             widgets=widgets) as pbar:
                    EVALS = ceil(self.total_epochs / jobs)
                    for i in range(EVALS):
                        # Correct the number of epochs to be processed for the last
                        # iteration (should not exceed self.total_epochs in total)
                        n_rest = (i + 1) * jobs - self.total_epochs
                        current_jobs = jobs - n_rest if n_rest > 0 else jobs

                        asked = self.opt.ask(n_points=current_jobs)
                        f_val = self.run_optimizer_parallel(parallel, asked, i)
                        self.opt.tell(asked, [v['loss'] for v in f_val])

                        # Calculate progressbar outputs
                        for j, val in enumerate(f_val):
                            # Use human-friendly indexes here (starting from 1)
                            current = i * jobs + j + 1
                            val['current_epoch'] = current
                            val['is_initial_point'] = current <= INITIAL_POINTS

                            logger.debug(f"Optimizer epoch evaluated: {val}")

                            is_best = HyperoptTools.is_best_loss(
                                val, self.current_best_loss)
                            # This value is assigned here and not in the optimization method
                            # to keep proper order in the list of results. That's because
                            # evaluations can take different time. Here they are aligned in the
                            # order they will be shown to the user.
                            val['is_best'] = is_best
                            self.print_results(val)

                            if is_best:
                                self.current_best_loss = val['loss']
                                self.current_best_epoch = val

                            self._save_result(val)

                            pbar.update(current)

        except KeyboardInterrupt:
            print('User interrupted..')

        logger.info(
            f"{self.num_epochs_saved} {plural(self.num_epochs_saved, 'epoch')} "
            f"saved to '{self.results_file}'.")

        if self.current_best_epoch:
            HyperoptTools.try_export_params(
                self.config, self.backtesting.strategy.get_strategy_name(),
                self.current_best_epoch)

            HyperoptTools.show_epoch_details(self.current_best_epoch,
                                             self.total_epochs,
                                             self.print_json)
        else:
            # This is printed when Ctrl+C is pressed quickly, before first epochs have
            # a chance to be evaluated.
            print("No epochs evaluated yet, no best result.")
Exemplo n.º 22
0
def start_hyperopt_show(args: Dict[str, Any]) -> None:
    """
    Show details of a hyperopt epoch previously evaluated
    """
    from freqtrade.optimize.hyperopt_tools import HyperoptTools

    config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)

    print_json = config.get('print_json', False)
    no_header = config.get('hyperopt_show_no_header', False)
    results_file = get_latest_hyperopt_file(
        config['user_data_dir'] / 'hyperopt_results',
        config.get('hyperoptexportfilename'))

    n = config.get('hyperopt_show_index', -1)

    filteroptions = {
        'only_best':
        config.get('hyperopt_list_best', False),
        'only_profitable':
        config.get('hyperopt_list_profitable', False),
        'filter_min_trades':
        config.get('hyperopt_list_min_trades', 0),
        'filter_max_trades':
        config.get('hyperopt_list_max_trades', 0),
        'filter_min_avg_time':
        config.get('hyperopt_list_min_avg_time', None),
        'filter_max_avg_time':
        config.get('hyperopt_list_max_avg_time', None),
        'filter_min_avg_profit':
        config.get('hyperopt_list_min_avg_profit', None),
        'filter_max_avg_profit':
        config.get('hyperopt_list_max_avg_profit', None),
        'filter_min_total_profit':
        config.get('hyperopt_list_min_total_profit', None),
        'filter_max_total_profit':
        config.get('hyperopt_list_max_total_profit', None),
        'filter_min_objective':
        config.get('hyperopt_list_min_objective', None),
        'filter_max_objective':
        config.get('hyperopt_list_max_objective', None)
    }

    # Previous evaluations
    epochs = HyperoptTools.load_previous_results(results_file)
    total_epochs = len(epochs)

    epochs = hyperopt_filter_epochs(epochs, filteroptions)
    filtered_epochs = len(epochs)

    if n > filtered_epochs:
        raise OperationalException(
            f"The index of the epoch to show should be less than {filtered_epochs + 1}."
        )
    if n < -filtered_epochs:
        raise OperationalException(
            f"The index of the epoch to show should be greater than {-filtered_epochs - 1}."
        )

    # Translate epoch index from human-readable format to pythonic
    if n > 0:
        n -= 1

    if epochs:
        val = epochs[n]

        metrics = val['results_metrics']
        if 'strategy_name' in metrics:
            strategy_name = metrics['strategy_name']
            show_backtest_result(strategy_name, metrics,
                                 metrics['stake_currency'])

            HyperoptTools.try_export_params(config, strategy_name, val)

        HyperoptTools.show_epoch_details(val,
                                         total_epochs,
                                         print_json,
                                         no_header,
                                         header_str="Epoch details")
Exemplo n.º 23
0
    def start(self) -> None:
        self.random_state = self._set_random_state(
            self.config.get('hyperopt_random_state', None))
        logger.info(f"Using optimizer random state: {self.random_state}")
        self.hyperopt_table_header = -1
        data, timerange = self.backtesting.load_bt_data()
        logger.info("Dataload complete. Calculating indicators")
        preprocessed = self.backtesting.strategy.ohlcvdata_to_dataframe(data)

        # Trim startup period from analyzed dataframe
        for pair, df in preprocessed.items():
            preprocessed[pair] = trim_dataframe(
                df,
                timerange,
                startup_candles=self.backtesting.required_startup)
        min_date, max_date = get_timerange(preprocessed)

        logger.info(
            f'Hyperopting with data from {min_date.strftime(DATETIME_PRINT_FORMAT)} '
            f'up to {max_date.strftime(DATETIME_PRINT_FORMAT)} '
            f'({(max_date - min_date).days} days)..')

        dump(preprocessed, self.data_pickle_file)

        # We don't need exchange instance anymore while running hyperopt
        self.backtesting.exchange.close()
        self.backtesting.exchange._api = None  # type: ignore
        self.backtesting.exchange._api_async = None  # type: ignore
        # self.backtesting.exchange = None  # type: ignore
        self.backtesting.pairlists = None  # type: ignore
        self.backtesting.strategy.dp = None  # type: ignore
        IStrategy.dp = None  # type: ignore

        cpus = cpu_count()
        logger.info(f"Found {cpus} CPU cores. Let's make them scream!")
        config_jobs = self.config.get('hyperopt_jobs', -1)
        logger.info(f'Number of parallel jobs set as: {config_jobs}')

        self.dimensions: List[Dimension] = self.hyperopt_space()
        self.opt = self.get_optimizer(self.dimensions, config_jobs)

        if self.print_colorized:
            colorama_init(autoreset=True)

        try:
            with Parallel(n_jobs=config_jobs) as parallel:
                jobs = parallel._effective_n_jobs()
                logger.info(
                    f'Effective number of parallel workers used: {jobs}')

                # Define progressbar
                if self.print_colorized:
                    widgets = [
                        ' [Epoch ',
                        progressbar.Counter(),
                        ' of ',
                        str(self.total_epochs),
                        ' (',
                        progressbar.Percentage(),
                        ')] ',
                        progressbar.Bar(marker=progressbar.AnimatedMarker(
                            fill='\N{FULL BLOCK}',
                            fill_wrap=Fore.GREEN + '{}' + Fore.RESET,
                            marker_wrap=Style.BRIGHT + '{}' + Style.RESET_ALL,
                        )),
                        ' [',
                        progressbar.ETA(),
                        ', ',
                        progressbar.Timer(),
                        ']',
                    ]
                else:
                    widgets = [
                        ' [Epoch ',
                        progressbar.Counter(),
                        ' of ',
                        str(self.total_epochs),
                        ' (',
                        progressbar.Percentage(),
                        ')] ',
                        progressbar.Bar(marker=progressbar.AnimatedMarker(
                            fill='\N{FULL BLOCK}', )),
                        ' [',
                        progressbar.ETA(),
                        ', ',
                        progressbar.Timer(),
                        ']',
                    ]
                with progressbar.ProgressBar(max_value=self.total_epochs,
                                             redirect_stdout=False,
                                             redirect_stderr=False,
                                             widgets=widgets) as pbar:
                    EVALS = ceil(self.total_epochs / jobs)
                    for i in range(EVALS):
                        # Correct the number of epochs to be processed for the last
                        # iteration (should not exceed self.total_epochs in total)
                        n_rest = (i + 1) * jobs - self.total_epochs
                        current_jobs = jobs - n_rest if n_rest > 0 else jobs

                        asked = self.opt.ask(n_points=current_jobs)
                        f_val = self.run_optimizer_parallel(parallel, asked, i)
                        self.opt.tell(asked, [v['loss'] for v in f_val])

                        # Calculate progressbar outputs
                        for j, val in enumerate(f_val):
                            # Use human-friendly indexes here (starting from 1)
                            current = i * jobs + j + 1
                            val['current_epoch'] = current
                            val['is_initial_point'] = current <= INITIAL_POINTS

                            logger.debug(f"Optimizer epoch evaluated: {val}")

                            is_best = HyperoptTools.is_best_loss(
                                val, self.current_best_loss)
                            # This value is assigned here and not in the optimization method
                            # to keep proper order in the list of results. That's because
                            # evaluations can take different time. Here they are aligned in the
                            # order they will be shown to the user.
                            val['is_best'] = is_best
                            self.print_results(val)

                            if is_best:
                                self.current_best_loss = val['loss']
                            self.epochs.append(val)

                            # Save results after each best epoch and every 100 epochs
                            if is_best or current % 100 == 0:
                                self._save_results()

                            pbar.update(current)

        except KeyboardInterrupt:
            print('User interrupted..')

        self._save_results()
        logger.info(
            f"{self.num_epochs_saved} {plural(self.num_epochs_saved, 'epoch')} "
            f"saved to '{self.results_file}'.")

        if self.epochs:
            sorted_epochs = sorted(self.epochs, key=itemgetter('loss'))
            best_epoch = sorted_epochs[0]
            HyperoptTools.print_epoch_details(best_epoch, self.total_epochs,
                                              self.print_json)
        else:
            # This is printed when Ctrl+C is pressed quickly, before first epochs have
            # a chance to be evaluated.
            print("No epochs evaluated yet, no best result.")
Exemplo n.º 24
0
def test_has_space(hyperopt_conf, spaces, expected_results):
    for s in ['buy', 'sell', 'roi', 'stoploss', 'trailing']:
        hyperopt_conf.update({'spaces': spaces})
        assert HyperoptTools.has_space(hyperopt_conf, s) == expected_results[s]
Exemplo n.º 25
0
def test_hyperopt_format_results(hyperopt):

    bt_result = {
        'results':
        pd.DataFrame({
            "pair":
            ["UNITTEST/BTC", "UNITTEST/BTC", "UNITTEST/BTC", "UNITTEST/BTC"],
            "profit_ratio": [0.003312, 0.010801, 0.013803, 0.002780],
            "profit_abs": [0.000003, 0.000011, 0.000014, 0.000003],
            "open_date": [
                Arrow(2017, 11, 14, 19, 32, 00).datetime,
                Arrow(2017, 11, 14, 21, 36, 00).datetime,
                Arrow(2017, 11, 14, 22, 12, 00).datetime,
                Arrow(2017, 11, 14, 22, 44, 00).datetime
            ],
            "close_date": [
                Arrow(2017, 11, 14, 21, 35, 00).datetime,
                Arrow(2017, 11, 14, 22, 10, 00).datetime,
                Arrow(2017, 11, 14, 22, 43, 00).datetime,
                Arrow(2017, 11, 14, 22, 58, 00).datetime
            ],
            "open_rate": [0.002543, 0.003003, 0.003089, 0.003214],
            "close_rate": [0.002546, 0.003014, 0.003103, 0.003217],
            "trade_duration": [123, 34, 31, 14],
            "is_open": [False, False, False, True],
            "stake_amount": [0.01, 0.01, 0.01, 0.01],
            "sell_reason": [
                SellType.ROI, SellType.STOP_LOSS, SellType.ROI,
                SellType.FORCE_SELL
            ]
        }),
        'config':
        hyperopt.config,
        'locks': [],
        'final_balance':
        0.02,
        'backtest_start_time':
        1619718665,
        'backtest_end_time':
        1619718665,
    }
    results_metrics = generate_strategy_stats({'XRP/BTC': None},
                                              '',
                                              bt_result,
                                              Arrow(2017, 11, 14, 19, 32, 00),
                                              Arrow(2017, 12, 14, 19, 32, 00),
                                              market_change=0)

    results_explanation = HyperoptTools.format_results_explanation_string(
        results_metrics, 'BTC')
    total_profit = results_metrics['profit_total_abs']

    results = {
        'loss': 0.0,
        'params_dict': None,
        'params_details': None,
        'results_metrics': results_metrics,
        'results_explanation': results_explanation,
        'total_profit': total_profit,
        'current_epoch': 1,
        'is_initial_point': True,
    }

    result = HyperoptTools._format_explanation_string(results, 1)
    assert ' 0.71%' in result
    assert 'Total profit  0.00003100 BTC' in result
    assert '0:50:00 min' in result
Exemplo n.º 26
0
def test_load_previous_results2(mocker, testdatadir, caplog) -> None:
    mocker.patch('freqtrade.optimize.hyperopt_tools.HyperoptTools._read_results_pickle',
                 return_value=[{'asdf': '222'}])
    results_file = testdatadir / 'hyperopt_results_SampleStrategy.pickle'
    with pytest.raises(OperationalException, match=r"The file .* incompatible.*"):
        HyperoptTools.load_previous_results(results_file)
Exemplo n.º 27
0
    def __init__(self, config: Dict[str, Any]) -> None:
        self.buy_space: List[Dimension] = []
        self.sell_space: List[Dimension] = []
        self.roi_space: List[Dimension] = []
        self.stoploss_space: List[Dimension] = []
        self.trailing_space: List[Dimension] = []
        self.dimensions: List[Dimension] = []

        self.config = config

        self.backtesting = Backtesting(self.config)

        if not self.config.get('hyperopt'):
            self.custom_hyperopt = HyperOptAuto(self.config)
        else:
            self.custom_hyperopt = HyperOptResolver.load_hyperopt(self.config)
        self.custom_hyperopt.strategy = self.backtesting.strategy

        self.custom_hyperoptloss = HyperOptLossResolver.load_hyperoptloss(
            self.config)
        self.calculate_loss = self.custom_hyperoptloss.hyperopt_loss_function
        time_now = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
        strategy = str(self.config['strategy'])
        self.results_file: Path = (
            self.config['user_data_dir'] / 'hyperopt_results' /
            f'strategy_{strategy}_hyperopt_results_{time_now}.pickle')
        self.data_pickle_file = (self.config['user_data_dir'] /
                                 'hyperopt_results' /
                                 'hyperopt_tickerdata.pkl')
        self.total_epochs = config.get('epochs', 0)

        self.current_best_loss = 100

        self.clean_hyperopt()

        self.num_epochs_saved = 0

        # Previous evaluations
        self.epochs: List = []

        # Populate functions here (hasattr is slow so should not be run during "regular" operations)
        if hasattr(self.custom_hyperopt, 'populate_indicators'):
            self.backtesting.strategy.advise_indicators = (  # type: ignore
                self.custom_hyperopt.populate_indicators)  # type: ignore
        if hasattr(self.custom_hyperopt, 'populate_buy_trend'):
            self.backtesting.strategy.advise_buy = (  # type: ignore
                self.custom_hyperopt.populate_buy_trend)  # type: ignore
        if hasattr(self.custom_hyperopt, 'populate_sell_trend'):
            self.backtesting.strategy.advise_sell = (  # type: ignore
                self.custom_hyperopt.populate_sell_trend)  # type: ignore

        # Use max_open_trades for hyperopt as well, except --disable-max-market-positions is set
        if self.config.get('use_max_market_positions', True):
            self.max_open_trades = self.config['max_open_trades']
        else:
            logger.debug(
                'Ignoring max_open_trades (--disable-max-market-positions was used) ...'
            )
            self.max_open_trades = 0
        self.position_stacking = self.config.get('position_stacking', False)

        if HyperoptTools.has_space(self.config, 'sell'):
            # Make sure use_sell_signal is enabled
            if 'ask_strategy' not in self.config:
                self.config['ask_strategy'] = {}
            self.config['ask_strategy']['use_sell_signal'] = True

        self.print_all = self.config.get('print_all', False)
        self.hyperopt_table_header = 0
        self.print_colorized = self.config.get('print_colorized', False)
        self.print_json = self.config.get('print_json', False)
Exemplo n.º 28
0
def test_load_previous_results2(mocker, testdatadir, caplog) -> None:
    results_file = testdatadir / 'hyperopt_results_SampleStrategy.pickle'
    with pytest.raises(OperationalException,
                       match=r"Legacy hyperopt results are no longer supported.*"):
        HyperoptTools.load_filtered_results(results_file, {})