Add short/long metrics to backtest result

This commit is contained in:
Matthias 2021-11-18 20:41:37 +01:00
parent 0a50017c84
commit 5a8824171c
2 changed files with 72 additions and 47 deletions

View File

@ -371,42 +371,48 @@ The last element of the backtest report is the summary metrics table.
It contains some useful key metrics about performance of your strategy on backtesting data. It contains some useful key metrics about performance of your strategy on backtesting data.
``` ```
=============== SUMMARY METRICS =============== ================ SUMMARY METRICS ===============
| Metric | Value | | Metric | Value |
|-----------------------+---------------------| |------------------------+---------------------|
| Backtesting from | 2019-01-01 00:00:00 | | Backtesting from | 2019-01-01 00:00:00 |
| Backtesting to | 2019-05-01 00:00:00 | | Backtesting to | 2019-05-01 00:00:00 |
| Max open trades | 3 | | Max open trades | 3 |
| | | | | |
| Total/Daily Avg Trades| 429 / 3.575 | | Total/Daily Avg Trades | 429 / 3.575 |
| Starting balance | 0.01000000 BTC | | Starting balance | 0.01000000 BTC |
| Final balance | 0.01762792 BTC | | Final balance | 0.01762792 BTC |
| Absolute profit | 0.00762792 BTC | | Absolute profit | 0.00762792 BTC |
| Total profit % | 76.2% | | Total profit % | 76.2% |
| Avg. stake amount | 0.001 BTC | | Avg. stake amount | 0.001 BTC |
| Total trade volume | 0.429 BTC | | Total trade volume | 0.429 BTC |
| | | | | |
| Best Pair | LSK/BTC 26.26% | | Long / Short | 352 / 77 |
| Worst Pair | ZEC/BTC -10.18% | | Total profit Long % | 1250.58% |
| Best Trade | LSK/BTC 4.25% | | Total profit Short % | -15.02% |
| Worst Trade | ZEC/BTC -10.25% | | Absolute profit Long | 0.00838792 BTC |
| Best day | 0.00076 BTC | | Absolute profit Short | -0.00076 BTC |
| Worst day | -0.00036 BTC | | | |
| Days win/draw/lose | 12 / 82 / 25 | | Best Pair | LSK/BTC 26.26% |
| Avg. Duration Winners | 4:23:00 | | Worst Pair | ZEC/BTC -10.18% |
| Avg. Duration Loser | 6:55:00 | | Best Trade | LSK/BTC 4.25% |
| Rejected Buy signals | 3089 | | Worst Trade | ZEC/BTC -10.25% |
| | | | Best day | 0.00076 BTC |
| Min balance | 0.00945123 BTC | | Worst day | -0.00036 BTC |
| Max balance | 0.01846651 BTC | | Days win/draw/lose | 12 / 82 / 25 |
| Drawdown | 50.63% | | Avg. Duration Winners | 4:23:00 |
| Drawdown | 0.0015 BTC | | Avg. Duration Loser | 6:55:00 |
| Drawdown high | 0.0013 BTC | | Rejected Buy signals | 3089 |
| Drawdown low | -0.0002 BTC | | | |
| Drawdown Start | 2019-02-15 14:10:00 | | Min balance | 0.00945123 BTC |
| Drawdown End | 2019-04-11 18:15:00 | | Max balance | 0.01846651 BTC |
| Market change | -5.88% | | Drawdown | 50.63% |
=============================================== | Drawdown | 0.0015 BTC |
| Drawdown high | 0.0013 BTC |
| Drawdown low | -0.0002 BTC |
| Drawdown Start | 2019-02-15 14:10:00 |
| Drawdown End | 2019-04-11 18:15:00 |
| Market change | -5.88% |
================================================
``` ```
@ -430,6 +436,9 @@ It contains some useful key metrics about performance of your strategy on backte
- `Drawdown high` / `Drawdown low`: Profit at the beginning and end of the largest drawdown period. A negative low value means initial capital lost. - `Drawdown high` / `Drawdown low`: Profit at the beginning and end of the largest drawdown period. A negative low value means initial capital lost.
- `Drawdown Start` / `Drawdown End`: Start and end datetime for this largest drawdown (can also be visualized via the `plot-dataframe` sub-command). - `Drawdown Start` / `Drawdown End`: Start and end datetime for this largest drawdown (can also be visualized via the `plot-dataframe` sub-command).
- `Market change`: Change of the market during the backtest period. Calculated as average of all pairs changes from the first to the last candle using the "close" column. - `Market change`: Change of the market during the backtest period. Calculated as average of all pairs changes from the first to the last candle using the "close" column.
- `Long / Short`: Split long/short values (Only shown when short trades were made).
- `Total profit Long %` / `Absolute profit Long`: Profit long trades only (Only shown when short trades were made).
- `Total profit Short %` / `Absolute profit Short`: Profit short trades only (Only shown when short trades were made).
### Daily / Weekly / Monthly breakdown ### Daily / Weekly / Monthly breakdown

