Add configurable throttle mechanism
This commit is contained in:
parent
8f817a3634
commit
d3b3370f23
@ -34,5 +34,8 @@
|
|||||||
"token": "token",
|
"token": "token",
|
||||||
"chat_id": "chat_id"
|
"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 import __version__, exchange, persistence
|
||||||
from freqtrade.analyze import get_buy_signal
|
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.persistence import Trade
|
||||||
from freqtrade.rpc import telegram
|
from freqtrade.rpc import telegram
|
||||||
|
|
||||||
@ -280,14 +280,14 @@ def main():
|
|||||||
# Load and validate configuration
|
# Load and validate configuration
|
||||||
with open(args.config) as file:
|
with open(args.config) as file:
|
||||||
_CONF = json.load(file)
|
_CONF = json.load(file)
|
||||||
|
if 'internals' not in _CONF:
|
||||||
|
_CONF['internals'] = {}
|
||||||
logger.info('Validating configuration ...')
|
logger.info('Validating configuration ...')
|
||||||
validate(_CONF, CONF_SCHEMA)
|
validate(_CONF, CONF_SCHEMA)
|
||||||
|
|
||||||
# Initialize all modules and start main loop
|
# Initialize all modules and start main loop
|
||||||
init(_CONF)
|
init(_CONF)
|
||||||
old_state = get_state()
|
old_state = None
|
||||||
logger.info('Initial State: %s', old_state)
|
|
||||||
telegram.send_msg('*Status:* `{}`'.format(old_state.name.lower()))
|
|
||||||
while True:
|
while True:
|
||||||
new_state = get_state()
|
new_state = get_state()
|
||||||
# Log state transition
|
# Log state transition
|
||||||
@ -298,8 +298,7 @@ def main():
|
|||||||
if new_state == State.STOPPED:
|
if new_state == State.STOPPED:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
elif new_state == State.RUNNING:
|
elif new_state == State.RUNNING:
|
||||||
_process()
|
throttle(_process, min_secs=_CONF['internals'].get('process_throttle_secs', 5))
|
||||||
time.sleep(5)
|
|
||||||
old_state = new_state
|
old_state = new_state
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import enum
|
import enum
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any, Callable
|
||||||
|
|
||||||
|
import time
|
||||||
from wrapt import synchronized
|
from wrapt import synchronized
|
||||||
|
|
||||||
from freqtrade import __version__
|
from freqtrade import __version__
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class State(enum.Enum):
|
class State(enum.Enum):
|
||||||
RUNNING = 0
|
RUNNING = 0
|
||||||
@ -36,6 +40,23 @@ def get_state() -> State:
|
|||||||
return _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:
|
def build_arg_parser() -> argparse.ArgumentParser:
|
||||||
""" Builds and returns an ArgumentParser instance """
|
""" Builds and returns an ArgumentParser instance """
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
@ -104,6 +125,12 @@ CONF_SCHEMA = {
|
|||||||
'required': ['enabled', 'token', 'chat_id']
|
'required': ['enabled', 'token', 'chat_id']
|
||||||
},
|
},
|
||||||
'initial_state': {'type': 'string', 'enum': ['running', 'stopped']},
|
'initial_state': {'type': 'string', 'enum': ['running', 'stopped']},
|
||||||
|
'internals': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'process_throttle_secs': {'type': 'number'}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'definitions': {
|
'definitions': {
|
||||||
'exchange': {
|
'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