Extract backtest 1 candle from main function
This commit is contained in:
parent
0e8cf366f5
commit
8534dfb0d4
@ -1067,54 +1067,15 @@ class Backtesting:
|
|||||||
return None
|
return None
|
||||||
return row
|
return row
|
||||||
|
|
||||||
def backtest(self, processed: Dict, # noqa: max-complexity: 13
|
def backtest_loop(
|
||||||
start_date: datetime, end_date: datetime,
|
self, row: Tuple, pair: str, current_time: datetime, end_date: datetime,
|
||||||
max_open_trades: int = 0, position_stacking: bool = False,
|
max_open_trades: int, position_stacking: bool, enable_protections: bool,
|
||||||
enable_protections: bool = False) -> Dict[str, Any]:
|
open_trade_count_start: int) -> int:
|
||||||
"""
|
"""
|
||||||
Implement backtesting functionality
|
|
||||||
|
|
||||||
NOTE: This method is used by Hyperopt at each iteration. Please keep it optimized.
|
NOTE: This method is used by Hyperopt at each iteration. Please keep it optimized.
|
||||||
Of course try to not have ugly code. By some accessor are sometime slower than functions.
|
|
||||||
Avoid extensive logging in this method and functions it calls.
|
|
||||||
|
|
||||||
:param processed: a processed dictionary with format {pair, data}, which gets cleared to
|
Backtesting processing for one candle.
|
||||||
optimize memory usage!
|
|
||||||
:param start_date: backtesting timerange start datetime
|
|
||||||
:param end_date: backtesting timerange end datetime
|
|
||||||
:param max_open_trades: maximum number of concurrent trades, <= 0 means unlimited
|
|
||||||
:param position_stacking: do we allow position stacking?
|
|
||||||
:param enable_protections: Should protections be enabled?
|
|
||||||
:return: DataFrame with trades (results of backtesting)
|
|
||||||
"""
|
"""
|
||||||
self.prepare_backtest(enable_protections)
|
|
||||||
# Ensure wallets are uptodate (important for --strategy-list)
|
|
||||||
self.wallets.update()
|
|
||||||
# Use dict of lists with data for performance
|
|
||||||
# (looping lists is a lot faster than pandas DataFrames)
|
|
||||||
data: Dict = self._get_ohlcv_as_lists(processed)
|
|
||||||
|
|
||||||
# Indexes per pair, so some pairs are allowed to have a missing start.
|
|
||||||
indexes: Dict = defaultdict(int)
|
|
||||||
current_time = start_date + timedelta(minutes=self.timeframe_min)
|
|
||||||
|
|
||||||
self.progress.init_step(BacktestState.BACKTEST, int(
|
|
||||||
(end_date - start_date) / timedelta(minutes=self.timeframe_min)))
|
|
||||||
|
|
||||||
# Loop timerange and get candle for each pair at that point in time
|
|
||||||
while current_time <= end_date:
|
|
||||||
open_trade_count_start = LocalTrade.bt_open_open_trade_count
|
|
||||||
self.check_abort()
|
|
||||||
for i, pair in enumerate(data):
|
|
||||||
row_index = indexes[pair]
|
|
||||||
row = self.validate_row(data, pair, row_index, current_time)
|
|
||||||
if not row:
|
|
||||||
continue
|
|
||||||
|
|
||||||
row_index += 1
|
|
||||||
indexes[pair] = row_index
|
|
||||||
self.dataprovider._set_dataframe_max_index(row_index)
|
|
||||||
|
|
||||||
for t in list(LocalTrade.bt_trades_open_pp[pair]):
|
for t in list(LocalTrade.bt_trades_open_pp[pair]):
|
||||||
# 1. Manage currently open orders of active trades
|
# 1. Manage currently open orders of active trades
|
||||||
if self.manage_open_orders(t, current_time, row):
|
if self.manage_open_orders(t, current_time, row):
|
||||||
@ -1173,8 +1134,60 @@ class Backtesting:
|
|||||||
# logger.debug(f"{pair} - Backtesting exit {trade}")
|
# logger.debug(f"{pair} - Backtesting exit {trade}")
|
||||||
LocalTrade.close_bt_trade(trade)
|
LocalTrade.close_bt_trade(trade)
|
||||||
self.wallets.update()
|
self.wallets.update()
|
||||||
self.run_protections(
|
self.run_protections(enable_protections, pair, current_time, trade.trade_direction)
|
||||||
enable_protections, pair, current_time, trade.trade_direction)
|
return open_trade_count_start
|
||||||
|
|
||||||
|
def backtest(self, processed: Dict, # noqa: max-complexity: 13
|
||||||
|
start_date: datetime, end_date: datetime,
|
||||||
|
max_open_trades: int = 0, position_stacking: bool = False,
|
||||||
|
enable_protections: bool = False) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Implement backtesting functionality
|
||||||
|
|
||||||
|
NOTE: This method is used by Hyperopt at each iteration. Please keep it optimized.
|
||||||
|
Of course try to not have ugly code. By some accessor are sometime slower than functions.
|
||||||
|
Avoid extensive logging in this method and functions it calls.
|
||||||
|
|
||||||
|
:param processed: a processed dictionary with format {pair, data}, which gets cleared to
|
||||||
|
optimize memory usage!
|
||||||
|
:param start_date: backtesting timerange start datetime
|
||||||
|
:param end_date: backtesting timerange end datetime
|
||||||
|
:param max_open_trades: maximum number of concurrent trades, <= 0 means unlimited
|
||||||
|
:param position_stacking: do we allow position stacking?
|
||||||
|
:param enable_protections: Should protections be enabled?
|
||||||
|
:return: DataFrame with trades (results of backtesting)
|
||||||
|
"""
|
||||||
|
self.prepare_backtest(enable_protections)
|
||||||
|
# Ensure wallets are uptodate (important for --strategy-list)
|
||||||
|
self.wallets.update()
|
||||||
|
# Use dict of lists with data for performance
|
||||||
|
# (looping lists is a lot faster than pandas DataFrames)
|
||||||
|
data: Dict = self._get_ohlcv_as_lists(processed)
|
||||||
|
|
||||||
|
# Indexes per pair, so some pairs are allowed to have a missing start.
|
||||||
|
indexes: Dict = defaultdict(int)
|
||||||
|
current_time = start_date + timedelta(minutes=self.timeframe_min)
|
||||||
|
|
||||||
|
self.progress.init_step(BacktestState.BACKTEST, int(
|
||||||
|
(end_date - start_date) / timedelta(minutes=self.timeframe_min)))
|
||||||
|
|
||||||
|
# Loop timerange and get candle for each pair at that point in time
|
||||||
|
while current_time <= end_date:
|
||||||
|
open_trade_count_start = LocalTrade.bt_open_open_trade_count
|
||||||
|
self.check_abort()
|
||||||
|
for i, pair in enumerate(data):
|
||||||
|
row_index = indexes[pair]
|
||||||
|
row = self.validate_row(data, pair, row_index, current_time)
|
||||||
|
if not row:
|
||||||
|
continue
|
||||||
|
|
||||||
|
row_index += 1
|
||||||
|
indexes[pair] = row_index
|
||||||
|
self.dataprovider._set_dataframe_max_index(row_index)
|
||||||
|
|
||||||
|
open_trade_count_start = self.backtest_loop(
|
||||||
|
row, pair, current_time, end_date, max_open_trades,
|
||||||
|
position_stacking, enable_protections, open_trade_count_start)
|
||||||
|
|
||||||
# Move time one configured time_interval ahead.
|
# Move time one configured time_interval ahead.
|
||||||
self.progress.increment()
|
self.progress.increment()
|
||||||
|
Loading…
Reference in New Issue
Block a user