Ejemplo n.º 1
0
    def start(self) -> None:
        """
        Run backtesting end-to-end
        :return: None
        """
        data: Dict[str, Any] = {}

        data, timerange = self.load_bt_data()

        min_date = None
        max_date = None
        for strat in self.strategylist:
            min_date, max_date = self.backtest_one_strategy(
                strat, data, timerange)

        stats = generate_backtest_stats(data,
                                        self.all_results,
                                        min_date=min_date,
                                        max_date=max_date)

        if self.config.get('export', False):
            store_backtest_stats(self.config['exportfilename'], stats)

        # Show backtest results
        show_backtest_results(self.config, stats)
Ejemplo n.º 2
0
    def start(self) -> None:
        """
        Run backtesting end-to-end
        :return: None
        """
        data: Dict[str, Any] = {}

        data, timerange = self.load_bt_data()
        self.load_bt_data_detail()
        logger.info("Dataload complete. Calculating indicators")

        for strat in self.strategylist:
            min_date, max_date = self.backtest_one_strategy(
                strat, data, timerange)
        if len(self.strategylist) > 0:

            self.results = generate_backtest_stats(data,
                                                   self.all_results,
                                                   min_date=min_date,
                                                   max_date=max_date)

            if self.config.get('export', 'none') == 'trades':
                store_backtest_stats(self.config['exportfilename'],
                                     self.results)

            # Show backtest results
            show_backtest_results(self.config, self.results)
Ejemplo n.º 3
0
    def start(self) -> None:
        """
        Run backtesting end-to-end
        :return: None
        """
        data: Dict[str, Any] = {}

        data, timerange = self.load_bt_data()
        self.load_bt_data_detail()
        logger.info("Dataload complete. Calculating indicators")

        self.load_prior_backtest()

        for strat in self.strategylist:
            if self.results and strat.get_strategy_name(
            ) in self.results['strategy']:
                # When previous result hash matches - reuse that result and skip backtesting.
                logger.info(
                    f'Reusing result of previous backtest for {strat.get_strategy_name()}'
                )
                continue
            min_date, max_date = self.backtest_one_strategy(
                strat, data, timerange)

        # Update old results with new ones.
        if len(self.all_results) > 0:
            results = generate_backtest_stats(data,
                                              self.all_results,
                                              min_date=min_date,
                                              max_date=max_date)
            if self.results:
                self.results['metadata'].update(results['metadata'])
                self.results['strategy'].update(results['strategy'])
                self.results['strategy_comparison'].extend(
                    results['strategy_comparison'])
            else:
                self.results = results

            if self.config.get('export', 'none') == 'trades':
                store_backtest_stats(self.config['exportfilename'],
                                     self.results)

        # Results may be mixed up now. Sort them so they follow --strategy-list order.
        if 'strategy_list' in self.config and len(self.results) > 0:
            self.results['strategy_comparison'] = sorted(
                self.results['strategy_comparison'],
                key=lambda c: self.config['strategy_list'].index(c['key']))
            self.results['strategy'] = dict(
                sorted(
                    self.results['strategy'].items(),
                    key=lambda kv: self.config['strategy_list'].index(kv[0])))

        if len(self.strategylist) > 0:
            # Show backtest results
            show_backtest_results(self.config, self.results)
Ejemplo n.º 4
0
def test_store_backtest_stats(testdatadir, mocker):

    dump_mock = mocker.patch('freqtrade.optimize.optimize_reports.file_dump_json')

    store_backtest_stats(testdatadir, {})

    assert dump_mock.call_count == 2
    assert isinstance(dump_mock.call_args_list[0][0][0], Path)
    assert str(dump_mock.call_args_list[0][0][0]).startswith(str(testdatadir/'backtest-result'))

    dump_mock.reset_mock()
    filename = testdatadir / 'testresult.json'
    store_backtest_stats(filename, {})
    assert dump_mock.call_count == 2
    assert isinstance(dump_mock.call_args_list[0][0][0], Path)
    # result will be testdatadir / testresult-<timestamp>.json
    assert str(dump_mock.call_args_list[0][0][0]).startswith(str(testdatadir / 'testresult'))
