Add configurable throttle mechanism
This commit is contained in:
parent
8f817a3634
commit
d3b3370f23
@ -34,5 +34,8 @@
|
||||
"token": "token",
|
||||
"chat_id": "chat_id"
|
||||
},
|
||||
"initial_state": "running"
|
||||
"initial_state": "running",
|
||||
"internals": {
|
||||
"process_throttle_secs": 5
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ from jsonschema import validate
|
||||
|
||||
from freqtrade import __version__, exchange, persistence
|
||||
from freqtrade.analyze import get_buy_signal
|
||||
from freqtrade.misc import CONF_SCHEMA, State, get_state, update_state, build_arg_parser
|
||||
from freqtrade.misc import CONF_SCHEMA, State, get_state, update_state, build_arg_parser, throttle
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.rpc import telegram
|
||||
|
||||
@ -280,14 +280,14 @@ def main():
|
||||
# Load and validate configuration
|
||||
with open(args.config) as file:
|
||||
_CONF = json.load(file)
|
||||
if 'internals' not in _CONF:
|
||||
_CONF['internals'] = {}
|
||||
logger.info('Validating configuration ...')
|
||||
validate(_CONF, CONF_SCHEMA)
|
||||
|
||||
# Initialize all modules and start main loop
|
||||
init(_CONF)
|
||||
old_state = get_state()
|
||||
logger.info('Initial State: %s', old_state)
|
||||
telegram.send_msg('*Status:* `{}`'.format(old_state.name.lower()))
|
||||
old_state = None
|
||||
while True:
|
||||
new_state = get_state()
|
||||
# Log state transition
|
||||
@ -298,8 +298,7 @@ def main():
|
||||
if new_state == State.STOPPED:
|
||||
time.sleep(1)
|
||||
elif new_state == State.RUNNING:
|
||||
_process()
|
||||
time.sleep(5)
|
||||
throttle(_process, min_secs=_CONF['internals'].get('process_throttle_secs', 5))
|
||||
old_state = new_state
|
||||
|
||||
|
||||
|
@ -1,11 +1,15 @@
|
||||
import argparse
|
||||
import enum
|
||||
import logging
|
||||
from typing import Any, Callable
|
||||
|
||||
import time
|
||||
from wrapt import synchronized
|
||||
|
||||
from freqtrade import __version__
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class State(enum.Enum):
|
||||
RUNNING = 0
|
||||
@ -36,6 +40,23 @@ def get_state() -> State:
|
||||
return _STATE
|
||||
|
||||
|
||||
def throttle(func: Callable[..., Any], min_secs: float, *args, **kwargs) -> Any:
|
||||
"""
|
||||
Throttles the given callable that it
|
||||
takes at least `min_secs` to finish execution.
|
||||
:param func: Any callable
|
||||
:param min_secs: minimum execution time in seconds
|
||||
:return: Any
|
||||
"""
|
||||
start = time.time()
|
||||
result = func(*args, **kwargs)
|
||||
end = time.time()
|
||||
duration = max(min_secs - (end - start), 0.0)
|
||||
logger.debug('Throttling %s for %.2f seconds', func.__name__, duration)
|
||||
time.sleep(duration)
|
||||
return result
|
||||
|
||||
|
||||
def build_arg_parser() -> argparse.ArgumentParser:
|
||||
""" Builds and returns an ArgumentParser instance """
|
||||
parser = argparse.ArgumentParser(
|
||||
@ -104,6 +125,12 @@ CONF_SCHEMA = {
|
||||
'required': ['enabled', 'token', 'chat_id']
|
||||
},
|
||||
'initial_state': {'type': 'string', 'enum': ['running', 'stopped']},
|
||||
'internals': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'process_throttle_secs': {'type': 'number'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'definitions': {
|
||||
'exchange': {
|
||||
|
20
freqtrade/tests/test_misc.py
Normal file
20
freqtrade/tests/test_misc.py
Normal file
@ -0,0 +1,20 @@
|
||||
# pragma pylint: disable=missing-docstring
|
||||
import time
|
||||
|
||||
from freqtrade.misc import throttle
|
||||
|
||||
|
||||
def test_throttle():
|
||||
|
||||
def func():
|
||||
return 42
|
||||
|
||||
start = time.time()
|
||||
result = throttle(func, 0.1)
|
||||
end = time.time()
|
||||
|
||||
assert result == 42
|
||||
assert end - start > 0.1
|
||||
|
||||
result = throttle(func, -1)
|
||||
assert result == 42
|
Loading…
Reference in New Issue
Block a user