feat: Add "replace-exit_order" to backtesting

This commit is contained in:
Matthias
2025-02-20 19:09:36 +01:00
parent 25c0036012
commit 756bada570

View File

@@ -396,6 +396,8 @@ class Backtesting:
self.canceled_trade_entries = 0
self.canceled_entry_orders = 0
self.replaced_entry_orders = 0
self.canceled_exit_orders = 0
self.replaced_exit_orders = 0
self.dataprovider.clear_cache()
if enable_protections:
self._load_protections(self.strategy)
@@ -1234,8 +1236,8 @@ class Backtesting:
for order in [o for o in trade.orders if o.ft_is_open]:
if order.side == trade.entry_side:
self.canceled_entry_orders += 1
# elif order.side == trade.exit_side:
# self.canceled_exit_orders += 1
elif order.side == trade.exit_side:
self.canceled_exit_orders += 1
# canceled orders are removed from the trade
del trade.orders[trade.orders.index(order)]
@@ -1300,8 +1302,9 @@ class Backtesting:
"""
# only check on new candles for open entry orders
if order.side == trade.entry_side and current_time > order.order_date_utc:
is_entry = order.side == trade.entry_side
requested_rate = strategy_safe_wrapper(
self.strategy.adjust_entry_price, default_retval=order.ft_price
self.strategy.adjust_order_price, default_retval=order.ft_price
)(
trade=trade, # type: ignore[arg-type]
order=order,
@@ -1311,6 +1314,7 @@ class Backtesting:
current_order_rate=order.ft_price,
entry_tag=trade.enter_tag,
side=trade.trade_direction,
is_entry=is_entry,
) # default value is current order price
# cancel existing order whenever a new rate is requested (or None)
@@ -1319,22 +1323,35 @@ class Backtesting:
return False
else:
del trade.orders[trade.orders.index(order)]
self.canceled_entry_orders += 1
if is_entry:
self.canceled_entry_orders += 1
else:
self.canceled_exit_orders += 1
# place new order if result was not None
if requested_rate:
self._enter_trade(
pair=trade.pair,
row=row,
trade=trade,
requested_rate=requested_rate,
requested_stake=(order.safe_remaining * order.ft_price / trade.leverage),
direction="short" if trade.is_short else "long",
)
if is_entry:
self._enter_trade(
pair=trade.pair,
row=row,
trade=trade,
requested_rate=requested_rate,
requested_stake=(order.safe_remaining * order.ft_price / trade.leverage),
direction="short" if trade.is_short else "long",
)
self.replaced_entry_orders += 1
else:
self._exit_trade(
trade=trade,
sell_row=row,
close_rate=requested_rate,
amount=order.safe_remaining,
exit_reason=order.ft_order_tag,
)
self.replaced_exit_orders += 1
# Delete trade if no successful entries happened (if placing the new order failed)
if not trade.has_open_orders and trade.nr_of_successful_entries == 0:
if not trade.has_open_orders and is_entry and trade.nr_of_successful_entries == 0:
return True
self.replaced_entry_orders += 1
else:
# assumption: there can't be multiple open entry orders at any given time
return trade.nr_of_successful_entries == 0