Exemplo n.º 1
0
def generate_backtest_stats(btdata: Dict[str, DataFrame],
                            all_results: Dict[str, Dict[str, Union[DataFrame,
                                                                   Dict]]],
                            min_date: datetime,
                            max_date: datetime) -> Dict[str, Any]:
    """
    :param btdata: Backtest data
    :param all_results: backtest result - dictionary in the form:
                     { Strategy: {'results: results, 'config: config}}.
    :param min_date: Backtest start date
    :param max_date: Backtest end date
    :return: Dictionary containing results per strategy and a strategy summary.
    """
    result: Dict[str, Any] = {'strategy': {}}
    market_change = calculate_market_change(btdata, 'close')

    for strategy, content in all_results.items():
        strat_stats = generate_strategy_stats(btdata,
                                              strategy,
                                              content,
                                              min_date,
                                              max_date,
                                              market_change=market_change)
        result['strategy'][strategy] = strat_stats

    strategy_results = generate_strategy_comparison(all_results=all_results)

    result['strategy_comparison'] = strategy_results

    return result
Exemplo n.º 2
0
def generate_backtest_stats(btdata: Dict[str, DataFrame],
                            all_results: Dict[str, Dict[str, Union[DataFrame,
                                                                   Dict]]],
                            min_date: datetime,
                            max_date: datetime) -> Dict[str, Any]:
    """
    :param btdata: Backtest data
    :param all_results: backtest result - dictionary in the form:
                     { Strategy: {'results: results, 'config: config}}.
    :param min_date: Backtest start date
    :param max_date: Backtest end date
    :return: Dictionary containing results per strategy and a strategy summary.
    """
    result: Dict[str, Any] = {
        'metadata': {},
        'strategy': {},
        'strategy_comparison': [],
    }
    market_change = calculate_market_change(btdata, 'close')
    metadata = {}
    pairlist = list(btdata.keys())
    for strategy, content in all_results.items():
        strat_stats = generate_strategy_stats(pairlist,
                                              strategy,
                                              content,
                                              min_date,
                                              max_date,
                                              market_change=market_change)
        metadata[strategy] = {
            'run_id': content['run_id'],
            'backtest_start_time': content['backtest_start_time'],
        }
        result['strategy'][strategy] = strat_stats

    strategy_results = generate_strategy_comparison(
        bt_stats=result['strategy'])

    result['metadata'] = metadata
    result['strategy_comparison'] = strategy_results

    return result
