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) 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 ( if (order['side'] == 'buy' and (order['status'] == 'open' or fully_cancelled) and (
fully_cancelled fully_cancelled
or self.strategy.ft_check_timed_out( or (order_obj and self.strategy.ft_check_timed_out(
'buy', trade, order, datetime.now(timezone.utc)) 'buy', trade, order_obj, datetime.now(timezone.utc))
)): ))):
self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['TIMEOUT']) self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['TIMEOUT'])
elif (order['side'] == 'sell' and (order['status'] == 'open' or fully_cancelled) and ( elif (order['side'] == 'sell' and (order['status'] == 'open' or fully_cancelled) and (
fully_cancelled fully_cancelled
or self.strategy.ft_check_timed_out( or (order_obj and self.strategy.ft_check_timed_out(
'sell', trade, order, datetime.now(timezone.utc))) 'sell', trade, order_obj, datetime.now(timezone.utc))
): ))):
self.handle_cancel_exit(trade, order, constants.CANCEL_REASON['TIMEOUT']) self.handle_cancel_exit(trade, order, constants.CANCEL_REASON['TIMEOUT'])
canceled_count = trade.get_exit_order_count() canceled_count = trade.get_exit_order_count()
max_timeouts = self.config.get('unfilledtimeout', {}).get('exit_timeout_count', 0) 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): if pos_adjust and self._get_order_filled(order.price, row):
order.close_bt_order(current_time) order.close_bt_order(current_time)
else: else:
trade.open_order_id = self.order_id_counter trade.open_order_id = str(self.order_id_counter)
trade.orders.append(order) trade.orders.append(order)
trade.recalc_trade_from_orders() 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]: 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 timedout:
if order.side == 'buy': if order.side == 'buy':
if trade.nr_of_successful_buys == 0: 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_filled_date = Column(DateTime, nullable=True)
order_update_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): def __repr__(self):
return (f'Order(id={self.id}, order_id={self.order_id}, trade_id={self.ft_trade_id}, ' 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: 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) 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( def select_order(
self, order_side: str = None, is_open: Optional[bool] = None) -> Optional[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 import timeframe_to_minutes, timeframe_to_seconds
from freqtrade.exchange.exchange import timeframe_to_next_date from freqtrade.exchange.exchange import timeframe_to_next_date
from freqtrade.persistence import PairLocks, Trade from freqtrade.persistence import PairLocks, Trade
from freqtrade.persistence.models import LocalTrade, Order
from freqtrade.strategy.hyper import HyperStrategyMixin from freqtrade.strategy.hyper import HyperStrategyMixin
from freqtrade.strategy.informative_decorator import (InformativeData, PopulateIndicators, from freqtrade.strategy.informative_decorator import (InformativeData, PopulateIndicators,
_create_and_merge_informative_pair, _create_and_merge_informative_pair,
@ -862,23 +863,22 @@ class IStrategy(ABC, HyperStrategyMixin):
else: else:
return current_profit > roi 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: current_time: datetime) -> bool:
""" """
FT Internal method. FT Internal method.
Check if timeout is active, and if the order is still open and timed out Check if timeout is active, and if the order is still open and timed out
""" """
timeout = self.config.get('unfilledtimeout', {}).get(side) timeout = self.config.get('unfilledtimeout', {}).get(side)
ordertime = arrow.get(order['datetime']).datetime
if timeout is not None: if timeout is not None:
timeout_unit = self.config.get('unfilledtimeout', {}).get('unit', 'minutes') timeout_unit = self.config.get('unfilledtimeout', {}).get('unit', 'minutes')
timeout_kwargs = {timeout_unit: -timeout} timeout_kwargs = {timeout_unit: -timeout}
timeout_threshold = current_time + timedelta(**timeout_kwargs) timeout_threshold = current_time + timedelta(**timeout_kwargs)
timedout = (order['status'] == 'open' and order['side'] == side timedout = (order.status == 'open' and order.side == side
and ordertime < timeout_threshold) and order.order_date_utc < timeout_threshold)
if timedout: if timedout:
return True 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, return strategy_safe_wrapper(time_method,
default_retval=False)( default_retval=False)(