View File

@ -415,20 +415,20 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
return {} return {}
config = content['config'] config = content['config']
max_open_trades = min(config['max_open_trades'], len(btdata.keys())) max_open_trades = min(config['max_open_trades'], len(btdata.keys()))
starting_balance = config['dry_run_wallet'] start_balance = config['dry_run_wallet']
stake_currency = config['stake_currency'] stake_currency = config['stake_currency']
pair_results = generate_pair_metrics(btdata, stake_currency=stake_currency, pair_results = generate_pair_metrics(btdata, stake_currency=stake_currency,
starting_balance=starting_balance, starting_balance=start_balance,
results=results, skip_nan=False) results=results, skip_nan=False)
buy_tag_results = generate_tag_metrics("buy_tag", starting_balance=starting_balance, buy_tag_results = generate_tag_metrics("buy_tag", starting_balance=start_balance,
results=results, skip_nan=False) results=results, skip_nan=False)
sell_reason_stats = generate_sell_reason_stats(max_open_trades=max_open_trades, sell_reason_stats = generate_sell_reason_stats(max_open_trades=max_open_trades,
results=results) results=results)
left_open_results = generate_pair_metrics(btdata, stake_currency=stake_currency, left_open_results = generate_pair_metrics(btdata, stake_currency=stake_currency,
starting_balance=starting_balance, starting_balance=start_balance,
results=results.loc[results['is_open']], results=results.loc[results['is_open']],
skip_nan=True) skip_nan=True)
daily_stats = generate_daily_stats(results) daily_stats = generate_daily_stats(results)
@ -460,8 +460,12 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
'avg_stake_amount': results['stake_amount'].mean() if len(results) > 0 else 0, '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_mean': results['profit_ratio'].mean() if len(results) > 0 else 0,
'profit_median': results['profit_ratio'].median() if len(results) > 0 else 0, 'profit_median': results['profit_ratio'].median() if len(results) > 0 else 0,
'profit_total': results['profit_abs'].sum() / starting_balance, 'profit_total': results['profit_abs'].sum() / start_balance,
'profit_total_long': results.loc[~results['is_short'], 'profit_abs'].sum() / start_balance,
'profit_total_short': results.loc[results['is_short'], 'profit_abs'].sum() / start_balance,
'profit_total_abs': results['profit_abs'].sum(), 'profit_total_abs': results['profit_abs'].sum(),
'profit_total_long_abs': results.loc[~results['is_short'], 'profit_abs'].sum(),
'profit_total_short_abs': results.loc[results['is_short'], 'profit_abs'].sum(),
'backtest_start': min_date.strftime(DATETIME_PRINT_FORMAT), 'backtest_start': min_date.strftime(DATETIME_PRINT_FORMAT),
'backtest_start_ts': int(min_date.timestamp() * 1000), 'backtest_start_ts': int(min_date.timestamp() * 1000),
'backtest_end': max_date.strftime(DATETIME_PRINT_FORMAT), 'backtest_end': max_date.strftime(DATETIME_PRINT_FORMAT),
@ -477,8 +481,8 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
'stake_amount': config['stake_amount'], 'stake_amount': config['stake_amount'],
'stake_currency': config['stake_currency'], 'stake_currency': config['stake_currency'],
'stake_currency_decimals': decimals_per_coin(config['stake_currency']), 'stake_currency_decimals': decimals_per_coin(config['stake_currency']),
'starting_balance': starting_balance, 'starting_balance': start_balance,
'dry_run_wallet': starting_balance, 'dry_run_wallet': start_balance,
'final_balance': content['final_balance'], 'final_balance': content['final_balance'],
'rejected_signals': content['rejected_signals'], 'rejected_signals': content['rejected_signals'],
'max_open_trades': max_open_trades, 'max_open_trades': max_open_trades,
@ -522,7 +526,7 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
'max_drawdown_high': high_val, 'max_drawdown_high': high_val,
}) })
csum_min, csum_max = calculate_csum(results, starting_balance) csum_min, csum_max = calculate_csum(results, start_balance)
strat_stats.update({ strat_stats.update({
'csum_min': csum_min, 'csum_min': csum_min,
'csum_max': csum_max 'csum_max': csum_max
@ -711,6 +715,19 @@ def text_table_add_metrics(strat_results: Dict) -> str:
best_trade = max(strat_results['trades'], key=lambda x: x['profit_ratio']) best_trade = max(strat_results['trades'], key=lambda x: x['profit_ratio'])
worst_trade = min(strat_results['trades'], key=lambda x: x['profit_ratio']) worst_trade = min(strat_results['trades'], key=lambda x: x['profit_ratio'])
short_metrics = [
('', ''), # Empty line to improve readability
('Long / Short',
f"{strat_results.get('trade_count_long', 'total_trades')} / "
f"{strat_results.get('trade_count_short', 0)}"),
('Total profit Long %', f"{strat_results['profit_total_long']:.2%}"),
('Total profit Short %', f"{strat_results['profit_total_short']:.2%}"),
('Absolute profit Long', round_coin_value(strat_results['profit_total_long_abs'],
strat_results['stake_currency'])),
('Absolute profit Short', round_coin_value(strat_results['profit_total_short_abs'],
strat_results['stake_currency'])),
] if strat_results.get('trade_count_short', 0) > 0 else []
# Newly added fields should be ignored if they are missing in strat_results. hyperopt-show # Newly added fields should be ignored if they are missing in strat_results. hyperopt-show
# command stores these results and newer version of freqtrade must be able to handle old # command stores these results and newer version of freqtrade must be able to handle old
# results with missing new fields. # results with missing new fields.
@ -721,9 +738,7 @@ def text_table_add_metrics(strat_results: Dict) -> str:
('', ''), # Empty line to improve readability ('', ''), # Empty line to improve readability
('Total/Daily Avg Trades', ('Total/Daily Avg Trades',
f"{strat_results['total_trades']} / {strat_results['trades_per_day']}"), f"{strat_results['total_trades']} / {strat_results['trades_per_day']}"),
('Long / Short',
f"{strat_results.get('trade_count_long', 'total_trades')} / "
f"{strat_results.get('trade_count_short', 0)}"),
('Starting balance', round_coin_value(strat_results['starting_balance'], ('Starting balance', round_coin_value(strat_results['starting_balance'],
strat_results['stake_currency'])), strat_results['stake_currency'])),
('Final balance', round_coin_value(strat_results['final_balance'], ('Final balance', round_coin_value(strat_results['final_balance'],
@ -738,6 +753,7 @@ def text_table_add_metrics(strat_results: Dict) -> str:
strat_results['stake_currency'])), strat_results['stake_currency'])),
('Total trade volume', round_coin_value(strat_results['total_volume'], ('Total trade volume', round_coin_value(strat_results['total_volume'],
strat_results['stake_currency'])), strat_results['stake_currency'])),
*short_metrics,
('', ''), # Empty line to improve readability ('', ''), # Empty line to improve readability
('Best Pair', f"{strat_results['best_pair']['key']} " ('Best Pair', f"{strat_results['best_pair']['key']} "
f"{strat_results['best_pair']['profit_sum']:.2%}"), f"{strat_results['best_pair']['profit_sum']:.2%}"),