Exemplo n.º 3
0
def generate_backtest_stats(btdata: Dict[str, DataFrame],
                            all_results: Dict[str, Dict[str, Union[DataFrame, Dict]]],
                            min_date: Arrow, max_date: Arrow
                            ) -> Dict[str, Any]:
    """
    :param btdata: Backtest data
    :param all_results: backtest result - dictionary in the form:
                     { Strategy: {'results: results, 'config: config}}.
    :param min_date: Backtest start date
    :param max_date: Backtest end date
    :return:
    Dictionary containing results per strategy and a stratgy summary.
    """
    result: Dict[str, Any] = {'strategy': {}}
    market_change = calculate_market_change(btdata, 'close')

    for strategy, content in all_results.items():
        results: Dict[str, DataFrame] = content['results']
        if not isinstance(results, DataFrame):
            continue
        config = content['config']
        max_open_trades = config['max_open_trades']
        stake_currency = config['stake_currency']

        pair_results = generate_pair_metrics(btdata, stake_currency=stake_currency,
                                             max_open_trades=max_open_trades,
                                             results=results, skip_nan=False)
        sell_reason_stats = generate_sell_reason_stats(max_open_trades=max_open_trades,
                                                       results=results)
        left_open_results = generate_pair_metrics(btdata, stake_currency=stake_currency,
                                                  max_open_trades=max_open_trades,
                                                  results=results.loc[results['open_at_end']],
                                                  skip_nan=True)
        daily_stats = generate_daily_stats(results)

        results['open_timestamp'] = results['open_date'].astype(int64) // 1e6
        results['close_timestamp'] = results['close_date'].astype(int64) // 1e6

        backtest_days = (max_date - min_date).days
        strat_stats = {
            'trades': results.to_dict(orient='records'),
            'results_per_pair': pair_results,
            'sell_reason_summary': sell_reason_stats,
            'left_open_trades': left_open_results,
            'total_trades': len(results),
            'profit_mean': results['profit_percent'].mean() if len(results) > 0 else 0,
            'profit_total': results['profit_percent'].sum(),
            'profit_total_abs': results['profit_abs'].sum(),
            'backtest_start': min_date.datetime,
            'backtest_start_ts': min_date.int_timestamp * 1000,
            'backtest_end': max_date.datetime,
            'backtest_end_ts': max_date.int_timestamp * 1000,
            'backtest_days': backtest_days,

            'trades_per_day': round(len(results) / backtest_days, 2) if backtest_days > 0 else 0,
            'market_change': market_change,
            'pairlist': list(btdata.keys()),
            'stake_amount': config['stake_amount'],
            'stake_currency': config['stake_currency'],
            'max_open_trades': (config['max_open_trades']
                                if config['max_open_trades'] != float('inf') else -1),
            'timeframe': config['timeframe'],
            # Parameters relevant for backtesting
            'stoploss': config['stoploss'],
            'trailing_stop': config.get('trailing_stop', False),
            'trailing_stop_positive': config.get('trailing_stop_positive'),
            'trailing_stop_positive_offset': config.get('trailing_stop_positive_offset', 0.0),
            'trailing_only_offset_is_reached': config.get('trailing_only_offset_is_reached', False),
            'minimal_roi': config['minimal_roi'],
            'use_sell_signal': config['ask_strategy']['use_sell_signal'],
            'sell_profit_only': config['ask_strategy']['sell_profit_only'],
            'ignore_roi_if_buy_signal': config['ask_strategy']['ignore_roi_if_buy_signal'],
            **daily_stats,
        }
        result['strategy'][strategy] = strat_stats

        try:
            max_drawdown, drawdown_start, drawdown_end = calculate_max_drawdown(
                results, value_col='profit_percent')
            strat_stats.update({
                'max_drawdown': max_drawdown,
                'drawdown_start': drawdown_start,
                'drawdown_start_ts': drawdown_start.timestamp() * 1000,
                'drawdown_end': drawdown_end,
                'drawdown_end_ts': drawdown_end.timestamp() * 1000,
            })
        except ValueError:
            strat_stats.update({
                'max_drawdown': 0.0,
                'drawdown_start': datetime(1970, 1, 1, tzinfo=timezone.utc),
                'drawdown_start_ts': 0,
                'drawdown_end': datetime(1970, 1, 1, tzinfo=timezone.utc),
                'drawdown_end_ts': 0,
            })

    strategy_results = generate_strategy_metrics(all_results=all_results)

    result['strategy_comparison'] = strategy_results

    return result
Exemplo n.º 4
0
def test_calculate_market_change(testdatadir):
    pairs = ["ETH/BTC", "ADA/BTC"]
    data = load_data(datadir=testdatadir, pairs=pairs, timeframe='5m')
    result = calculate_market_change(data)
    assert isinstance(result, float)
    assert pytest.approx(result) == 0.00955514
