Use Order object for ft_timeout check

This commit is contained in:
Matthias 2022-01-30 17:47:37 +01:00
parent 1e603985c5
commit 4ea79a32e4
4 changed files with 29 additions and 13 deletions

View File

@ -987,18 +987,20 @@ class FreqtradeBot(LoggingMixin):
fully_cancelled = self.update_trade_state(trade, trade.open_order_id, order)
order_obj = trade.select_order_by_order_id(trade.open_order_id)
if (order['side'] == 'buy' and (order['status'] == 'open' or fully_cancelled) and (
fully_cancelled
or self.strategy.ft_check_timed_out(
'buy', trade, order, datetime.now(timezone.utc))
)):
or (order_obj and self.strategy.ft_check_timed_out(
'buy', trade, order_obj, datetime.now(timezone.utc))
))):
self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['TIMEOUT'])
elif (order['side'] == 'sell' and (order['status'] == 'open' or fully_cancelled) and (
fully_cancelled
or self.strategy.ft_check_timed_out(
'sell', trade, order, datetime.now(timezone.utc)))
):
or (order_obj and self.strategy.ft_check_timed_out(
'sell', trade, order_obj, datetime.now(timezone.utc))
))):
self.handle_cancel_exit(trade, order, constants.CANCEL_REASON['TIMEOUT'])
canceled_count = trade.get_exit_order_count()
max_timeouts = self.config.get('unfilledtimeout', {}).get('exit_timeout_count', 0)

View File

@ -593,7 +593,7 @@ class Backtesting:
if pos_adjust and self._get_order_filled(order.price, row):
order.close_bt_order(current_time)
else:
trade.open_order_id = self.order_id_counter
trade.open_order_id = str(self.order_id_counter)
trade.orders.append(order)
trade.recalc_trade_from_orders()
@ -642,7 +642,7 @@ class Backtesting:
"""
for order in [o for o in trade.orders if o.ft_is_open]:
timedout = self.strategy.ft_check_timed_out(order.side, trade, {}, current_time)
timedout = self.strategy.ft_check_timed_out(order.side, trade, order, current_time)
if timedout:
if order.side == 'buy':
if trade.nr_of_successful_buys == 0:

View File

@ -132,6 +132,10 @@ class Order(_DECL_BASE):
order_filled_date = Column(DateTime, nullable=True)
order_update_date = Column(DateTime, nullable=True)
@property
def order_date_utc(self):
return self.order_date.replace(tzinfo=timezone.utc)
def __repr__(self):
return (f'Order(id={self.id}, order_id={self.order_id}, trade_id={self.ft_trade_id}, '
@ -641,6 +645,16 @@ class LocalTrade():
if self.stop_loss_pct is not None and self.open_rate is not None:
self.adjust_stop_loss(self.open_rate, self.stop_loss_pct)
def select_order_by_order_id(self, order_id: str) -> Optional[Order]:
"""
Finds order object by Order id.
:param order_id: Exchange order id
"""
orders = [o for o in self.orders if o.order_id == order_id]
if orders:
return orders[0]
return None
def select_order(
self, order_side: str = None, is_open: Optional[bool] = None) -> Optional[Order]:
"""

View File

@ -18,6 +18,7 @@ from freqtrade.exceptions import OperationalException, StrategyError
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
from freqtrade.exchange.exchange import timeframe_to_next_date
from freqtrade.persistence import PairLocks, Trade
from freqtrade.persistence.models import LocalTrade, Order
from freqtrade.strategy.hyper import HyperStrategyMixin
from freqtrade.strategy.informative_decorator import (InformativeData, PopulateIndicators,
_create_and_merge_informative_pair,
@ -862,23 +863,22 @@ class IStrategy(ABC, HyperStrategyMixin):
else:
return current_profit > roi
def ft_check_timed_out(self, side: str, trade: Trade, order: Dict,
def ft_check_timed_out(self, side: str, trade: LocalTrade, order: Order,
current_time: datetime) -> bool:
"""
FT Internal method.
Check if timeout is active, and if the order is still open and timed out
"""
timeout = self.config.get('unfilledtimeout', {}).get(side)
ordertime = arrow.get(order['datetime']).datetime
if timeout is not None:
timeout_unit = self.config.get('unfilledtimeout', {}).get('unit', 'minutes')
timeout_kwargs = {timeout_unit: -timeout}
timeout_threshold = current_time + timedelta(**timeout_kwargs)
timedout = (order['status'] == 'open' and order['side'] == side
and ordertime < timeout_threshold)
timedout = (order.status == 'open' and order.side == side
and order.order_date_utc < timeout_threshold)
if timedout:
return True
time_method = self.check_sell_timeout if order['side'] == 'sell' else self.check_buy_timeout
time_method = self.check_sell_timeout if order.side == 'sell' else self.check_buy_timeout
return strategy_safe_wrapper(time_method,
default_retval=False)(