commit
02faeb60a3
@ -237,29 +237,29 @@ 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 | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins | Draws | Losses |
|
| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins Draws Loss Win% |
|
||||||
|:---------|-------:|---------------:|---------------:|-----------------:|---------------:|:---------------|------:|-------:|--------:|
|
|:---------|-------:|---------------:|---------------:|-----------------:|---------------:|:-------------|-------------------------:|
|
||||||
| ADA/BTC | 35 | -0.11 | -3.88 | -0.00019428 | -1.94 | 4:35:00 | 14 | 0 | 21 |
|
| ADA/BTC | 35 | -0.11 | -3.88 | -0.00019428 | -1.94 | 4:35:00 | 14 0 21 40.0 |
|
||||||
| ARK/BTC | 11 | -0.41 | -4.52 | -0.00022647 | -2.26 | 2:03:00 | 3 | 0 | 8 |
|
| ARK/BTC | 11 | -0.41 | -4.52 | -0.00022647 | -2.26 | 2:03:00 | 3 0 8 27.3 |
|
||||||
| BTS/BTC | 32 | 0.31 | 9.78 | 0.00048938 | 4.89 | 5:05:00 | 18 | 0 | 14 |
|
| BTS/BTC | 32 | 0.31 | 9.78 | 0.00048938 | 4.89 | 5:05:00 | 18 0 14 56.2 |
|
||||||
| DASH/BTC | 13 | -0.08 | -1.07 | -0.00005343 | -0.53 | 4:39:00 | 6 | 0 | 7 |
|
| DASH/BTC | 13 | -0.08 | -1.07 | -0.00005343 | -0.53 | 4:39:00 | 6 0 7 46.2 |
|
||||||
| ENG/BTC | 18 | 1.36 | 24.54 | 0.00122807 | 12.27 | 2:50:00 | 8 | 0 | 10 |
|
| ENG/BTC | 18 | 1.36 | 24.54 | 0.00122807 | 12.27 | 2:50:00 | 8 0 10 44.4 |
|
||||||
| EOS/BTC | 36 | 0.08 | 3.06 | 0.00015304 | 1.53 | 3:34:00 | 16 | 0 | 20 |
|
| EOS/BTC | 36 | 0.08 | 3.06 | 0.00015304 | 1.53 | 3:34:00 | 16 0 20 44.4 |
|
||||||
| ETC/BTC | 26 | 0.37 | 9.51 | 0.00047576 | 4.75 | 6:14:00 | 11 | 0 | 15 |
|
| ETC/BTC | 26 | 0.37 | 9.51 | 0.00047576 | 4.75 | 6:14:00 | 11 0 15 42.3 |
|
||||||
| ETH/BTC | 33 | 0.30 | 9.96 | 0.00049856 | 4.98 | 7:31:00 | 16 | 0 | 17 |
|
| ETH/BTC | 33 | 0.30 | 9.96 | 0.00049856 | 4.98 | 7:31:00 | 16 0 17 48.5 |
|
||||||
| IOTA/BTC | 32 | 0.03 | 1.09 | 0.00005444 | 0.54 | 3:12:00 | 14 | 0 | 18 |
|
| IOTA/BTC | 32 | 0.03 | 1.09 | 0.00005444 | 0.54 | 3:12:00 | 14 0 18 43.8 |
|
||||||
| LSK/BTC | 15 | 1.75 | 26.26 | 0.00131413 | 13.13 | 2:58:00 | 6 | 0 | 9 |
|
| LSK/BTC | 15 | 1.75 | 26.26 | 0.00131413 | 13.13 | 2:58:00 | 6 0 9 40.0 |
|
||||||
| LTC/BTC | 32 | -0.04 | -1.38 | -0.00006886 | -0.69 | 4:49:00 | 11 | 0 | 21 |
|
| LTC/BTC | 32 | -0.04 | -1.38 | -0.00006886 | -0.69 | 4:49:00 | 11 0 21 34.4 |
|
||||||
| NANO/BTC | 17 | 1.26 | 21.39 | 0.00107058 | 10.70 | 1:55:00 | 10 | 0 | 7 |
|
| NANO/BTC | 17 | 1.26 | 21.39 | 0.00107058 | 10.70 | 1:55:00 | 10 0 7 58.5 |
|
||||||
| NEO/BTC | 23 | 0.82 | 18.97 | 0.00094936 | 9.48 | 2:59:00 | 10 | 0 | 13 |
|
| NEO/BTC | 23 | 0.82 | 18.97 | 0.00094936 | 9.48 | 2:59:00 | 10 0 13 43.5 |
|
||||||
| REQ/BTC | 9 | 1.17 | 10.54 | 0.00052734 | 5.27 | 3:47:00 | 4 | 0 | 5 |
|
| REQ/BTC | 9 | 1.17 | 10.54 | 0.00052734 | 5.27 | 3:47:00 | 4 0 5 44.4 |
|
||||||
| XLM/BTC | 16 | 1.22 | 19.54 | 0.00097800 | 9.77 | 3:15:00 | 7 | 0 | 9 |
|
| XLM/BTC | 16 | 1.22 | 19.54 | 0.00097800 | 9.77 | 3:15:00 | 7 0 9 43.8 |
|
||||||
| XMR/BTC | 23 | -0.18 | -4.13 | -0.00020696 | -2.07 | 5:30:00 | 12 | 0 | 11 |
|
| XMR/BTC | 23 | -0.18 | -4.13 | -0.00020696 | -2.07 | 5:30:00 | 12 0 11 52.2 |
|
||||||
| XRP/BTC | 35 | 0.66 | 22.96 | 0.00114897 | 11.48 | 3:49:00 | 12 | 0 | 23 |
|
| XRP/BTC | 35 | 0.66 | 22.96 | 0.00114897 | 11.48 | 3:49:00 | 12 0 23 34.3 |
|
||||||
| ZEC/BTC | 22 | -0.46 | -10.18 | -0.00050971 | -5.09 | 2:22:00 | 7 | 0 | 15 |
|
| ZEC/BTC | 22 | -0.46 | -10.18 | -0.00050971 | -5.09 | 2:22:00 | 7 0 15 31.8 |
|
||||||
| TOTAL | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 | 0 | 243 |
|
| TOTAL | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 0 243 43.4 |
|
||||||
========================================================= SELL REASON STATS =========================================================
|
========================================================= SELL REASON STATS ==========================================================
|
||||||
| Sell Reason | Sells | Wins | Draws | Losses |
|
| Sell Reason | Sells | Wins | Draws | Losses |
|
||||||
|:-------------------|--------:|------:|-------:|--------:|
|
|:-------------------|--------:|------:|-------:|--------:|
|
||||||
| trailing_stop_loss | 205 | 150 | 0 | 55 |
|
| trailing_stop_loss | 205 | 150 | 0 | 55 |
|
||||||
@ -267,11 +267,11 @@ A backtesting result will look like that:
|
|||||||
| sell_signal | 56 | 36 | 0 | 20 |
|
| sell_signal | 56 | 36 | 0 | 20 |
|
||||||
| force_sell | 2 | 0 | 0 | 2 |
|
| force_sell | 2 | 0 | 0 | 2 |
|
||||||
====================================================== LEFT OPEN TRADES REPORT ======================================================
|
====================================================== LEFT OPEN TRADES REPORT ======================================================
|
||||||
| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins | Draws | Losses |
|
| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|
||||||
|:---------|-------:|---------------:|---------------:|-----------------:|---------------:|:---------------|------:|-------:|--------:|
|
|:---------|-------:|---------------:|---------------:|-----------------:|---------------:|:---------------|--------------------:|
|
||||||
| ADA/BTC | 1 | 0.89 | 0.89 | 0.00004434 | 0.44 | 6:00:00 | 1 | 0 | 0 |
|
| ADA/BTC | 1 | 0.89 | 0.89 | 0.00004434 | 0.44 | 6:00:00 | 1 0 0 100 |
|
||||||
| LTC/BTC | 1 | 0.68 | 0.68 | 0.00003421 | 0.34 | 2:00:00 | 1 | 0 | 0 |
|
| LTC/BTC | 1 | 0.68 | 0.68 | 0.00003421 | 0.34 | 2:00:00 | 1 0 0 100 |
|
||||||
| TOTAL | 2 | 0.78 | 1.57 | 0.00007855 | 0.78 | 4:00:00 | 2 | 0 | 0 |
|
| TOTAL | 2 | 0.78 | 1.57 | 0.00007855 | 0.78 | 4:00:00 | 2 0 0 100 |
|
||||||
=============== SUMMARY METRICS ===============
|
=============== SUMMARY METRICS ===============
|
||||||
| Metric | Value |
|
| Metric | Value |
|
||||||
|-----------------------+---------------------|
|
|-----------------------+---------------------|
|
||||||
@ -297,6 +297,7 @@ A backtesting result will look like that:
|
|||||||
| Days win/draw/lose | 12 / 82 / 25 |
|
| Days win/draw/lose | 12 / 82 / 25 |
|
||||||
| Avg. Duration Winners | 4:23:00 |
|
| Avg. Duration Winners | 4:23:00 |
|
||||||
| Avg. Duration Loser | 6:55:00 |
|
| Avg. Duration Loser | 6:55:00 |
|
||||||
|
| Zero Duration Trades | 4.6% (20) |
|
||||||
| | |
|
| | |
|
||||||
| Min balance | 0.00945123 BTC |
|
| Min balance | 0.00945123 BTC |
|
||||||
| Max balance | 0.01846651 BTC |
|
| Max balance | 0.01846651 BTC |
|
||||||
@ -318,7 +319,7 @@ The last line will give you the overall performance of your strategy,
|
|||||||
here:
|
here:
|
||||||
|
|
||||||
```
|
```
|
||||||
| TOTAL | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 | 243 |
|
| TOTAL | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 0 243 43.4 |
|
||||||
```
|
```
|
||||||
|
|
||||||
The bot has made `429` trades for an average duration of `4:12:00`, with a performance of `76.20%` (profit), that means it has
|
The bot has made `429` trades for an average duration of `4:12:00`, with a performance of `76.20%` (profit), that means it has
|
||||||
@ -384,6 +385,7 @@ It contains some useful key metrics about performance of your strategy on backte
|
|||||||
| Days win/draw/lose | 12 / 82 / 25 |
|
| Days win/draw/lose | 12 / 82 / 25 |
|
||||||
| Avg. Duration Winners | 4:23:00 |
|
| Avg. Duration Winners | 4:23:00 |
|
||||||
| Avg. Duration Loser | 6:55:00 |
|
| Avg. Duration Loser | 6:55:00 |
|
||||||
|
| Zero Duration Trades | 4.6% (20) |
|
||||||
| | |
|
| | |
|
||||||
| Min balance | 0.00945123 BTC |
|
| Min balance | 0.00945123 BTC |
|
||||||
| Max balance | 0.01846651 BTC |
|
| Max balance | 0.01846651 BTC |
|
||||||
@ -413,6 +415,7 @@ It contains some useful key metrics about performance of your strategy on backte
|
|||||||
- `Best day` / `Worst day`: Best and worst day based on daily profit.
|
- `Best day` / `Worst day`: Best and worst day based on daily profit.
|
||||||
- `Days win/draw/lose`: Winning / Losing days (draws are usually days without closed trade).
|
- `Days win/draw/lose`: Winning / Losing days (draws are usually days without closed trade).
|
||||||
- `Avg. Duration Winners` / `Avg. Duration Loser`: Average durations for winning and losing trades.
|
- `Avg. Duration Winners` / `Avg. Duration Loser`: Average durations for winning and losing trades.
|
||||||
|
- `Zero Duration Trades`: A number of trades that completed within same candle as they opened and had `trailing_stop_loss` sell reason. A significant amount of such trades may indicate that strategy is exploiting trailing stoploss behavior in backtesting and produces unrealistic results.
|
||||||
- `Min balance` / `Max balance`: Lowest and Highest Wallet balance during the backtest period.
|
- `Min balance` / `Max balance`: Lowest and Highest Wallet balance during the backtest period.
|
||||||
- `Drawdown`: Maximum drawdown experienced. For example, the value of 50% means that from highest to subsequent lowest point, a 50% drop was experienced).
|
- `Drawdown`: Maximum drawdown experienced. For example, the value of 50% means that from highest to subsequent lowest point, a 50% drop was experienced).
|
||||||
- `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.
|
||||||
@ -472,11 +475,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 to see the details per strategy.
|
Detailed output for all strategies one after the other will be available, so make sure to scroll up to see the details per strategy.
|
||||||
|
|
||||||
```
|
```
|
||||||
=========================================================== STRATEGY SUMMARY ===========================================================
|
=========================================================== STRATEGY SUMMARY =========================================================================
|
||||||
| Strategy | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins | Draws | Losses |
|
| Strategy | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins | Draws | Losses | Drawdown % |
|
||||||
|:------------|-------:|---------------:|---------------:|-----------------:|---------------:|:---------------|------:|-------:|-------:|
|
|:------------|-------:|---------------:|---------------:|-----------------:|---------------:|:---------------|------:|-------:|-------:|-----------:|
|
||||||
| Strategy1 | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 | 0 | 243 |
|
| Strategy1 | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 | 0 | 243 | 45.2 |
|
||||||
| Strategy2 | 1487 | -0.13 | -197.58 | -0.00988917 | -98.79 | 4:43:00 | 662 | 0 | 825 |
|
| Strategy2 | 1487 | -0.13 | -197.58 | -0.00988917 | -98.79 | 4:43:00 | 662 | 0 | 825 | 241.68 |
|
||||||
```
|
```
|
||||||
|
|
||||||
## Next step
|
## Next step
|
||||||
|
@ -43,7 +43,7 @@ def _get_line_floatfmt(stake_currency: str) -> List[str]:
|
|||||||
Generate floatformat (goes in line with _generate_result_line())
|
Generate floatformat (goes in line with _generate_result_line())
|
||||||
"""
|
"""
|
||||||
return ['s', 'd', '.2f', '.2f', f'.{decimals_per_coin(stake_currency)}f',
|
return ['s', 'd', '.2f', '.2f', f'.{decimals_per_coin(stake_currency)}f',
|
||||||
'.2f', 'd', 'd', 'd', 'd']
|
'.2f', 'd', 's', 's']
|
||||||
|
|
||||||
|
|
||||||
def _get_line_header(first_column: str, stake_currency: str) -> List[str]:
|
def _get_line_header(first_column: str, stake_currency: str) -> List[str]:
|
||||||
@ -52,7 +52,17 @@ def _get_line_header(first_column: str, stake_currency: str) -> List[str]:
|
|||||||
"""
|
"""
|
||||||
return [first_column, 'Buys', 'Avg Profit %', 'Cum Profit %',
|
return [first_column, 'Buys', 'Avg Profit %', 'Cum Profit %',
|
||||||
f'Tot Profit {stake_currency}', 'Tot Profit %', 'Avg Duration',
|
f'Tot Profit {stake_currency}', 'Tot Profit %', 'Avg Duration',
|
||||||
'Wins', 'Draws', 'Losses']
|
'Win Draw Loss Win%']
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_wins_draws_losses(wins, draws, losses):
|
||||||
|
if wins > 0 and losses == 0:
|
||||||
|
wl_ratio = '100'
|
||||||
|
elif wins == 0:
|
||||||
|
wl_ratio = '0'
|
||||||
|
else:
|
||||||
|
wl_ratio = f'{100.0 / (wins + draws + losses) * wins:.1f}' if losses > 0 else '100'
|
||||||
|
return f'{wins:>4} {draws:>4} {losses:>4} {wl_ratio:>4}'
|
||||||
|
|
||||||
|
|
||||||
def _generate_result_line(result: DataFrame, starting_balance: int, first_column: str) -> Dict:
|
def _generate_result_line(result: DataFrame, starting_balance: int, first_column: str) -> Dict:
|
||||||
@ -164,6 +174,17 @@ def generate_strategy_comparison(all_results: Dict) -> List[Dict]:
|
|||||||
tabular_data.append(_generate_result_line(
|
tabular_data.append(_generate_result_line(
|
||||||
results['results'], results['config']['dry_run_wallet'], strategy)
|
results['results'], results['config']['dry_run_wallet'], strategy)
|
||||||
)
|
)
|
||||||
|
try:
|
||||||
|
max_drawdown_per, _, _, _, _ = calculate_max_drawdown(results['results'],
|
||||||
|
value_col='profit_ratio')
|
||||||
|
max_drawdown_abs, _, _, _, _ = calculate_max_drawdown(results['results'],
|
||||||
|
value_col='profit_abs')
|
||||||
|
except ValueError:
|
||||||
|
max_drawdown_per = 0
|
||||||
|
max_drawdown_abs = 0
|
||||||
|
tabular_data[-1]['max_drawdown_per'] = round(max_drawdown_per * 100, 2)
|
||||||
|
tabular_data[-1]['max_drawdown_abs'] = \
|
||||||
|
round_coin_value(max_drawdown_abs, results['config']['stake_currency'], False)
|
||||||
return tabular_data
|
return tabular_data
|
||||||
|
|
||||||
|
|
||||||
@ -208,6 +229,8 @@ def generate_trading_stats(results: DataFrame) -> Dict[str, Any]:
|
|||||||
winning_trades = results.loc[results['profit_ratio'] > 0]
|
winning_trades = results.loc[results['profit_ratio'] > 0]
|
||||||
draw_trades = results.loc[results['profit_ratio'] == 0]
|
draw_trades = results.loc[results['profit_ratio'] == 0]
|
||||||
losing_trades = results.loc[results['profit_ratio'] < 0]
|
losing_trades = results.loc[results['profit_ratio'] < 0]
|
||||||
|
zero_duration_trades = len(results.loc[(results['trade_duration'] == 0) &
|
||||||
|
(results['sell_reason'] == 'trailing_stop_loss')])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'wins': len(winning_trades),
|
'wins': len(winning_trades),
|
||||||
@ -219,6 +242,7 @@ def generate_trading_stats(results: DataFrame) -> Dict[str, Any]:
|
|||||||
if not winning_trades.empty else timedelta()),
|
if not winning_trades.empty else timedelta()),
|
||||||
'loser_holding_avg': (timedelta(minutes=round(losing_trades['trade_duration'].mean()))
|
'loser_holding_avg': (timedelta(minutes=round(losing_trades['trade_duration'].mean()))
|
||||||
if not losing_trades.empty else timedelta()),
|
if not losing_trades.empty else timedelta()),
|
||||||
|
'zero_duration_trades': zero_duration_trades,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -437,7 +461,8 @@ def text_table_bt_results(pair_results: List[Dict[str, Any]], stake_currency: st
|
|||||||
floatfmt = _get_line_floatfmt(stake_currency)
|
floatfmt = _get_line_floatfmt(stake_currency)
|
||||||
output = [[
|
output = [[
|
||||||
t['key'], t['trades'], t['profit_mean_pct'], t['profit_sum_pct'], t['profit_total_abs'],
|
t['key'], t['trades'], t['profit_mean_pct'], t['profit_sum_pct'], t['profit_total_abs'],
|
||||||
t['profit_total_pct'], t['duration_avg'], t['wins'], t['draws'], t['losses']
|
t['profit_total_pct'], t['duration_avg'],
|
||||||
|
_generate_wins_draws_losses(t['wins'], t['draws'], t['losses'])
|
||||||
] for t in pair_results]
|
] for t in pair_results]
|
||||||
# Ignore type as floatfmt does allow tuples but mypy does not know that
|
# Ignore type as floatfmt does allow tuples but mypy does not know that
|
||||||
return tabulate(output, headers=headers,
|
return tabulate(output, headers=headers,
|
||||||
@ -454,9 +479,7 @@ def text_table_sell_reason(sell_reason_stats: List[Dict[str, Any]], stake_curren
|
|||||||
headers = [
|
headers = [
|
||||||
'Sell Reason',
|
'Sell Reason',
|
||||||
'Sells',
|
'Sells',
|
||||||
'Wins',
|
'Win Draws Loss Win%',
|
||||||
'Draws',
|
|
||||||
'Losses',
|
|
||||||
'Avg Profit %',
|
'Avg Profit %',
|
||||||
'Cum Profit %',
|
'Cum Profit %',
|
||||||
f'Tot Profit {stake_currency}',
|
f'Tot Profit {stake_currency}',
|
||||||
@ -464,7 +487,8 @@ def text_table_sell_reason(sell_reason_stats: List[Dict[str, Any]], stake_curren
|
|||||||
]
|
]
|
||||||
|
|
||||||
output = [[
|
output = [[
|
||||||
t['sell_reason'], t['trades'], t['wins'], t['draws'], t['losses'],
|
t['sell_reason'], t['trades'],
|
||||||
|
_generate_wins_draws_losses(t['wins'], t['draws'], t['losses']),
|
||||||
t['profit_mean_pct'], t['profit_sum_pct'],
|
t['profit_mean_pct'], t['profit_sum_pct'],
|
||||||
round_coin_value(t['profit_total_abs'], stake_currency, False),
|
round_coin_value(t['profit_total_abs'], stake_currency, False),
|
||||||
t['profit_total_pct'],
|
t['profit_total_pct'],
|
||||||
@ -482,11 +506,22 @@ def text_table_strategy(strategy_results, stake_currency: str) -> str:
|
|||||||
"""
|
"""
|
||||||
floatfmt = _get_line_floatfmt(stake_currency)
|
floatfmt = _get_line_floatfmt(stake_currency)
|
||||||
headers = _get_line_header('Strategy', stake_currency)
|
headers = _get_line_header('Strategy', stake_currency)
|
||||||
|
# _get_line_header() is also used for per-pair summary. Per-pair drawdown is mostly useless
|
||||||
|
# therefore we slip this column in only for strategy summary here.
|
||||||
|
headers.append('Drawdown')
|
||||||
|
|
||||||
|
# Align drawdown string on the center two space separator.
|
||||||
|
drawdown = [f'{t["max_drawdown_per"]:.2f}' for t in strategy_results]
|
||||||
|
dd_pad_abs = max([len(t['max_drawdown_abs']) for t in strategy_results])
|
||||||
|
dd_pad_per = max([len(dd) for dd in drawdown])
|
||||||
|
drawdown = [f'{t["max_drawdown_abs"]:>{dd_pad_abs}} {stake_currency} {dd:>{dd_pad_per}}%'
|
||||||
|
for t, dd in zip(strategy_results, drawdown)]
|
||||||
|
|
||||||
output = [[
|
output = [[
|
||||||
t['key'], t['trades'], t['profit_mean_pct'], t['profit_sum_pct'], t['profit_total_abs'],
|
t['key'], t['trades'], t['profit_mean_pct'], t['profit_sum_pct'], t['profit_total_abs'],
|
||||||
t['profit_total_pct'], t['duration_avg'], t['wins'], t['draws'], t['losses']
|
t['profit_total_pct'], t['duration_avg'],
|
||||||
] for t in strategy_results]
|
_generate_wins_draws_losses(t['wins'], t['draws'], t['losses']), drawdown]
|
||||||
|
for t, drawdown in zip(strategy_results, drawdown)]
|
||||||
# Ignore type as floatfmt does allow tuples but mypy does not know that
|
# Ignore type as floatfmt does allow tuples but mypy does not know that
|
||||||
return tabulate(output, headers=headers,
|
return tabulate(output, headers=headers,
|
||||||
floatfmt=floatfmt, tablefmt="orgtbl", stralign="right")
|
floatfmt=floatfmt, tablefmt="orgtbl", stralign="right")
|
||||||
@ -496,6 +531,18 @@ def text_table_add_metrics(strat_results: Dict) -> str:
|
|||||||
if len(strat_results['trades']) > 0:
|
if len(strat_results['trades']) > 0:
|
||||||
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'])
|
||||||
|
|
||||||
|
# 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
|
||||||
|
# results with missing new fields.
|
||||||
|
zero_duration_trades = '--'
|
||||||
|
|
||||||
|
if 'zero_duration_trades' in strat_results:
|
||||||
|
zero_duration_trades_per = \
|
||||||
|
100.0 / strat_results['total_trades'] * strat_results['zero_duration_trades']
|
||||||
|
zero_duration_trades = f'{zero_duration_trades_per}% ' \
|
||||||
|
f'({strat_results["zero_duration_trades"]})'
|
||||||
|
|
||||||
metrics = [
|
metrics = [
|
||||||
('Backtesting from', strat_results['backtest_start']),
|
('Backtesting from', strat_results['backtest_start']),
|
||||||
('Backtesting to', strat_results['backtest_end']),
|
('Backtesting to', strat_results['backtest_end']),
|
||||||
@ -508,7 +555,7 @@ def text_table_add_metrics(strat_results: Dict) -> str:
|
|||||||
strat_results['stake_currency'])),
|
strat_results['stake_currency'])),
|
||||||
('Absolute profit ', round_coin_value(strat_results['profit_total_abs'],
|
('Absolute profit ', round_coin_value(strat_results['profit_total_abs'],
|
||||||
strat_results['stake_currency'])),
|
strat_results['stake_currency'])),
|
||||||
('Total profit %', f"{round(strat_results['profit_total'] * 100, 2)}%"),
|
('Total profit %', f"{round(strat_results['profit_total'] * 100, 2):}%"),
|
||||||
('Trades per day', strat_results['trades_per_day']),
|
('Trades per day', strat_results['trades_per_day']),
|
||||||
('Avg. stake amount', round_coin_value(strat_results['avg_stake_amount'],
|
('Avg. stake amount', round_coin_value(strat_results['avg_stake_amount'],
|
||||||
strat_results['stake_currency'])),
|
strat_results['stake_currency'])),
|
||||||
@ -532,6 +579,7 @@ def text_table_add_metrics(strat_results: Dict) -> str:
|
|||||||
f"{strat_results['draw_days']} / {strat_results['losing_days']}"),
|
f"{strat_results['draw_days']} / {strat_results['losing_days']}"),
|
||||||
('Avg. Duration Winners', f"{strat_results['winner_holding_avg']}"),
|
('Avg. Duration Winners', f"{strat_results['winner_holding_avg']}"),
|
||||||
('Avg. Duration Loser', f"{strat_results['loser_holding_avg']}"),
|
('Avg. Duration Loser', f"{strat_results['loser_holding_avg']}"),
|
||||||
|
('Zero Duration Trades', zero_duration_trades),
|
||||||
('', ''), # Empty line to improve readability
|
('', ''), # Empty line to improve readability
|
||||||
|
|
||||||
('Min balance', round_coin_value(strat_results['csum_min'],
|
('Min balance', round_coin_value(strat_results['csum_min'],
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import datetime
|
||||||
import re
|
import re
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -27,25 +28,22 @@ def test_text_table_bt_results():
|
|||||||
|
|
||||||
results = pd.DataFrame(
|
results = pd.DataFrame(
|
||||||
{
|
{
|
||||||
'pair': ['ETH/BTC', 'ETH/BTC'],
|
'pair': ['ETH/BTC', 'ETH/BTC', 'ETH/BTC'],
|
||||||
'profit_ratio': [0.1, 0.2],
|
'profit_ratio': [0.1, 0.2, -0.05],
|
||||||
'profit_abs': [0.2, 0.4],
|
'profit_abs': [0.2, 0.4, -0.1],
|
||||||
'trade_duration': [10, 30],
|
'trade_duration': [10, 30, 20],
|
||||||
'wins': [2, 0],
|
|
||||||
'draws': [0, 0],
|
|
||||||
'losses': [0, 0]
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
result_str = (
|
result_str = (
|
||||||
'| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC |'
|
'| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % |'
|
||||||
' Tot Profit % | Avg Duration | Wins | Draws | Losses |\n'
|
' Avg Duration | Win Draw Loss Win% |\n'
|
||||||
'|---------+--------+----------------+----------------+------------------+'
|
'|---------+--------+----------------+----------------+------------------+----------------+'
|
||||||
'----------------+----------------+--------+---------+----------|\n'
|
'----------------+-------------------------|\n'
|
||||||
'| ETH/BTC | 2 | 15.00 | 30.00 | 0.60000000 |'
|
'| ETH/BTC | 3 | 8.33 | 25.00 | 0.50000000 | 12.50 |'
|
||||||
' 15.00 | 0:20:00 | 2 | 0 | 0 |\n'
|
' 0:20:00 | 2 0 1 66.7 |\n'
|
||||||
'| TOTAL | 2 | 15.00 | 30.00 | 0.60000000 |'
|
'| TOTAL | 3 | 8.33 | 25.00 | 0.50000000 | 12.50 |'
|
||||||
' 15.00 | 0:20:00 | 2 | 0 | 0 |'
|
' 0:20:00 | 2 0 1 66.7 |'
|
||||||
)
|
)
|
||||||
|
|
||||||
pair_results = generate_pair_metrics(data={'ETH/BTC': {}}, stake_currency='BTC',
|
pair_results = generate_pair_metrics(data={'ETH/BTC': {}}, stake_currency='BTC',
|
||||||
@ -270,14 +268,14 @@ def test_text_table_sell_reason():
|
|||||||
)
|
)
|
||||||
|
|
||||||
result_str = (
|
result_str = (
|
||||||
'| Sell Reason | Sells | Wins | Draws | Losses |'
|
'| Sell Reason | Sells | Win Draws Loss Win% | Avg Profit % | Cum Profit % |'
|
||||||
' Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % |\n'
|
' Tot Profit BTC | Tot Profit % |\n'
|
||||||
'|---------------+---------+--------+---------+----------+'
|
'|---------------+---------+--------------------------+----------------+----------------+'
|
||||||
'----------------+----------------+------------------+----------------|\n'
|
'------------------+----------------|\n'
|
||||||
'| roi | 2 | 2 | 0 | 0 |'
|
'| roi | 2 | 2 0 0 100 | 15 | 30 |'
|
||||||
' 15 | 30 | 0.6 | 15 |\n'
|
' 0.6 | 15 |\n'
|
||||||
'| stop_loss | 1 | 0 | 0 | 1 |'
|
'| stop_loss | 1 | 0 0 1 0 | -10 | -10 |'
|
||||||
' -10 | -10 | -0.2 | -5 |'
|
' -0.2 | -5 |'
|
||||||
)
|
)
|
||||||
|
|
||||||
sell_reason_stats = generate_sell_reason_stats(max_open_trades=2,
|
sell_reason_stats = generate_sell_reason_stats(max_open_trades=2,
|
||||||
@ -325,9 +323,12 @@ def test_text_table_strategy(default_conf):
|
|||||||
default_conf['max_open_trades'] = 2
|
default_conf['max_open_trades'] = 2
|
||||||
default_conf['dry_run_wallet'] = 3
|
default_conf['dry_run_wallet'] = 3
|
||||||
results = {}
|
results = {}
|
||||||
|
date = datetime.datetime(year=2020, month=1, day=1, hour=12, minute=30)
|
||||||
|
delta = datetime.timedelta(days=1)
|
||||||
results['TestStrategy1'] = {'results': pd.DataFrame(
|
results['TestStrategy1'] = {'results': pd.DataFrame(
|
||||||
{
|
{
|
||||||
'pair': ['ETH/BTC', 'ETH/BTC', 'ETH/BTC'],
|
'pair': ['ETH/BTC', 'ETH/BTC', 'ETH/BTC'],
|
||||||
|
'close_date': [date, date + delta, date + delta * 2],
|
||||||
'profit_ratio': [0.1, 0.2, 0.3],
|
'profit_ratio': [0.1, 0.2, 0.3],
|
||||||
'profit_abs': [0.2, 0.4, 0.5],
|
'profit_abs': [0.2, 0.4, 0.5],
|
||||||
'trade_duration': [10, 30, 10],
|
'trade_duration': [10, 30, 10],
|
||||||
@ -340,6 +341,7 @@ def test_text_table_strategy(default_conf):
|
|||||||
results['TestStrategy2'] = {'results': pd.DataFrame(
|
results['TestStrategy2'] = {'results': pd.DataFrame(
|
||||||
{
|
{
|
||||||
'pair': ['LTC/BTC', 'LTC/BTC', 'LTC/BTC'],
|
'pair': ['LTC/BTC', 'LTC/BTC', 'LTC/BTC'],
|
||||||
|
'close_date': [date, date + delta, date + delta * 2],
|
||||||
'profit_ratio': [0.4, 0.2, 0.3],
|
'profit_ratio': [0.4, 0.2, 0.3],
|
||||||
'profit_abs': [0.4, 0.4, 0.5],
|
'profit_abs': [0.4, 0.4, 0.5],
|
||||||
'trade_duration': [15, 30, 15],
|
'trade_duration': [15, 30, 15],
|
||||||
@ -351,18 +353,17 @@ def test_text_table_strategy(default_conf):
|
|||||||
), 'config': default_conf}
|
), 'config': default_conf}
|
||||||
|
|
||||||
result_str = (
|
result_str = (
|
||||||
'| Strategy | Buys | Avg Profit % | Cum Profit % | Tot'
|
'| Strategy | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC |'
|
||||||
' Profit BTC | Tot Profit % | Avg Duration | Wins | Draws | Losses |\n'
|
' Tot Profit % | Avg Duration | Win Draw Loss Win% | Drawdown |\n'
|
||||||
'|---------------+--------+----------------+----------------+------------------+'
|
'|---------------+--------+----------------+----------------+------------------+'
|
||||||
'----------------+----------------+--------+---------+----------|\n'
|
'----------------+----------------+-------------------------+-----------------------|\n'
|
||||||
'| TestStrategy1 | 3 | 20.00 | 60.00 | 1.10000000 |'
|
'| TestStrategy1 | 3 | 20.00 | 60.00 | 1.10000000 |'
|
||||||
' 36.67 | 0:17:00 | 3 | 0 | 0 |\n'
|
' 36.67 | 0:17:00 | 3 0 0 100 | 0.00000000 BTC 0.00% |\n'
|
||||||
'| TestStrategy2 | 3 | 30.00 | 90.00 | 1.30000000 |'
|
'| TestStrategy2 | 3 | 30.00 | 90.00 | 1.30000000 |'
|
||||||
' 43.33 | 0:20:00 | 3 | 0 | 0 |'
|
' 43.33 | 0:20:00 | 3 0 0 100 | 0.00000000 BTC 0.00% |'
|
||||||
)
|
)
|
||||||
|
|
||||||
strategy_results = generate_strategy_comparison(all_results=results)
|
strategy_results = generate_strategy_comparison(all_results=results)
|
||||||
|
|
||||||
assert text_table_strategy(strategy_results, 'BTC') == result_str
|
assert text_table_strategy(strategy_results, 'BTC') == result_str
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user