Backtesting does not need to convert to BacktestResult object

This commit is contained in:
Matthias
2021-01-23 12:50:20 +01:00
parent 3b51545d23
commit 48977493bb
4 changed files with 25 additions and 42 deletions

View File

@@ -9,7 +9,7 @@ from copy import deepcopy
from datetime import datetime, timedelta, timezone
from typing import Any, Dict, List, NamedTuple, Optional, Tuple
from pandas import DataFrame
from pandas import DataFrame, to_datetime
from freqtrade.configuration import TimeRange, remove_credentials, validate_config_consistency
from freqtrade.constants import DATETIME_PRINT_FORMAT
@@ -264,7 +264,7 @@ class Backtesting:
else:
return sell_row[OPEN_IDX]
def _get_sell_trade_entry(self, trade: Trade, sell_row: Tuple) -> Optional[BacktestResult]:
def _get_sell_trade_entry(self, trade: Trade, sell_row: Tuple) -> Optional[Trade]:
sell = self.strategy.should_sell(trade, sell_row[OPEN_IDX], sell_row[DATE_IDX],
sell_row[BUY_IDX], sell_row[SELL_IDX],
@@ -276,25 +276,12 @@ class Backtesting:
trade.close_date = sell_row[DATE_IDX]
trade.sell_reason = sell.sell_type
trade.close(closerate, show_msg=False)
return trade
return BacktestResult(pair=trade.pair,
profit_percent=trade.calc_profit_ratio(rate=closerate),
profit_abs=trade.calc_profit(rate=closerate),
open_date=trade.open_date,
open_rate=trade.open_rate,
open_fee=self.fee,
close_date=sell_row[DATE_IDX],
close_rate=closerate,
close_fee=self.fee,
amount=trade.amount,
trade_duration=trade_dur,
open_at_end=False,
sell_reason=sell.sell_type
)
return None
def handle_left_open(self, open_trades: Dict[str, List[Trade]],
data: Dict[str, List[Tuple]]) -> List[BacktestResult]:
data: Dict[str, List[Tuple]]) -> List[Trade]:
"""
Handling of left open trades at the end of backtesting
"""
@@ -304,24 +291,11 @@ class Backtesting:
for trade in open_trades[pair]:
sell_row = data[pair][-1]
trade_entry = BacktestResult(pair=trade.pair,
profit_percent=trade.calc_profit_ratio(
rate=sell_row[OPEN_IDX]),
profit_abs=trade.calc_profit(sell_row[OPEN_IDX]),
open_date=trade.open_date,
open_rate=trade.open_rate,
open_fee=self.fee,
close_date=sell_row[DATE_IDX],
close_rate=sell_row[OPEN_IDX],
close_fee=self.fee,
amount=trade.amount,
trade_duration=int((
sell_row[DATE_IDX] - trade.open_date
).total_seconds() // 60),
open_at_end=True,
sell_reason=SellType.FORCE_SELL
)
trades.append(trade_entry)
trade.close_date = sell_row[DATE_IDX]
trade.sell_reason = SellType.FORCE_SELL
trade.close(sell_row[OPEN_IDX], show_msg=False)
trade.is_open = True
trades.append(trade)
return trades
def backtest(self, processed: Dict, stake_amount: float,
@@ -348,7 +322,7 @@ class Backtesting:
f"start_date: {start_date}, end_date: {end_date}, "
f"max_open_trades: {max_open_trades}, position_stacking: {position_stacking}"
)
trades = []
trades: List[Trade] = []
self.prepare_backtest(enable_protections)
# Use dict of lists with data for performance
@@ -429,7 +403,16 @@ class Backtesting:
trades += self.handle_left_open(open_trades, data=data)
return DataFrame.from_records(trades, columns=BacktestResult._fields)
cols = ['pair', 'stake_amount', 'amount', 'open_date', 'close_date',
'open_fee', 'close_fee', 'trade_duration',
'profit_ratio', 'profit_percent', 'profit_abs', 'sell_reason',
'initial_stop_loss_abs', 'initial_stop_loss_ratio' 'stop_loss', 'stop_loss_ratio',
'min_rate', 'max_rate', 'is_open', ]
df = DataFrame.from_records([t.to_json() for t in trades], columns=cols)
if len(df) > 0:
df.loc[:, 'close_date'] = to_datetime(df['close_date'], utc=True)
df.loc[:, 'open_date'] = to_datetime(df['open_date'], utc=True)
return df
def backtest_one_strategy(self, strat: IStrategy, data: Dict[str, Any], timerange: TimeRange):
logger.info("Running backtesting for Strategy %s", strat.get_strategy_name())

View File

@@ -253,7 +253,7 @@ def generate_backtest_stats(btdata: Dict[str, DataFrame],
results=results)
left_open_results = generate_pair_metrics(btdata, stake_currency=stake_currency,
max_open_trades=max_open_trades,
results=results.loc[results['open_at_end']],
results=results.loc[results['is_open']],
skip_nan=True)
daily_stats = generate_daily_stats(results)
best_pair = max([pair for pair in pair_results if pair['key'] != 'TOTAL'],