Extract timeout handling from freqtradebot class
This commit is contained in:
parent
a35b0b519a
commit
7bef9a9b3e
@ -9,8 +9,6 @@ from math import isclose
|
|||||||
from threading import Lock
|
from threading import Lock
|
||||||
from typing import Any, Dict, List, Optional, Tuple
|
from typing import Any, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
import arrow
|
|
||||||
|
|
||||||
from freqtrade import __version__, constants
|
from freqtrade import __version__, constants
|
||||||
from freqtrade.configuration import validate_config_consistency
|
from freqtrade.configuration import validate_config_consistency
|
||||||
from freqtrade.data.converter import order_book_to_dataframe
|
from freqtrade.data.converter import order_book_to_dataframe
|
||||||
@ -959,20 +957,6 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _check_timed_out(self, side: str, order: dict) -> bool:
|
|
||||||
"""
|
|
||||||
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 = arrow.utcnow().shift(**timeout_kwargs).datetime
|
|
||||||
return (order['status'] == 'open' and order['side'] == side
|
|
||||||
and ordertime < timeout_threshold)
|
|
||||||
return False
|
|
||||||
|
|
||||||
def check_handle_timedout(self) -> None:
|
def check_handle_timedout(self) -> None:
|
||||||
"""
|
"""
|
||||||
Check if any orders are timed out and cancel if necessary
|
Check if any orders are timed out and cancel if necessary
|
||||||
@ -993,20 +977,16 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
|
|
||||||
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._check_timed_out('buy', order)
|
or self.strategy.ft_check_timed_out(
|
||||||
or strategy_safe_wrapper(self.strategy.check_buy_timeout,
|
'buy', trade, order, datetime.now(timezone.utc))
|
||||||
default_retval=False)(pair=trade.pair,
|
)):
|
||||||
trade=trade,
|
|
||||||
order=order))):
|
|
||||||
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._check_timed_out('sell', order)
|
or self.strategy.ft_check_timed_out(
|
||||||
or strategy_safe_wrapper(self.strategy.check_sell_timeout,
|
'sell', trade, order, datetime.now(timezone.utc)))
|
||||||
default_retval=False)(pair=trade.pair,
|
):
|
||||||
trade=trade,
|
|
||||||
order=order))):
|
|
||||||
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)
|
||||||
|
@ -852,6 +852,28 @@ 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,
|
||||||
|
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)
|
||||||
|
if timedout:
|
||||||
|
return True
|
||||||
|
time_method = 'check_sell_timeout' if order['side'] == 'sell' else 'check_buy_timeout'
|
||||||
|
|
||||||
|
return strategy_safe_wrapper(getattr(self, time_method),
|
||||||
|
default_retval=False)(
|
||||||
|
pair=trade.pair, trade=trade, order=order)
|
||||||
|
|
||||||
def advise_all_indicators(self, data: Dict[str, DataFrame]) -> Dict[str, DataFrame]:
|
def advise_all_indicators(self, data: Dict[str, DataFrame]) -> Dict[str, DataFrame]:
|
||||||
"""
|
"""
|
||||||
Populates indicators for given candle (OHLCV) data (for multiple pairs)
|
Populates indicators for given candle (OHLCV) data (for multiple pairs)
|
||||||
|
Loading…
Reference in New Issue
Block a user