From ff819386e1ce2f03f63acb9601486fcf0280053e Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Fri, 7 Feb 2020 03:51:50 +0100 Subject: [PATCH] added draws to backtesting tables, reduced len of some labels to help fit this without increasing total width --- docs/backtesting.md | 72 ++++++++++++------------- freqtrade/optimize/optimize_reports.py | 25 +++++---- tests/optimize/test_optimize_reports.py | 62 ++++++++++----------- 3 files changed, 79 insertions(+), 80 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index 2abb32ca0..79bfa2350 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -119,40 +119,40 @@ A backtesting result will look like that: ``` ========================================================= BACKTESTING REPORT ======================================================== -| pair | buy count | avg profit % | cum profit % | tot profit BTC | tot profit % | avg duration | profit | loss | -|:---------|------------:|---------------:|---------------:|-----------------:|---------------:|:---------------|---------:|-------:| -| ADA/BTC | 35 | -0.11 | -3.88 | -0.00019428 | -1.94 | 4:35:00 | 14 | 21 | -| ARK/BTC | 11 | -0.41 | -4.52 | -0.00022647 | -2.26 | 2:03:00 | 3 | 8 | -| BTS/BTC | 32 | 0.31 | 9.78 | 0.00048938 | 4.89 | 5:05:00 | 18 | 14 | -| DASH/BTC | 13 | -0.08 | -1.07 | -0.00005343 | -0.53 | 4:39:00 | 6 | 7 | -| ENG/BTC | 18 | 1.36 | 24.54 | 0.00122807 | 12.27 | 2:50:00 | 8 | 10 | -| EOS/BTC | 36 | 0.08 | 3.06 | 0.00015304 | 1.53 | 3:34:00 | 16 | 20 | -| ETC/BTC | 26 | 0.37 | 9.51 | 0.00047576 | 4.75 | 6:14:00 | 11 | 15 | -| ETH/BTC | 33 | 0.30 | 9.96 | 0.00049856 | 4.98 | 7:31:00 | 16 | 17 | -| IOTA/BTC | 32 | 0.03 | 1.09 | 0.00005444 | 0.54 | 3:12:00 | 14 | 18 | -| LSK/BTC | 15 | 1.75 | 26.26 | 0.00131413 | 13.13 | 2:58:00 | 6 | 9 | -| LTC/BTC | 32 | -0.04 | -1.38 | -0.00006886 | -0.69 | 4:49:00 | 11 | 21 | -| NANO/BTC | 17 | 1.26 | 21.39 | 0.00107058 | 10.70 | 1:55:00 | 10 | 7 | -| NEO/BTC | 23 | 0.82 | 18.97 | 0.00094936 | 9.48 | 2:59:00 | 10 | 13 | -| REQ/BTC | 9 | 1.17 | 10.54 | 0.00052734 | 5.27 | 3:47:00 | 4 | 5 | -| XLM/BTC | 16 | 1.22 | 19.54 | 0.00097800 | 9.77 | 3:15:00 | 7 | 9 | -| XMR/BTC | 23 | -0.18 | -4.13 | -0.00020696 | -2.07 | 5:30:00 | 12 | 11 | -| XRP/BTC | 35 | 0.66 | 22.96 | 0.00114897 | 11.48 | 3:49:00 | 12 | 23 | -| ZEC/BTC | 22 | -0.46 | -10.18 | -0.00050971 | -5.09 | 2:22:00 | 7 | 15 | -| TOTAL | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 | 243 | +| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins | Draws | Losses | +|:---------|-------:|---------------:|---------------:|-----------------:|---------------:|:---------------|------:|-------:|--------:| +| ADA/BTC | 35 | -0.11 | -3.88 | -0.00019428 | -1.94 | 4:35:00 | 14 | 0 | 21 | +| ARK/BTC | 11 | -0.41 | -4.52 | -0.00022647 | -2.26 | 2:03:00 | 3 | 0 | 8 | +| BTS/BTC | 32 | 0.31 | 9.78 | 0.00048938 | 4.89 | 5:05:00 | 18 | 0 | 14 | +| DASH/BTC | 13 | -0.08 | -1.07 | -0.00005343 | -0.53 | 4:39:00 | 6 | 0 | 7 | +| ENG/BTC | 18 | 1.36 | 24.54 | 0.00122807 | 12.27 | 2:50:00 | 8 | 0 | 10 | +| EOS/BTC | 36 | 0.08 | 3.06 | 0.00015304 | 1.53 | 3:34:00 | 16 | 0 | 20 | +| ETC/BTC | 26 | 0.37 | 9.51 | 0.00047576 | 4.75 | 6:14:00 | 11 | 0 | 15 | +| ETH/BTC | 33 | 0.30 | 9.96 | 0.00049856 | 4.98 | 7:31:00 | 16 | 0 | 17 | +| IOTA/BTC | 32 | 0.03 | 1.09 | 0.00005444 | 0.54 | 3:12:00 | 14 | 0 | 18 | +| LSK/BTC | 15 | 1.75 | 26.26 | 0.00131413 | 13.13 | 2:58:00 | 6 | 0 | 9 | +| LTC/BTC | 32 | -0.04 | -1.38 | -0.00006886 | -0.69 | 4:49:00 | 11 | 0 | 21 | +| NANO/BTC | 17 | 1.26 | 21.39 | 0.00107058 | 10.70 | 1:55:00 | 10 | 0 | 7 | +| NEO/BTC | 23 | 0.82 | 18.97 | 0.00094936 | 9.48 | 2:59:00 | 10 | 0 | 13 | +| REQ/BTC | 9 | 1.17 | 10.54 | 0.00052734 | 5.27 | 3:47:00 | 4 | 0 | 5 | +| XLM/BTC | 16 | 1.22 | 19.54 | 0.00097800 | 9.77 | 3:15:00 | 7 | 0 | 9 | +| XMR/BTC | 23 | -0.18 | -4.13 | -0.00020696 | -2.07 | 5:30:00 | 12 | 0 | 11 | +| XRP/BTC | 35 | 0.66 | 22.96 | 0.00114897 | 11.48 | 3:49:00 | 12 | 0 | 23 | +| ZEC/BTC | 22 | -0.46 | -10.18 | -0.00050971 | -5.09 | 2:22:00 | 7 | 0 | 15 | +| TOTAL | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 | 0 | 243 | ========================================================= SELL REASON STATS ========================================================= -| Sell Reason | Count | Profit | Loss | -|:-------------------|--------:|---------:|-------:| -| trailing_stop_loss | 205 | 150 | 55 | -| stop_loss | 166 | 0 | 166 | -| sell_signal | 56 | 36 | 20 | -| force_sell | 2 | 0 | 2 | +| Sell Reason | Sells | Wins | Draws | Losses | +|:-------------------|--------:|------:|-------:|--------:| +| trailing_stop_loss | 205 | 150 | 0 | 55 | +| stop_loss | 166 | 0 | 0 | 166 | +| sell_signal | 56 | 36 | 0 | 20 | +| force_sell | 2 | 0 | 0 | 2 | ====================================================== LEFT OPEN TRADES REPORT ====================================================== -| pair | buy count | avg profit % | cum profit % | tot profit BTC | tot profit % | avg duration | profit | loss | -|:---------|------------:|---------------:|---------------:|-----------------:|---------------:|:---------------|---------:|-------:| -| ADA/BTC | 1 | 0.89 | 0.89 | 0.00004434 | 0.44 | 6:00:00 | 1 | 0 | -| LTC/BTC | 1 | 0.68 | 0.68 | 0.00003421 | 0.34 | 2:00:00 | 1 | 0 | -| TOTAL | 2 | 0.78 | 1.57 | 0.00007855 | 0.78 | 4:00:00 | 2 | 0 | +| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins | Draws | Losses | +|:---------|-------:|---------------:|---------------:|-----------------:|---------------:|:---------------|------:|-------:|--------:| +| ADA/BTC | 1 | 0.89 | 0.89 | 0.00004434 | 0.44 | 6:00:00 | 1 | 0 | 0 | +| LTC/BTC | 1 | 0.68 | 0.68 | 0.00003421 | 0.34 | 2:00:00 | 1 | 0 | 0 | +| TOTAL | 2 | 0.78 | 1.57 | 0.00007855 | 0.78 | 4:00:00 | 2 | 0 | 0 | ``` The 1st table contains all trades the bot made, including "left open trades". @@ -238,10 +238,10 @@ Detailed output for all strategies one after the other will be available, so mak ``` =========================================================== STRATEGY SUMMARY =========================================================== -| Strategy | Buy Count | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins | Losses | -|:------------|------------:|---------------:|---------------:|-----------------:|---------------:|:---------------|---------:|-------:| -| Strategy1 | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 | 243 | -| Strategy2 | 1487 | -0.13 | -197.58 | -0.00988917 | -98.79 | 4:43:00 | 662 | 825 | +| Strategy | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins | Draws | Losses | +|:------------|-------:|---------------:|---------------:|-----------------:|---------------:|:---------------|------:|-------:|-------:| +| Strategy1 | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 | 0 | 243 | +| Strategy2 | 1487 | -0.13 | -197.58 | -0.00988917 | -98.79 | 4:43:00 | 662 | 0 | 825 | ``` ## Next step diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 8ad063056..b00adbd48 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -21,13 +21,14 @@ def generate_text_table(data: Dict[str, Dict], stake_currency: str, max_open_tra tabular_data = [] headers = [ 'Pair', - 'Buy Count', + 'Buys', 'Avg Profit %', 'Cum Profit %', f'Tot Profit {stake_currency}', 'Tot Profit %', 'Avg Duration', 'Wins', + 'Draws', 'Losses' ] for pair in data: @@ -45,6 +46,7 @@ def generate_text_table(data: Dict[str, Dict], stake_currency: str, max_open_tra str(timedelta( minutes=round(result.trade_duration.mean()))) if not result.empty else '0:00', len(result[result.profit_abs > 0]), + len(result[result.profit_abs == 0]), len(result[result.profit_abs < 0]) ]) @@ -59,6 +61,7 @@ def generate_text_table(data: Dict[str, Dict], stake_currency: str, max_open_tra str(timedelta( minutes=round(results.trade_duration.mean()))) if not results.empty else '0:00', len(results[results.profit_abs > 0]), + len(results[results.profit_abs == 0]), len(results[results.profit_abs < 0]) ]) # Ignore type as floatfmt does allow tuples but mypy does not know that @@ -78,8 +81,9 @@ def generate_text_table_sell_reason( tabular_data = [] headers = [ "Sell Reason", - "Sell Count", + "Sells", "Wins", + "Draws", "Losses", "Avg Profit %", "Cum Profit %", @@ -88,7 +92,8 @@ def generate_text_table_sell_reason( ] for reason, count in results['sell_reason'].value_counts().iteritems(): result = results.loc[results['sell_reason'] == reason] - profit = len(result[result['profit_abs'] >= 0]) + wins = len(result[result['profit_abs'] > 0]) + draws = len(result[result['profit_abs'] == 0]) loss = len(result[result['profit_abs'] < 0]) profit_mean = round(result['profit_percent'].mean() * 100.0, 2) profit_sum = round(result["profit_percent"].sum() * 100.0, 2) @@ -98,7 +103,8 @@ def generate_text_table_sell_reason( [ reason.value, count, - profit, + wins, + draws, loss, profit_mean, profit_sum, @@ -121,9 +127,9 @@ def generate_text_table_strategy(stake_currency: str, max_open_trades: str, floatfmt = ('s', 'd', '.2f', '.2f', '.8f', '.2f', 'd', '.1f', '.1f') tabular_data = [] - headers = ['Strategy', 'Buy Count', 'Avg Profit %', 'Cum Profit %', + headers = ['Strategy', 'Buys', 'Avg Profit %', 'Cum Profit %', f'Tot Profit {stake_currency}', 'Tot Profit %', 'Avg Duration', - 'Wins', 'Losses'] + 'Wins', 'Draws', 'Losses'] for strategy, results in all_results.items(): tabular_data.append([ strategy, @@ -135,6 +141,7 @@ def generate_text_table_strategy(stake_currency: str, max_open_trades: str, str(timedelta( minutes=round(results.trade_duration.mean()))) if not results.empty else '0:00', len(results[results.profit_abs > 0]), + len(results[results.profit_abs == 0]), len(results[results.profit_abs < 0]) ]) # Ignore type as floatfmt does allow tuples but mypy does not know that @@ -146,9 +153,9 @@ def generate_edge_table(results: dict) -> str: floatfmt = ('s', '.10g', '.2f', '.2f', '.2f', '.2f', 'd', '.d') tabular_data = [] - headers = ['pair', 'stoploss', 'win rate', 'risk reward ratio', - 'required risk reward', 'expectancy', 'total number of trades', - 'average duration (min)'] + headers = ['Pair', 'Stoploss', 'Win Rate', 'Risk Reward Ratio', + 'Required Risk Reward', 'Expectancy', 'Total Number of Trades', + 'Average Duration (min)'] for result in results.items(): if result[1].nb_trades > 0: diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 3ea13be47..c31b10290 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -15,20 +15,17 @@ def test_generate_text_table(default_conf, mocker): 'profit_percent': [0.1, 0.2], 'profit_abs': [0.2, 0.4], 'trade_duration': [10, 30], - 'profit': [2, 0], - 'loss': [0, 0] + 'wins': [2, 0], + 'draws': [0, 0], + 'losses': [0, 0] } ) result_str = ( - '| Pair | Buy Count | Avg Profit % | Cum Profit % | Tot Profit BTC ' - '| Tot Profit % | Avg Duration | Wins | Losses |\n' - '|:--------|------------:|---------------:|---------------:|-----------------:' - '|---------------:|:---------------|-------:|---------:|\n' - '| ETH/BTC | 2 | 15.00 | 30.00 | 0.60000000 ' - '| 15.00 | 0:20:00 | 2 | 0 |\n' - '| TOTAL | 2 | 15.00 | 30.00 | 0.60000000 ' - '| 15.00 | 0:20:00 | 2 | 0 |' + '| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins | Draws | Losses |\n' + '|:--------|-------:|---------------:|---------------:|-----------------:|---------------:|:---------------|-------:|--------:|---------:|\n' + '| ETH/BTC | 2 | 15.00 | 30.00 | 0.60000000 | 15.00 | 0:20:00 | 2 | 0 | 0 |\n' + '| TOTAL | 2 | 15.00 | 30.00 | 0.60000000 | 15.00 | 0:20:00 | 2 | 0 | 0 |' ) assert generate_text_table(data={'ETH/BTC': {}}, stake_currency='BTC', max_open_trades=2, @@ -43,21 +40,18 @@ def test_generate_text_table_sell_reason(default_conf, mocker): 'profit_percent': [0.1, 0.2, -0.1], 'profit_abs': [0.2, 0.4, -0.2], 'trade_duration': [10, 30, 10], - 'profit': [2, 0, 0], - 'loss': [0, 0, 1], + 'wins': [2, 0, 0], + 'draws': [0, 0, 0], + 'losses': [0, 0, 1], 'sell_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS] } ) result_str = ( - '| Sell Reason | Sell Count | Wins | Losses | Avg Profit % |' - ' Cum Profit % | Tot Profit BTC | Tot Profit % |\n' - '|:--------------|-------------:|-------:|---------:|---------------:|' - '---------------:|-----------------:|---------------:|\n' - '| roi | 2 | 2 | 0 | 15 |' - ' 30 | 0.6 | 15 |\n' - '| stop_loss | 1 | 0 | 1 | -10 |' - ' -10 | -0.2 | -5 |' + '| Sell Reason | Sells | Wins | Draws | Losses | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % |\n' + '|:--------------|--------:|-------:|--------:|---------:|---------------:|---------------:|-----------------:|---------------:|\n' + '| roi | 2 | 2 | 0 | 0 | 15 | 30 | 0.6 | 15 |\n' + '| stop_loss | 1 | 0 | 0 | 1 | -10 | -10 | -0.2 | -5 |' ) assert generate_text_table_sell_reason( data={'ETH/BTC': {}}, @@ -67,38 +61,36 @@ def test_generate_text_table_sell_reason(default_conf, mocker): def test_generate_text_table_strategy(default_conf, mocker): results = {} - results['ETH/BTC'] = pd.DataFrame( + results['TestStrategy1'] = pd.DataFrame( { 'pair': ['ETH/BTC', 'ETH/BTC', 'ETH/BTC'], 'profit_percent': [0.1, 0.2, 0.3], 'profit_abs': [0.2, 0.4, 0.5], 'trade_duration': [10, 30, 10], - 'profit': [2, 0, 0], - 'loss': [0, 0, 1], + 'wins': [2, 0, 0], + 'draws': [0, 0, 0], + 'losses': [0, 0, 1], 'sell_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS] } ) - results['LTC/BTC'] = pd.DataFrame( + results['TestStrategy2'] = pd.DataFrame( { 'pair': ['LTC/BTC', 'LTC/BTC', 'LTC/BTC'], 'profit_percent': [0.4, 0.2, 0.3], 'profit_abs': [0.4, 0.4, 0.5], 'trade_duration': [15, 30, 15], - 'profit': [4, 1, 0], - 'loss': [0, 0, 1], + 'wins': [4, 1, 0], + 'draws': [0, 0, 0], + 'losses': [0, 0, 1], 'sell_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS] } ) result_str = ( - '| Strategy | Buy Count | Avg Profit % | Cum Profit % | Tot Profit BTC ' - '| Tot Profit % | Avg Duration | Wins | Losses |\n' - '|:-----------|------------:|---------------:|---------------:|-----------------:' - '|---------------:|:---------------|-------:|---------:|\n' - '| ETH/BTC | 3 | 20.00 | 60.00 ' - '| 1.10000000 | 30.00 | 0:17:00 | 3 | 0 |\n' - '| LTC/BTC | 3 | 30.00 | 90.00 ' - '| 1.30000000 | 45.00 | 0:20:00 | 3 | 0 |' + '| Strategy | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins | Draws | Losses |\n' + '|:--------------|-------:|---------------:|---------------:|-----------------:|---------------:|:---------------|-------:|--------:|---------:|\n' + '| TestStrategy1 | 3 | 20.00 | 60.00 | 1.10000000 | 30.00 | 0:17:00 | 3 | 0 | 0 |\n' + '| TestStrategy2 | 3 | 30.00 | 90.00 | 1.30000000 | 45.00 | 0:20:00 | 3 | 0 | 0 |' ) assert generate_text_table_strategy('BTC', 2, all_results=results) == result_str @@ -111,4 +103,4 @@ def test_generate_edge_table(edge_conf, mocker): assert generate_edge_table(results).count(':|') == 7 assert generate_edge_table(results).count('| ETH/BTC |') == 1 assert generate_edge_table(results).count( - '| risk reward ratio | required risk reward | expectancy |') == 1 + '| Risk Reward Ratio | Required Risk Reward | Expectancy |') == 1