Ejemplo n.º 5
0
def test_generate_backtest_stats(default_conf, testdatadir):
    default_conf.update({'strategy': 'DefaultStrategy'})
    StrategyResolver.load_strategy(default_conf)

    results = {
        'DefStrat': {
            '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],
                "sell_reason": [
                    SellType.ROI, SellType.STOP_LOSS, SellType.ROI,
                    SellType.FORCE_SELL
                ]
            }),
            'config':
            default_conf,
            'locks': [],
            'backtest_start_time':
            Arrow.utcnow().int_timestamp,
            'backtest_end_time':
            Arrow.utcnow().int_timestamp,
        }
    }
    timerange = TimeRange.parse_timerange('1510688220-1510700340')
    min_date = Arrow.fromtimestamp(1510688220)
    max_date = Arrow.fromtimestamp(1510700340)
    btdata = history.load_data(testdatadir,
                               '1m', ['UNITTEST/BTC'],
                               timerange=timerange,
                               fill_up_missing=True)

    stats = generate_backtest_stats(btdata, results, min_date, max_date)
    assert isinstance(stats, dict)
    assert 'strategy' in stats
    assert 'DefStrat' in stats['strategy']
    assert 'strategy_comparison' in stats
    strat_stats = stats['strategy']['DefStrat']
    assert strat_stats['backtest_start'] == min_date.datetime
    assert strat_stats['backtest_end'] == max_date.datetime
    assert strat_stats['total_trades'] == len(results['DefStrat']['results'])
    # Above sample had no loosing trade
    assert strat_stats['max_drawdown'] == 0.0

    results = {
        'DefStrat': {
            '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.0032903, 0.003217],
                "trade_duration": [123, 34, 31, 14],
                "open_at_end": [False, False, False, True],
                "sell_reason": [
                    SellType.ROI, SellType.STOP_LOSS, SellType.ROI,
                    SellType.FORCE_SELL
                ]
            }),
            'config':
            default_conf
        }
    }

    assert strat_stats['max_drawdown'] == 0.0
    assert strat_stats['drawdown_start'] == datetime(1970,
                                                     1,
                                                     1,
                                                     tzinfo=timezone.utc)
    assert strat_stats['drawdown_end'] == datetime(1970,
                                                   1,
                                                   1,
                                                   tzinfo=timezone.utc)
    assert strat_stats['drawdown_end_ts'] == 0
    assert strat_stats['drawdown_start_ts'] == 0
    assert strat_stats['pairlist'] == ['UNITTEST/BTC']

    # Test storing stats
    filename = Path(testdatadir / 'btresult.json')
    filename_last = Path(testdatadir / LAST_BT_RESULT_FN)
    _backup_file(filename_last, copy_file=True)
    assert not filename.is_file()

    store_backtest_stats(filename, stats)

    # get real Filename (it's btresult-<date>.json)
    last_fn = get_latest_backtest_filename(filename_last.parent)
    assert re.match(r"btresult-.*\.json", last_fn)

    filename1 = (testdatadir / last_fn)
    assert filename1.is_file()
    content = filename1.read_text()
    assert 'max_drawdown' in content
    assert 'strategy' in content
    assert 'pairlist' in content

    assert filename_last.is_file()

    _clean_test_file(filename_last)
    filename1.unlink()
