Backtest-reports should calculate total gains based on starting capital
This commit is contained in:
parent
8d61a26382
commit
35e6a9ab3a
@ -252,7 +252,10 @@ A backtesting result will look like that:
|
||||
| Max open trades | 3 |
|
||||
| | |
|
||||
| Total trades | 429 |
|
||||
| Total Profit % | 152.41% |
|
||||
| Starting capital | 0.01000000 BTC |
|
||||
| End capital | 0.01762792 BTC |
|
||||
| Absolute profit | 0.00762792 BTC |
|
||||
| Total Profit % | 76.2% |
|
||||
| Trades per day | 3.575 |
|
||||
| | |
|
||||
| Best Pair | LSK/BTC 26.26% |
|
||||
@ -261,6 +264,7 @@ A backtesting result will look like that:
|
||||
| Worst Trade | ZEC/BTC -10.25% |
|
||||
| Best day | 25.27% |
|
||||
| Worst day | -30.67% |
|
||||
| Days win/draw/lose | 12 / 82 / 25 |
|
||||
| Avg. Duration Winners | 4:23:00 |
|
||||
| Avg. Duration Loser | 6:55:00 |
|
||||
| | |
|
||||
@ -328,7 +332,10 @@ It contains some useful key metrics about performance of your strategy on backte
|
||||
| Max open trades | 3 |
|
||||
| | |
|
||||
| Total trades | 429 |
|
||||
| Total Profit % | 152.41% |
|
||||
| Starting capital | 0.01000000 BTC |
|
||||
| End capital | 0.01762792 BTC |
|
||||
| Absolute profit | 0.00762792 BTC |
|
||||
| Total Profit % | 76.2% |
|
||||
| Trades per day | 3.575 |
|
||||
| | |
|
||||
| Best Pair | LSK/BTC 26.26% |
|
||||
@ -337,6 +344,7 @@ It contains some useful key metrics about performance of your strategy on backte
|
||||
| Worst Trade | ZEC/BTC -10.25% |
|
||||
| Best day | 25.27% |
|
||||
| Worst day | -30.67% |
|
||||
| Days win/draw/lose | 12 / 82 / 25 |
|
||||
| Avg. Duration Winners | 4:23:00 |
|
||||
| Avg. Duration Loser | 6:55:00 |
|
||||
| | |
|
||||
@ -351,11 +359,15 @@ It contains some useful key metrics about performance of your strategy on backte
|
||||
- `Backtesting from` / `Backtesting to`: Backtesting range (usually defined with the `--timerange` option).
|
||||
- `Max open trades`: Setting of `max_open_trades` (or `--max-open-trades`) - or number of pairs in the pairlist (whatever is lower).
|
||||
- `Total trades`: Identical to the total trades of the backtest output table.
|
||||
- `Total Profit %`: Total profit. Aligned to the `TOTAL` row's `Tot Profit %` from the first table.
|
||||
- `Starting capital`: Start capital - as given by dry-run-wallet (config or command line).
|
||||
- `End capital`: Final capital - starting capital + absolute profit.
|
||||
- `Absolute profit`: Profit made in stake currency.
|
||||
- `Total Profit %`: Total profit. Aligned to the `TOTAL` row's `Tot Profit %` from the first table. Calculated as `(End capital − Starting capital) / Starting capital`.
|
||||
- `Trades per day`: Total trades divided by the backtesting duration in days (this will give you information about how many trades to expect from the strategy).
|
||||
- `Best Pair` / `Worst Pair`: Best and worst performing pair, and it's corresponding `Cum Profit %`.
|
||||
- `Best Trade` / `Worst Trade`: Biggest winning trade and biggest losing trade
|
||||
- `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).
|
||||
- `Avg. Duration Winners` / `Avg. Duration Loser`: Average durations for winning and losing trades.
|
||||
- `Max Drawdown`: Maximum drawdown experienced. For example, the value of 50% means that from highest to subsequent lowest point, a 50% drop was experienced).
|
||||
- `Drawdown Start` / `Drawdown End`: Start and end datetime for this largest drawdown (can also be visualized via the `plot-dataframe` sub-command).
|
||||
|
@ -56,12 +56,13 @@ def _get_line_header(first_column: str, stake_currency: str) -> List[str]:
|
||||
'Wins', 'Draws', 'Losses']
|
||||
|
||||
|
||||
def _generate_result_line(result: DataFrame, max_open_trades: int, first_column: str) -> Dict:
|
||||
def _generate_result_line(result: DataFrame, starting_balance: int, first_column: str) -> Dict:
|
||||
"""
|
||||
Generate one result dict, with "first_column" as key.
|
||||
"""
|
||||
profit_sum = result['profit_ratio'].sum()
|
||||
profit_total = profit_sum / max_open_trades
|
||||
# (end-capital - starting capital) / starting capital
|
||||
profit_total = result['profit_abs'].sum() / starting_balance
|
||||
|
||||
return {
|
||||
'key': first_column,
|
||||
@ -88,13 +89,13 @@ def _generate_result_line(result: DataFrame, max_open_trades: int, first_column:
|
||||
}
|
||||
|
||||
|
||||
def generate_pair_metrics(data: Dict[str, Dict], stake_currency: str, max_open_trades: int,
|
||||
def generate_pair_metrics(data: Dict[str, Dict], stake_currency: str, starting_balance: int,
|
||||
results: DataFrame, skip_nan: bool = False) -> List[Dict]:
|
||||
"""
|
||||
Generates and returns a list for the given backtest data and the results dataframe
|
||||
:param data: Dict of <pair: dataframe> containing data that was used during backtesting.
|
||||
:param stake_currency: stake-currency - used to correctly name headers
|
||||
:param max_open_trades: Maximum allowed open trades
|
||||
:param starting_balance: Starting balance
|
||||
:param results: Dataframe containing the backtest results
|
||||
:param skip_nan: Print "left open" open trades
|
||||
:return: List of Dicts containing the metrics per pair
|
||||
@ -107,10 +108,10 @@ def generate_pair_metrics(data: Dict[str, Dict], stake_currency: str, max_open_t
|
||||
if skip_nan and result['profit_abs'].isnull().all():
|
||||
continue
|
||||
|
||||
tabular_data.append(_generate_result_line(result, max_open_trades, pair))
|
||||
tabular_data.append(_generate_result_line(result, starting_balance, pair))
|
||||
|
||||
# Append Total
|
||||
tabular_data.append(_generate_result_line(results, max_open_trades, 'TOTAL'))
|
||||
tabular_data.append(_generate_result_line(results, starting_balance, 'TOTAL'))
|
||||
return tabular_data
|
||||
|
||||
|
||||
@ -159,7 +160,7 @@ def generate_strategy_metrics(all_results: Dict) -> List[Dict]:
|
||||
tabular_data = []
|
||||
for strategy, results in all_results.items():
|
||||
tabular_data.append(_generate_result_line(
|
||||
results['results'], results['config']['max_open_trades'], strategy)
|
||||
results['results'], results['config']['dry_run_wallet'], strategy)
|
||||
)
|
||||
return tabular_data
|
||||
|
||||
@ -246,15 +247,16 @@ def generate_backtest_stats(btdata: Dict[str, 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,
|
||||
max_open_trades=max_open_trades,
|
||||
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,
|
||||
max_open_trades=max_open_trades,
|
||||
starting_balance=starting_balance,
|
||||
results=results.loc[results['is_open']],
|
||||
skip_nan=True)
|
||||
daily_stats = generate_daily_stats(results)
|
||||
@ -276,7 +278,7 @@ def generate_backtest_stats(btdata: Dict[str, DataFrame],
|
||||
'left_open_trades': left_open_results,
|
||||
'total_trades': len(results),
|
||||
'profit_mean': results['profit_ratio'].mean() if len(results) > 0 else 0,
|
||||
'profit_total': results['profit_ratio'].sum() / max_open_trades,
|
||||
'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,
|
||||
@ -292,6 +294,9 @@ def generate_backtest_stats(btdata: Dict[str, DataFrame],
|
||||
'pairlist': list(btdata.keys()),
|
||||
'stake_amount': config['stake_amount'],
|
||||
'stake_currency': 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),
|
||||
@ -431,6 +436,13 @@ def text_table_add_metrics(strat_results: Dict) -> str:
|
||||
('Max open trades', strat_results['max_open_trades']),
|
||||
('', ''), # Empty line to improve readability
|
||||
('Total trades', strat_results['total_trades']),
|
||||
('Starting capital', round_coin_value(strat_results['starting_balance'],
|
||||
strat_results['stake_currency'])),
|
||||
('End capital', round_coin_value(strat_results['final_balance'],
|
||||
strat_results['stake_currency'])),
|
||||
('Absolute profit ', round_coin_value(strat_results['profit_total_abs'],
|
||||
strat_results['stake_currency'])),
|
||||
|
||||
('Total Profit %', f"{round(strat_results['profit_total'] * 100, 2)}%"),
|
||||
('Trades per day', strat_results['trades_per_day']),
|
||||
('', ''), # Empty line to improve readability
|
||||
|
@ -261,6 +261,7 @@ def get_default_conf(testdatadir):
|
||||
"20": 0.02,
|
||||
"0": 0.04
|
||||
},
|
||||
"dry_run_wallet": 1000,
|
||||
"stoploss": -0.10,
|
||||
"unfilledtimeout": {
|
||||
"buy": 10,
|
||||
|
@ -48,7 +48,7 @@ def test_text_table_bt_results():
|
||||
)
|
||||
|
||||
pair_results = generate_pair_metrics(data={'ETH/BTC': {}}, stake_currency='BTC',
|
||||
max_open_trades=2, results=results)
|
||||
starting_balance=4, results=results)
|
||||
assert text_table_bt_results(pair_results, stake_currency='BTC') == result_str
|
||||
|
||||
|
||||
@ -78,6 +78,7 @@ def test_generate_backtest_stats(default_conf, testdatadir):
|
||||
}),
|
||||
'config': default_conf,
|
||||
'locks': [],
|
||||
'final_balance': 1000.02,
|
||||
'backtest_start_time': Arrow.utcnow().int_timestamp,
|
||||
'backtest_end_time': Arrow.utcnow().int_timestamp,
|
||||
}
|
||||
@ -189,7 +190,7 @@ def test_generate_pair_metrics():
|
||||
)
|
||||
|
||||
pair_results = generate_pair_metrics(data={'ETH/BTC': {}}, stake_currency='BTC',
|
||||
max_open_trades=2, results=results)
|
||||
starting_balance=2, results=results)
|
||||
assert isinstance(pair_results, list)
|
||||
assert len(pair_results) == 2
|
||||
assert pair_results[-1]['key'] == 'TOTAL'
|
||||
@ -291,6 +292,7 @@ def test_generate_sell_reason_stats():
|
||||
|
||||
def test_text_table_strategy(default_conf):
|
||||
default_conf['max_open_trades'] = 2
|
||||
default_conf['dry_run_wallet'] = 3
|
||||
results = {}
|
||||
results['TestStrategy1'] = {'results': pd.DataFrame(
|
||||
{
|
||||
@ -323,9 +325,9 @@ def test_text_table_strategy(default_conf):
|
||||
'|---------------+--------+----------------+----------------+------------------+'
|
||||
'----------------+----------------+--------+---------+----------|\n'
|
||||
'| TestStrategy1 | 3 | 20.00 | 60.00 | 1.10000000 |'
|
||||
' 30.00 | 0:17:00 | 3 | 0 | 0 |\n'
|
||||
' 36.67 | 0:17:00 | 3 | 0 | 0 |\n'
|
||||
'| TestStrategy2 | 3 | 30.00 | 90.00 | 1.30000000 |'
|
||||
' 45.00 | 0:20:00 | 3 | 0 | 0 |'
|
||||
' 43.33 | 0:20:00 | 3 | 0 | 0 |'
|
||||
)
|
||||
|
||||
strategy_results = generate_strategy_metrics(all_results=results)
|
||||
|
Loading…
Reference in New Issue
Block a user