Exemplo n.º 5
0
def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame],
                            all_results: Dict[str, DataFrame], min_date: Arrow,
                            max_date: Arrow) -> Dict[str, Any]:
    """
    :param config: Configuration object used for backtest
    :param btdata: Backtest data
    :param all_results: backtest result - dictionary with { Strategy: results}.
    :param min_date: Backtest start date
    :param max_date: Backtest end date
    :return:
    Dictionary containing results per strategy and a stratgy summary.
    """
    stake_currency = config['stake_currency']
    max_open_trades = config['max_open_trades']
    result: Dict[str, Any] = {'strategy': {}}
    market_change = calculate_market_change(btdata, 'close')

    for strategy, results in all_results.items():

        pair_results = generate_pair_metrics(btdata,
                                             stake_currency=stake_currency,
                                             max_open_trades=max_open_trades,
                                             results=results,
                                             skip_nan=False)
        sell_reason_stats = generate_sell_reason_stats(
            max_open_trades=max_open_trades, results=results)
        left_open_results = generate_pair_metrics(
            btdata,
            stake_currency=stake_currency,
            max_open_trades=max_open_trades,
            results=results.loc[results['open_at_end']],
            skip_nan=True)
        daily_stats = generate_daily_stats(results)

        results['open_timestamp'] = results['open_date'].astype(int64) // 1e6
        results['close_timestamp'] = results['close_date'].astype(int64) // 1e6

        backtest_days = (max_date - min_date).days
        strat_stats = {
            'trades':
            results.to_dict(orient='records'),
            'results_per_pair':
            pair_results,
            'sell_reason_summary':
            sell_reason_stats,
            'left_open_trades':
            left_open_results,
            'total_trades':
            len(results),
            'profit_mean':
            results['profit_percent'].mean() if len(results) > 0 else 0,
            'profit_total':
            results['profit_percent'].sum(),
            'profit_total_abs':
            results['profit_abs'].sum(),
            'backtest_start':
            min_date.datetime,
            'backtest_start_ts':
            min_date.timestamp * 1000,
            'backtest_end':
            max_date.datetime,
            'backtest_end_ts':
            max_date.timestamp * 1000,
            'backtest_days':
            backtest_days,
            'trades_per_day':
            round(len(results) / backtest_days, 2) if backtest_days > 0 else 0,
            'market_change':
            market_change,
            'pairlist':
            list(btdata.keys()),
            'stake_amount':
            config['stake_amount'],
            'stake_currency':
            config['stake_currency'],
            'max_open_trades':
            (config['max_open_trades']
             if config['max_open_trades'] != float('inf') else -1),
            'timeframe':
            config['timeframe'],
            **daily_stats,
        }
        result['strategy'][strategy] = strat_stats

        try:
            max_drawdown, drawdown_start, drawdown_end = calculate_max_drawdown(
                results, value_col='profit_percent')
            strat_stats.update({
                'max_drawdown':
                max_drawdown,
                'drawdown_start':
                drawdown_start,
                'drawdown_start_ts':
                drawdown_start.timestamp() * 1000,
                'drawdown_end':
                drawdown_end,
                'drawdown_end_ts':
                drawdown_end.timestamp() * 1000,
            })
        except ValueError:
            strat_stats.update({
                'max_drawdown':
                0.0,
                'drawdown_start':
                datetime(1970, 1, 1, tzinfo=timezone.utc),
                'drawdown_start_ts':
                0,
                'drawdown_end':
                datetime(1970, 1, 1, tzinfo=timezone.utc),
                'drawdown_end_ts':
                0,
            })

    strategy_results = generate_strategy_metrics(
        stake_currency=stake_currency,
        max_open_trades=max_open_trades,
        all_results=all_results)

    result['strategy_comparison'] = strategy_results

    return result
