From 10ef0874b58b5eded398ca3503fb295528b65ce1 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste LE STANG Date: Tue, 30 Jan 2018 09:59:47 +0100 Subject: [PATCH] Refactoring _process/throttle to let throttle handle cases when we need an extra sleep time due to poor exchange conditions --- freqtrade/main.py | 11 +++++++---- freqtrade/misc.py | 4 ++-- freqtrade/tests/test_main.py | 10 +++++----- freqtrade/tests/test_misc.py | 4 ++-- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/freqtrade/main.py b/freqtrade/main.py index 6f7a67df2..696d8e066 100755 --- a/freqtrade/main.py +++ b/freqtrade/main.py @@ -92,14 +92,17 @@ def process_maybe_execute_sell(trade, interval): return False -def _process(interval: int, nb_assets: Optional[int] = 0) -> bool: +def _process(interval: int, nb_assets: Optional[int] = 0) -> (bool, int): """ Queries the persistence layer for open trades and handles them, otherwise a new trade is created. :param: nb_assets: the maximum number of pairs to be traded at the same time - :return: True if one or more trades has been created or closed, False otherwise + :return: a pair, the first value is True if one or more trades has been created + or closed, False otherwise, the second argument is a requested sleep time in + seconds to be used when exchange is having problems """ state_changed = False + extra_time = 0 try: # Refresh whitelist based on wallet maintenance sanitized_list = refresh_whitelist( @@ -130,7 +133,7 @@ def _process(interval: int, nb_assets: Optional[int] = 0) -> bool: 'Got %s in _process(), retrying in 30 seconds...', error ) - time.sleep(30) + extra_time = 30 except OperationalException: rpc.send_msg('*Status:* Got OperationalException:\n```\n{traceback}```{hint}'.format( traceback=traceback.format_exc(), @@ -138,7 +141,7 @@ def _process(interval: int, nb_assets: Optional[int] = 0) -> bool: )) logger.exception('Got OperationalException. Stopping trader ...') update_state(State.STOPPED) - return state_changed + return state_changed, extra_time # FIX: 20180110, why is cancel.order unconditionally here, whereas diff --git a/freqtrade/misc.py b/freqtrade/misc.py index cf2db1004..befe63b12 100644 --- a/freqtrade/misc.py +++ b/freqtrade/misc.py @@ -115,9 +115,9 @@ def throttle(func: Callable[..., Any], min_secs: float, *args, **kwargs) -> Any: :return: Any """ start = time.time() - result = func(*args, **kwargs) + (result, extra_time) = func(*args, **kwargs) end = time.time() - duration = max(min_secs - (end - start), 0.0) + duration = max(max(min_secs - (end - start), 0.0), extra_time) logger.debug('Throttling %s for %.2f seconds', func.__name__, duration) time.sleep(duration) return result diff --git a/freqtrade/tests/test_main.py b/freqtrade/tests/test_main.py index ba7f8108f..a41e78ea6 100644 --- a/freqtrade/tests/test_main.py +++ b/freqtrade/tests/test_main.py @@ -91,7 +91,7 @@ def test_process_trade_creation(default_conf, ticker, limit_buy_order, health, m assert not trades result = _process(interval=int(default_conf['ticker_interval'])) - assert result is True + assert result == (True, 0) trades = Trade.query.filter(Trade.is_open.is_(True)).all() assert len(trades) == 1 @@ -117,7 +117,7 @@ def test_process_exchange_failures(default_conf, ticker, health, mocker): buy=MagicMock(side_effect=requests.exceptions.RequestException)) init(default_conf, create_engine('sqlite://')) result = _process(interval=int(default_conf['ticker_interval'])) - assert result is False + assert result == (False, 30) assert sleep_mock.has_calls() @@ -135,7 +135,7 @@ def test_process_operational_exception(default_conf, ticker, health, mocker): assert get_state() == State.RUNNING result = _process(interval=int(default_conf['ticker_interval'])) - assert result is False + assert result == (False, 0) assert get_state() == State.STOPPED assert 'OperationalException' in msg_mock.call_args_list[-1][0][0] @@ -155,12 +155,12 @@ def test_process_trade_handling(default_conf, ticker, limit_buy_order, health, m trades = Trade.query.filter(Trade.is_open.is_(True)).all() assert not trades result = _process(interval=int(default_conf['ticker_interval'])) - assert result is True + assert result == (True, 0) trades = Trade.query.filter(Trade.is_open.is_(True)).all() assert len(trades) == 1 result = _process(interval=int(default_conf['ticker_interval'])) - assert result is False + assert result == (False, 0) def test_create_trade(default_conf, ticker, limit_buy_order, mocker): diff --git a/freqtrade/tests/test_misc.py b/freqtrade/tests/test_misc.py index c0d4db7a1..ef0ed2b7c 100644 --- a/freqtrade/tests/test_misc.py +++ b/freqtrade/tests/test_misc.py @@ -16,7 +16,7 @@ from freqtrade.misc import (common_args_parser, file_dump_json, load_config, def test_throttle(): def func(): - return 42 + return (42, 1) start = time.time() result = throttle(func, min_secs=0.1) @@ -32,7 +32,7 @@ def test_throttle(): def test_throttle_with_assets(): def func(nb_assets=-1): - return nb_assets + return (nb_assets, 0) result = throttle(func, min_secs=0.1, nb_assets=666) assert result == 666