Ejemplo n.º 6
0
    def run_backtest():
        from freqtrade.optimize.optimize_reports import (
            generate_backtest_stats, store_backtest_stats)
        from freqtrade.resolvers import StrategyResolver
        asyncio.set_event_loop(asyncio.new_event_loop())
        try:
            # Reload strategy
            lastconfig = ApiServer._bt_last_config
            strat = StrategyResolver.load_strategy(btconfig)
            validate_config_consistency(btconfig)

            if (not ApiServer._bt
                    or lastconfig.get('timeframe') != strat.timeframe
                    or lastconfig.get('timeframe_detail') !=
                    btconfig.get('timeframe_detail')
                    or lastconfig.get('timerange') != btconfig['timerange']):
                from freqtrade.optimize.backtesting import Backtesting
                ApiServer._bt = Backtesting(btconfig)
                if ApiServer._bt.timeframe_detail:
                    ApiServer._bt.load_bt_data_detail()
            else:
                ApiServer._bt.config = btconfig
                ApiServer._bt.init_backtest()
            # Only reload data if timeframe changed.
            if (not ApiServer._bt_data or not ApiServer._bt_timerange
                    or lastconfig.get('timeframe') != strat.timeframe
                    or lastconfig.get('timerange') != btconfig['timerange']):
                ApiServer._bt_data, ApiServer._bt_timerange = ApiServer._bt.load_bt_data(
                )

            lastconfig['timerange'] = btconfig['timerange']
            lastconfig['timeframe'] = strat.timeframe
            lastconfig['protections'] = btconfig.get('protections', [])
            lastconfig['enable_protections'] = btconfig.get(
                'enable_protections')
            lastconfig['dry_run_wallet'] = btconfig.get('dry_run_wallet')

            ApiServer._bt.results = {}
            ApiServer._bt.load_prior_backtest()

            ApiServer._bt.abort = False
            if (ApiServer._bt.results and strat.get_strategy_name()
                    in ApiServer._bt.results['strategy']):
                # When previous result hash matches - reuse that result and skip backtesting.
                logger.info(
                    f'Reusing result of previous backtest for {strat.get_strategy_name()}'
                )
            else:
                min_date, max_date = ApiServer._bt.backtest_one_strategy(
                    strat, ApiServer._bt_data, ApiServer._bt_timerange)

                ApiServer._bt.results = generate_backtest_stats(
                    ApiServer._bt_data,
                    ApiServer._bt.all_results,
                    min_date=min_date,
                    max_date=max_date)

            if btconfig.get('export', 'none') == 'trades':
                store_backtest_stats(btconfig['exportfilename'],
                                     ApiServer._bt.results)

            logger.info("Backtest finished.")

        except DependencyException as e:
            logger.info(f"Backtesting caused an error: {e}")
            pass
        finally:
            ApiServer._bgtask_running = False
