Merge pull request #1510 from gianlup/add_totprofit_to_bt
Added total profit column to backtest result
This commit is contained in:
commit
3afe54790e
@ -166,53 +166,65 @@ The most important in the backtesting is to understand the result.
|
|||||||
A backtesting result will look like that:
|
A backtesting result will look like that:
|
||||||
|
|
||||||
```
|
```
|
||||||
======================================== BACKTESTING REPORT =========================================
|
========================================================= BACKTESTING REPORT ========================================================
|
||||||
| pair | buy count | avg profit % | total profit BTC | avg duration | profit | loss |
|
| pair | buy count | avg profit % | cum profit % | tot profit BTC | tot profit % | avg duration | profit | loss |
|
||||||
|:---------|------------:|---------------:|-------------------:|---------------:|---------:|-------:|
|
|:---------|------------:|---------------:|---------------:|-----------------:|---------------:|:---------------|---------:|-------:|
|
||||||
| ETH/BTC | 44 | 0.18 | 0.00159118 | 50.9 | 44 | 0 |
|
| ADA/BTC | 35 | -0.11 | -3.88 | -0.00019428 | -1.94 | 4:35:00 | 14 | 21 |
|
||||||
| LTC/BTC | 27 | 0.10 | 0.00051931 | 103.1 | 26 | 1 |
|
| ARK/BTC | 11 | -0.41 | -4.52 | -0.00022647 | -2.26 | 2:03:00 | 3 | 8 |
|
||||||
| ETC/BTC | 24 | 0.05 | 0.00022434 | 166.0 | 22 | 2 |
|
| BTS/BTC | 32 | 0.31 | 9.78 | 0.00048938 | 4.89 | 5:05:00 | 18 | 14 |
|
||||||
| DASH/BTC | 29 | 0.18 | 0.00103223 | 192.2 | 29 | 0 |
|
| DASH/BTC | 13 | -0.08 | -1.07 | -0.00005343 | -0.53 | 4:39:00 | 6 | 7 |
|
||||||
| ZEC/BTC | 65 | -0.02 | -0.00020621 | 202.7 | 62 | 3 |
|
| ENG/BTC | 18 | 1.36 | 24.54 | 0.00122807 | 12.27 | 2:50:00 | 8 | 10 |
|
||||||
| XLM/BTC | 35 | 0.02 | 0.00012877 | 242.4 | 32 | 3 |
|
| EOS/BTC | 36 | 0.08 | 3.06 | 0.00015304 | 1.53 | 3:34:00 | 16 | 20 |
|
||||||
| BCH/BTC | 12 | 0.62 | 0.00149284 | 50.0 | 12 | 0 |
|
| ETC/BTC | 26 | 0.37 | 9.51 | 0.00047576 | 4.75 | 6:14:00 | 11 | 15 |
|
||||||
| POWR/BTC | 21 | 0.26 | 0.00108215 | 134.8 | 21 | 0 |
|
| ETH/BTC | 33 | 0.30 | 9.96 | 0.00049856 | 4.98 | 7:31:00 | 16 | 17 |
|
||||||
| ADA/BTC | 54 | -0.19 | -0.00205202 | 191.3 | 47 | 7 |
|
| IOTA/BTC | 32 | 0.03 | 1.09 | 0.00005444 | 0.54 | 3:12:00 | 14 | 18 |
|
||||||
| XMR/BTC | 24 | -0.43 | -0.00206013 | 120.6 | 20 | 4 |
|
| LSK/BTC | 15 | 1.75 | 26.26 | 0.00131413 | 13.13 | 2:58:00 | 6 | 9 |
|
||||||
| TOTAL | 335 | 0.03 | 0.00175246 | 157.9 | 315 | 20 |
|
| LTC/BTC | 32 | -0.04 | -1.38 | -0.00006886 | -0.69 | 4:49:00 | 11 | 21 |
|
||||||
2018-06-13 06:57:27,347 - freqtrade.optimize.backtesting - INFO -
|
| NANO/BTC | 17 | 1.26 | 21.39 | 0.00107058 | 10.70 | 1:55:00 | 10 | 7 |
|
||||||
====================================== LEFT OPEN TRADES REPORT ======================================
|
| NEO/BTC | 23 | 0.82 | 18.97 | 0.00094936 | 9.48 | 2:59:00 | 10 | 13 |
|
||||||
| pair | buy count | avg profit % | total profit BTC | avg duration | profit | loss |
|
| 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 |
|
||||||
| ETH/BTC | 3 | 0.16 | 0.00009619 | 25.0 | 3 | 0 |
|
| XMR/BTC | 23 | -0.18 | -4.13 | -0.00020696 | -2.07 | 5:30:00 | 12 | 11 |
|
||||||
| LTC/BTC | 1 | -1.00 | -0.00020118 | 1085.0 | 0 | 1 |
|
| XRP/BTC | 35 | 0.66 | 22.96 | 0.00114897 | 11.48 | 3:49:00 | 12 | 23 |
|
||||||
| ETC/BTC | 2 | -1.80 | -0.00071933 | 1092.5 | 0 | 2 |
|
| ZEC/BTC | 22 | -0.46 | -10.18 | -0.00050971 | -5.09 | 2:22:00 | 7 | 15 |
|
||||||
| DASH/BTC | 0 | nan | 0.00000000 | nan | 0 | 0 |
|
| TOTAL | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 | 243 |
|
||||||
| ZEC/BTC | 3 | -4.27 | -0.00256826 | 1301.7 | 0 | 3 |
|
========================================================= SELL REASON STATS =========================================================
|
||||||
| XLM/BTC | 3 | -1.11 | -0.00066744 | 965.0 | 0 | 3 |
|
| Sell Reason | Count |
|
||||||
| BCH/BTC | 0 | nan | 0.00000000 | nan | 0 | 0 |
|
|:-------------------|--------:|
|
||||||
| POWR/BTC | 0 | nan | 0.00000000 | nan | 0 | 0 |
|
| trailing_stop_loss | 205 |
|
||||||
| ADA/BTC | 7 | -3.58 | -0.00503604 | 850.0 | 0 | 7 |
|
| stop_loss | 166 |
|
||||||
| XMR/BTC | 4 | -3.79 | -0.00303456 | 291.2 | 0 | 4 |
|
| sell_signal | 56 |
|
||||||
| TOTAL | 23 | -2.63 | -0.01213062 | 750.4 | 3 | 20 |
|
| force_sell | 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 |
|
||||||
```
|
```
|
||||||
|
|
||||||
The 1st table will contain all trades the bot made.
|
The 1st table will contain all trades the bot made.
|
||||||
|
|
||||||
The 2nd table will contain all trades the bot had to `forcesell` at the end of the backtest period to present a full picture.
|
The 2nd table will contain a recap of sell reasons.
|
||||||
|
|
||||||
|
The 3rd table will contain all trades the bot had to `forcesell` at the end of the backtest period to present a full picture.
|
||||||
These trades are also included in the first table, but are extracted separately for clarity.
|
These trades are also included in the first table, but are extracted separately for clarity.
|
||||||
|
|
||||||
The last line will give you the overall performance of your strategy,
|
The last line will give you the overall performance of your strategy,
|
||||||
here:
|
here:
|
||||||
|
|
||||||
```
|
```
|
||||||
TOTAL 419 -0.41 -0.00348593 52.9
|
| TOTAL | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 | 243 |
|
||||||
```
|
```
|
||||||
|
|
||||||
We understand the bot has made `419` trades for an average duration of
|
We understand the bot has made `429` trades for an average duration of
|
||||||
`52.9` min, with a performance of `-0.41%` (loss), that means it has
|
`4:12:00`, with a performance of `76.20%` (profit), that means it has
|
||||||
lost a total of `-0.00348593 BTC`.
|
earned a total of `0.00762792 BTC` starting with a capital of 0.01 BTC.
|
||||||
|
|
||||||
|
The column `avg profit %` shows the average profit for all trades made while the column `cum profit %` sums all the profits/losses.
|
||||||
|
The column `tot profit %` shows instead the total profit % in relation to allocated capital
|
||||||
|
(`max_open_trades * stake_amount`). In the above results we have `max_open_trades=2 stake_amount=0.005` in config
|
||||||
|
so `(76.20/100) * (0.005 * 2) =~ 0.00762792 BTC`.
|
||||||
|
|
||||||
As you will see your strategy performance will be influenced by your buy
|
As you will see your strategy performance will be influenced by your buy
|
||||||
strategy, your sell strategy, and also by the `minimal_roi` and
|
strategy, your sell strategy, and also by the `minimal_roi` and
|
||||||
@ -251,11 +263,11 @@ There will be an additional table comparing win/losses of the different strategi
|
|||||||
Detailed output for all strategies one after the other will be available, so make sure to scroll up.
|
Detailed output for all strategies one after the other will be available, so make sure to scroll up.
|
||||||
|
|
||||||
```
|
```
|
||||||
=================================================== Strategy Summary ====================================================
|
=========================================================== Strategy Summary ===========================================================
|
||||||
| Strategy | buy count | avg profit % | cum profit % | total profit ETH | avg duration | profit | loss |
|
| Strategy | buy count | avg profit % | cum profit % | tot profit BTC | tot profit % | avg duration | profit | loss |
|
||||||
|:-----------|------------:|---------------:|---------------:|-------------------:|:----------------|---------:|-------:|
|
|:------------|------------:|---------------:|---------------:|-----------------:|---------------:|:---------------|---------:|-------:|
|
||||||
| Strategy1 | 19 | -0.76 | -14.39 | -0.01440287 | 15:48:00 | 15 | 4 |
|
| Strategy1 | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 | 243 |
|
||||||
| Strategy2 | 6 | -2.73 | -16.40 | -0.01641299 | 1 day, 14:12:00 | 3 | 3 |
|
| Strategy2 | 1487 | -0.13 | -197.58 | -0.00988917 | -98.79 | 4:43:00 | 662 | 825 |
|
||||||
```
|
```
|
||||||
|
|
||||||
## Next step
|
## Next step
|
||||||
|
@ -100,11 +100,13 @@ class Backtesting(object):
|
|||||||
:return: pretty printed table with tabulate as str
|
:return: pretty printed table with tabulate as str
|
||||||
"""
|
"""
|
||||||
stake_currency = str(self.config.get('stake_currency'))
|
stake_currency = str(self.config.get('stake_currency'))
|
||||||
|
max_open_trades = self.config.get('max_open_trades')
|
||||||
|
|
||||||
floatfmt = ('s', 'd', '.2f', '.2f', '.8f', 'd', '.1f', '.1f')
|
floatfmt = ('s', 'd', '.2f', '.2f', '.8f', '.2f', 'd', '.1f', '.1f')
|
||||||
tabular_data = []
|
tabular_data = []
|
||||||
headers = ['pair', 'buy count', 'avg profit %', 'cum profit %',
|
headers = ['pair', 'buy count', 'avg profit %', 'cum profit %',
|
||||||
'total profit ' + stake_currency, 'avg duration', 'profit', 'loss']
|
'tot profit ' + stake_currency, 'tot profit %', 'avg duration',
|
||||||
|
'profit', 'loss']
|
||||||
for pair in data:
|
for pair in data:
|
||||||
result = results[results.pair == pair]
|
result = results[results.pair == pair]
|
||||||
if skip_nan and result.profit_abs.isnull().all():
|
if skip_nan and result.profit_abs.isnull().all():
|
||||||
@ -116,6 +118,7 @@ class Backtesting(object):
|
|||||||
result.profit_percent.mean() * 100.0,
|
result.profit_percent.mean() * 100.0,
|
||||||
result.profit_percent.sum() * 100.0,
|
result.profit_percent.sum() * 100.0,
|
||||||
result.profit_abs.sum(),
|
result.profit_abs.sum(),
|
||||||
|
result.profit_percent.sum() * 100.0 / max_open_trades,
|
||||||
str(timedelta(
|
str(timedelta(
|
||||||
minutes=round(result.trade_duration.mean()))) if not result.empty else '0:00',
|
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]),
|
||||||
@ -129,6 +132,7 @@ class Backtesting(object):
|
|||||||
results.profit_percent.mean() * 100.0,
|
results.profit_percent.mean() * 100.0,
|
||||||
results.profit_percent.sum() * 100.0,
|
results.profit_percent.sum() * 100.0,
|
||||||
results.profit_abs.sum(),
|
results.profit_abs.sum(),
|
||||||
|
results.profit_percent.sum() * 100.0 / max_open_trades,
|
||||||
str(timedelta(
|
str(timedelta(
|
||||||
minutes=round(results.trade_duration.mean()))) if not results.empty else '0:00',
|
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]),
|
||||||
@ -153,11 +157,13 @@ class Backtesting(object):
|
|||||||
Generate summary table per strategy
|
Generate summary table per strategy
|
||||||
"""
|
"""
|
||||||
stake_currency = str(self.config.get('stake_currency'))
|
stake_currency = str(self.config.get('stake_currency'))
|
||||||
|
max_open_trades = self.config.get('max_open_trades')
|
||||||
|
|
||||||
floatfmt = ('s', 'd', '.2f', '.2f', '.8f', 'd', '.1f', '.1f')
|
floatfmt = ('s', 'd', '.2f', '.2f', '.8f', '.2f', 'd', '.1f', '.1f')
|
||||||
tabular_data = []
|
tabular_data = []
|
||||||
headers = ['Strategy', 'buy count', 'avg profit %', 'cum profit %',
|
headers = ['Strategy', 'buy count', 'avg profit %', 'cum profit %',
|
||||||
'total profit ' + stake_currency, 'avg duration', 'profit', 'loss']
|
'tot profit ' + stake_currency, 'tot profit %', 'avg duration',
|
||||||
|
'profit', 'loss']
|
||||||
for strategy, results in all_results.items():
|
for strategy, results in all_results.items():
|
||||||
tabular_data.append([
|
tabular_data.append([
|
||||||
strategy,
|
strategy,
|
||||||
@ -165,6 +171,7 @@ class Backtesting(object):
|
|||||||
results.profit_percent.mean() * 100.0,
|
results.profit_percent.mean() * 100.0,
|
||||||
results.profit_percent.sum() * 100.0,
|
results.profit_percent.sum() * 100.0,
|
||||||
results.profit_abs.sum(),
|
results.profit_abs.sum(),
|
||||||
|
results.profit_percent.sum() * 100.0 / max_open_trades,
|
||||||
str(timedelta(
|
str(timedelta(
|
||||||
minutes=round(results.trade_duration.mean()))) if not results.empty else '0:00',
|
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]),
|
||||||
@ -430,18 +437,18 @@ class Backtesting(object):
|
|||||||
strategy if len(self.strategylist) > 1 else None)
|
strategy if len(self.strategylist) > 1 else None)
|
||||||
|
|
||||||
print(f"Result for strategy {strategy}")
|
print(f"Result for strategy {strategy}")
|
||||||
print(' BACKTESTING REPORT '.center(119, '='))
|
print(' BACKTESTING REPORT '.center(133, '='))
|
||||||
print(self._generate_text_table(data, results))
|
print(self._generate_text_table(data, results))
|
||||||
|
|
||||||
print(' SELL REASON STATS '.center(119, '='))
|
print(' SELL REASON STATS '.center(133, '='))
|
||||||
print(self._generate_text_table_sell_reason(data, results))
|
print(self._generate_text_table_sell_reason(data, results))
|
||||||
|
|
||||||
print(' LEFT OPEN TRADES REPORT '.center(119, '='))
|
print(' LEFT OPEN TRADES REPORT '.center(133, '='))
|
||||||
print(self._generate_text_table(data, results.loc[results.open_at_end], True))
|
print(self._generate_text_table(data, results.loc[results.open_at_end], True))
|
||||||
print()
|
print()
|
||||||
if len(all_results) > 1:
|
if len(all_results) > 1:
|
||||||
# Print Strategy summary table
|
# Print Strategy summary table
|
||||||
print(' Strategy Summary '.center(119, '='))
|
print(' Strategy Summary '.center(133, '='))
|
||||||
print(self._generate_text_table_strategy(all_results))
|
print(self._generate_text_table_strategy(all_results))
|
||||||
print('\nFor more details, please look at the detail tables above')
|
print('\nFor more details, please look at the detail tables above')
|
||||||
|
|
||||||
|
@ -341,6 +341,7 @@ def test_tickerdata_to_dataframe_bt(default_conf, mocker) -> None:
|
|||||||
|
|
||||||
def test_generate_text_table(default_conf, mocker):
|
def test_generate_text_table(default_conf, mocker):
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
|
default_conf['max_open_trades'] = 2
|
||||||
backtesting = Backtesting(default_conf)
|
backtesting = Backtesting(default_conf)
|
||||||
|
|
||||||
results = pd.DataFrame(
|
results = pd.DataFrame(
|
||||||
@ -356,13 +357,13 @@ def test_generate_text_table(default_conf, mocker):
|
|||||||
|
|
||||||
result_str = (
|
result_str = (
|
||||||
'| pair | buy count | avg profit % | cum profit % | '
|
'| pair | buy count | avg profit % | cum profit % | '
|
||||||
'total profit BTC | avg duration | profit | loss |\n'
|
'tot profit BTC | tot profit % | avg duration | profit | loss |\n'
|
||||||
'|:--------|------------:|---------------:|---------------:|'
|
'|:--------|------------:|---------------:|---------------:|'
|
||||||
'-------------------:|:---------------|---------:|-------:|\n'
|
'-----------------:|---------------:|:---------------|---------:|-------:|\n'
|
||||||
'| ETH/BTC | 2 | 15.00 | 30.00 | '
|
'| ETH/BTC | 2 | 15.00 | 30.00 | '
|
||||||
'0.60000000 | 0:20:00 | 2 | 0 |\n'
|
'0.60000000 | 15.00 | 0:20:00 | 2 | 0 |\n'
|
||||||
'| TOTAL | 2 | 15.00 | 30.00 | '
|
'| TOTAL | 2 | 15.00 | 30.00 | '
|
||||||
'0.60000000 | 0:20:00 | 2 | 0 |'
|
'0.60000000 | 15.00 | 0:20:00 | 2 | 0 |'
|
||||||
)
|
)
|
||||||
assert backtesting._generate_text_table(data={'ETH/BTC': {}}, results=results) == result_str
|
assert backtesting._generate_text_table(data={'ETH/BTC': {}}, results=results) == result_str
|
||||||
|
|
||||||
@ -398,6 +399,7 @@ def test_generate_text_table_strategyn(default_conf, mocker):
|
|||||||
Test Backtesting.generate_text_table_sell_reason() method
|
Test Backtesting.generate_text_table_sell_reason() method
|
||||||
"""
|
"""
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
|
default_conf['max_open_trades'] = 2
|
||||||
backtesting = Backtesting(default_conf)
|
backtesting = Backtesting(default_conf)
|
||||||
results = {}
|
results = {}
|
||||||
results['ETH/BTC'] = pd.DataFrame(
|
results['ETH/BTC'] = pd.DataFrame(
|
||||||
@ -425,13 +427,13 @@ def test_generate_text_table_strategyn(default_conf, mocker):
|
|||||||
|
|
||||||
result_str = (
|
result_str = (
|
||||||
'| Strategy | buy count | avg profit % | cum profit % '
|
'| Strategy | buy count | avg profit % | cum profit % '
|
||||||
'| total profit BTC | avg duration | profit | loss |\n'
|
'| tot profit BTC | tot profit % | avg duration | profit | loss |\n'
|
||||||
'|:-----------|------------:|---------------:|---------------:'
|
'|:-----------|------------:|---------------:|---------------:'
|
||||||
'|-------------------:|:---------------|---------:|-------:|\n'
|
'|-----------------:|---------------:|:---------------|---------:|-------:|\n'
|
||||||
'| ETH/BTC | 3 | 20.00 | 60.00 '
|
'| ETH/BTC | 3 | 20.00 | 60.00 '
|
||||||
'| 1.10000000 | 0:17:00 | 3 | 0 |\n'
|
'| 1.10000000 | 30.00 | 0:17:00 | 3 | 0 |\n'
|
||||||
'| LTC/BTC | 3 | 30.00 | 90.00 '
|
'| LTC/BTC | 3 | 30.00 | 90.00 '
|
||||||
'| 1.30000000 | 0:20:00 | 3 | 0 |'
|
'| 1.30000000 | 45.00 | 0:20:00 | 3 | 0 |'
|
||||||
)
|
)
|
||||||
print(backtesting._generate_text_table_strategy(all_results=results))
|
print(backtesting._generate_text_table_strategy(all_results=results))
|
||||||
assert backtesting._generate_text_table_strategy(all_results=results) == result_str
|
assert backtesting._generate_text_table_strategy(all_results=results) == result_str
|
||||||
|
Loading…
Reference in New Issue
Block a user