Exemplo n.º 6
0
def generate_backtest_stats(btdata: Dict[str, DataFrame],
                            all_results: Dict[str, Dict[str, Union[DataFrame,
                                                                   Dict]]],
                            min_date: Arrow,
                            max_date: Arrow) -> Dict[str, Any]:
    """
    :param btdata: Backtest data
    :param all_results: backtest result - dictionary in the form:
                     { Strategy: {'results: results, 'config: config}}.
    :param min_date: Backtest start date
    :param max_date: Backtest end date
    :return:
    Dictionary containing results per strategy and a stratgy summary.
    """
    result: Dict[str, Any] = {'strategy': {}}
    market_change = calculate_market_change(btdata, 'close')

    for strategy, content in all_results.items():
        results: Dict[str, DataFrame] = content['results']
        if not isinstance(results, DataFrame):
            continue
        config = content['config']
        max_open_trades = min(config['max_open_trades'], len(btdata.keys()))
        starting_balance = config['dry_run_wallet']
        stake_currency = config['stake_currency']

        pair_results = generate_pair_metrics(btdata,
                                             stake_currency=stake_currency,
                                             starting_balance=starting_balance,
                                             results=results,
                                             skip_nan=False)
        sell_reason_stats = generate_sell_reason_stats(
            max_open_trades=max_open_trades, results=results)
        left_open_results = generate_pair_metrics(
            btdata,
            stake_currency=stake_currency,
            starting_balance=starting_balance,
            results=results.loc[results['is_open']],
            skip_nan=True)
        daily_stats = generate_daily_stats(results)
        best_pair = max(
            [pair for pair in pair_results if pair['key'] != 'TOTAL'],
            key=lambda x: x['profit_sum']) if len(pair_results) > 1 else None
        worst_pair = min(
            [pair for pair in pair_results if pair['key'] != 'TOTAL'],
            key=lambda x: x['profit_sum']) if len(pair_results) > 1 else None
        results['open_timestamp'] = results['open_date'].astype(int64) // 1e6
        results['close_timestamp'] = results['close_date'].astype(int64) // 1e6

        backtest_days = (max_date - min_date).days
        strat_stats = {
            'trades':
            results.to_dict(orient='records'),
            'locks': [lock.to_json() for lock in content['locks']],
            'best_pair':
            best_pair,
            'worst_pair':
            worst_pair,
            'results_per_pair':
            pair_results,
            'sell_reason_summary':
            sell_reason_stats,
            'left_open_trades':
            left_open_results,
            'total_trades':
            len(results),
            'total_volume':
            float(results['stake_amount'].sum()),
            'avg_stake_amount':
            results['stake_amount'].mean() if len(results) > 0 else 0,
            'profit_mean':
            results['profit_ratio'].mean() if len(results) > 0 else 0,
            'profit_total':
            results['profit_abs'].sum() / starting_balance,
            'profit_total_abs':
            results['profit_abs'].sum(),
            'backtest_start':
            min_date.datetime,
            'backtest_start_ts':
            min_date.int_timestamp * 1000,
            'backtest_end':
            max_date.datetime,
            'backtest_end_ts':
            max_date.int_timestamp * 1000,
            'backtest_days':
            backtest_days,
            'backtest_run_start_ts':
            content['backtest_start_time'],
            'backtest_run_end_ts':
            content['backtest_end_time'],
            'trades_per_day':
            round(len(results) / backtest_days, 2) if backtest_days > 0 else 0,
            'market_change':
            market_change,
            'pairlist':
            list(btdata.keys()),
            'stake_amount':
            config['stake_amount'],
            'stake_currency':
            config['stake_currency'],
            'stake_currency_decimals':
            decimals_per_coin(config['stake_currency']),
            'starting_balance':
            starting_balance,
            'dry_run_wallet':
            starting_balance,
            'final_balance':
            content['final_balance'],
            'max_open_trades':
            max_open_trades,
            'max_open_trades_setting':
            (config['max_open_trades']
             if config['max_open_trades'] != float('inf') else -1),
            'timeframe':
            config['timeframe'],
            'timerange':
            config.get('timerange', ''),
            'enable_protections':
            config.get('enable_protections', False),
            'strategy_name':
            strategy,
            # Parameters relevant for backtesting
            'stoploss':
            config['stoploss'],
            'trailing_stop':
            config.get('trailing_stop', False),
            'trailing_stop_positive':
            config.get('trailing_stop_positive'),
            'trailing_stop_positive_offset':
            config.get('trailing_stop_positive_offset', 0.0),
            'trailing_only_offset_is_reached':
            config.get('trailing_only_offset_is_reached', False),
            'use_custom_stoploss':
            config.get('use_custom_stoploss', False),
            'minimal_roi':
            config['minimal_roi'],
            'use_sell_signal':
            config['ask_strategy']['use_sell_signal'],
            'sell_profit_only':
            config['ask_strategy']['sell_profit_only'],
            'sell_profit_offset':
            config['ask_strategy']['sell_profit_offset'],
            'ignore_roi_if_buy_signal':
            config['ask_strategy']['ignore_roi_if_buy_signal'],
            **daily_stats,
        }
        result['strategy'][strategy] = strat_stats

        try:
            max_drawdown, _, _, _, _ = calculate_max_drawdown(
                results, value_col='profit_ratio')
            drawdown_abs, drawdown_start, drawdown_end, high_val, low_val = calculate_max_drawdown(
                results, value_col='profit_abs')
            strat_stats.update({
                'max_drawdown':
                max_drawdown,
                'max_drawdown_abs':
                drawdown_abs,
                'drawdown_start':
                drawdown_start,
                'drawdown_start_ts':
                drawdown_start.timestamp() * 1000,
                'drawdown_end':
                drawdown_end,
                'drawdown_end_ts':
                drawdown_end.timestamp() * 1000,
                'max_drawdown_low':
                low_val,
                'max_drawdown_high':
                high_val,
            })

            csum_min, csum_max = calculate_csum(results, starting_balance)
            strat_stats.update({'csum_min': csum_min, 'csum_max': csum_max})

        except ValueError:
            strat_stats.update({
                'max_drawdown':
                0.0,
                'max_drawdown_abs':
                0.0,
                'max_drawdown_low':
                0.0,
                'max_drawdown_high':
                0.0,
                'drawdown_start':
                datetime(1970, 1, 1, tzinfo=timezone.utc),
                'drawdown_start_ts':
                0,
                'drawdown_end':
                datetime(1970, 1, 1, tzinfo=timezone.utc),
                'drawdown_end_ts':
                0,
                'csum_min':
                0,
                'csum_max':
                0
            })

    strategy_results = generate_strategy_metrics(all_results=all_results)

    result['strategy_comparison'] = strategy_results

    return result