Ejemplo n.º 7
0
def test_generate_backtest_stats(default_conf, testdatadir, tmpdir):
    default_conf.update({'strategy': CURRENT_TEST_STRATEGY})
    StrategyResolver.load_strategy(default_conf)

    results = {
        'DefStrat': {
            '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],
                "is_short": [False, False, False, False],
                "stake_amount": [0.01, 0.01, 0.01, 0.01],
                "exit_reason": [
                    ExitType.ROI, ExitType.STOP_LOSS, ExitType.ROI,
                    ExitType.FORCE_EXIT
                ]
            }),
            'config':
            default_conf,
            'locks': [],
            'final_balance':
            1000.02,
            'rejected_signals':
            20,
            'timedout_entry_orders':
            0,
            'timedout_exit_orders':
            0,
            'backtest_start_time':
            Arrow.utcnow().int_timestamp,
            'backtest_end_time':
            Arrow.utcnow().int_timestamp,
            'run_id':
            '123',
        }
    }
    timerange = TimeRange.parse_timerange('1510688220-1510700340')
    min_date = Arrow.fromtimestamp(1510688220)
    max_date = Arrow.fromtimestamp(1510700340)
    btdata = history.load_data(testdatadir,
                               '1m', ['UNITTEST/BTC'],
                               timerange=timerange,
                               fill_up_missing=True)

    stats = generate_backtest_stats(btdata, results, min_date, max_date)
    assert isinstance(stats, dict)
    assert 'strategy' in stats
    assert 'DefStrat' in stats['strategy']
    assert 'strategy_comparison' in stats
    strat_stats = stats['strategy']['DefStrat']
    assert strat_stats['backtest_start'] == min_date.strftime(
        DATETIME_PRINT_FORMAT)
    assert strat_stats['backtest_end'] == max_date.strftime(
        DATETIME_PRINT_FORMAT)
    assert strat_stats['total_trades'] == len(results['DefStrat']['results'])
    # Above sample had no loosing trade
    assert strat_stats['max_drawdown_account'] == 0.0

    # Retry with losing trade
    results = {
        'DefStrat': {
            '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.0032903, 0.003217],
                "trade_duration": [123, 34, 31, 14],
                "is_open": [False, False, False, True],
                "is_short": [False, False, False, False],
                "stake_amount": [0.01, 0.01, 0.01, 0.01],
                "exit_reason": [
                    ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS,
                    ExitType.FORCE_EXIT
                ]
            }),
            'config':
            default_conf,
            'locks': [],
            'final_balance':
            1000.02,
            'rejected_signals':
            20,
            'timedout_entry_orders':
            0,
            'timedout_exit_orders':
            0,
            'backtest_start_time':
            Arrow.utcnow().int_timestamp,
            'backtest_end_time':
            Arrow.utcnow().int_timestamp,
            'run_id':
            '124',
        }
    }

    stats = generate_backtest_stats(btdata, results, min_date, max_date)
    assert isinstance(stats, dict)
    assert 'strategy' in stats
    assert 'DefStrat' in stats['strategy']
    assert 'strategy_comparison' in stats
    strat_stats = stats['strategy']['DefStrat']

    assert pytest.approx(strat_stats['max_drawdown_account']) == 1.399999e-08
    assert strat_stats['drawdown_start'] == '2017-11-14 22:10:00'
    assert strat_stats['drawdown_end'] == '2017-11-14 22:43:00'
    assert strat_stats['drawdown_end_ts'] == 1510699380000
    assert strat_stats['drawdown_start_ts'] == 1510697400000
    assert strat_stats['pairlist'] == ['UNITTEST/BTC']

    # Test storing stats
    filename = Path(tmpdir / 'btresult.json')
    filename_last = Path(tmpdir / LAST_BT_RESULT_FN)
    _backup_file(filename_last, copy_file=True)
    assert not filename.is_file()

    store_backtest_stats(filename, stats)

    # get real Filename (it's btresult-<date>.json)
    last_fn = get_latest_backtest_filename(filename_last.parent)
    assert re.match(r"btresult-.*\.json", last_fn)

    filename1 = Path(tmpdir / last_fn)
    assert filename1.is_file()
    content = filename1.read_text()
    assert 'max_drawdown_account' in content
    assert 'strategy' in content
    assert 'pairlist' in content

    assert filename_last.is_file()

    _clean_test_file(filename_last)
    filename1.unlink()
Ejemplo n.º 8
0
    def start(self) -> None:
        """
        Run backtesting end-to-end
        :return: None
        """
        data: Dict[str, Any] = {}

        logger.info('Using stake_currency: %s ...',
                    self.config['stake_currency'])
        logger.info('Using stake_amount: %s ...', self.config['stake_amount'])

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

        data, timerange = self.load_bt_data()

        all_results = {}
        for strat in self.strategylist:
            logger.info("Running backtesting for Strategy %s",
                        strat.get_strategy_name())
            self._set_strategy(strat)

            # need to reprocess data every time to populate signals
            preprocessed = self.strategy.ohlcvdata_to_dataframe(data)

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

            logger.info(
                f'Backtesting 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)..')
            # Execute backtest and print results
            all_results[self.strategy.get_strategy_name()] = self.backtest(
                processed=preprocessed,
                stake_amount=self.config['stake_amount'],
                start_date=min_date,
                end_date=max_date,
                max_open_trades=max_open_trades,
                position_stacking=position_stacking,
            )

        stats = generate_backtest_stats(self.config,
                                        data,
                                        all_results,
                                        min_date=min_date,
                                        max_date=max_date)
        if self.config.get('export', False):
            store_backtest_stats(self.config['exportfilename'], stats)

        # Show backtest results
        show_backtest_results(self.config, stats)