define constants on module level (#596)
This commit is contained in:
parent
9cb5591007
commit
9019f6492f
@ -8,8 +8,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
from typing import List, Tuple, Optional
|
from typing import List, Tuple, Optional
|
||||||
|
|
||||||
from freqtrade import __version__
|
from freqtrade import __version__, constants
|
||||||
from freqtrade.constants import Constants
|
|
||||||
|
|
||||||
|
|
||||||
class Arguments(object):
|
class Arguments(object):
|
||||||
@ -98,7 +97,7 @@ class Arguments(object):
|
|||||||
help='dynamically generate and update whitelist \
|
help='dynamically generate and update whitelist \
|
||||||
based on 24h BaseVolume (Default 20 currencies)', # noqa
|
based on 24h BaseVolume (Default 20 currencies)', # noqa
|
||||||
dest='dynamic_whitelist',
|
dest='dynamic_whitelist',
|
||||||
const=Constants.DYNAMIC_WHITELIST,
|
const=constants.DYNAMIC_WHITELIST,
|
||||||
type=int,
|
type=int,
|
||||||
metavar='INT',
|
metavar='INT',
|
||||||
nargs='?',
|
nargs='?',
|
||||||
@ -170,7 +169,7 @@ class Arguments(object):
|
|||||||
'-e', '--epochs',
|
'-e', '--epochs',
|
||||||
help='specify number of epochs (default: %(default)d)',
|
help='specify number of epochs (default: %(default)d)',
|
||||||
dest='epochs',
|
dest='epochs',
|
||||||
default=Constants.HYPEROPT_EPOCH,
|
default=constants.HYPEROPT_EPOCH,
|
||||||
type=int,
|
type=int,
|
||||||
metavar='INT',
|
metavar='INT',
|
||||||
)
|
)
|
||||||
|
@ -10,7 +10,7 @@ from typing import Dict, Any
|
|||||||
from jsonschema import Draft4Validator, validate
|
from jsonschema import Draft4Validator, validate
|
||||||
from jsonschema.exceptions import ValidationError, best_match
|
from jsonschema.exceptions import ValidationError, best_match
|
||||||
|
|
||||||
from freqtrade.constants import Constants
|
from freqtrade import constants
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -34,7 +34,7 @@ class Configuration(object):
|
|||||||
config = self._load_config_file(self.args.config)
|
config = self._load_config_file(self.args.config)
|
||||||
|
|
||||||
# Set strategy if not specified in config and or if it's non default
|
# Set strategy if not specified in config and or if it's non default
|
||||||
if self.args.strategy != Constants.DEFAULT_STRATEGY or not config.get('strategy'):
|
if self.args.strategy != constants.DEFAULT_STRATEGY or not config.get('strategy'):
|
||||||
config.update({'strategy': self.args.strategy})
|
config.update({'strategy': self.args.strategy})
|
||||||
|
|
||||||
if self.args.strategy_path:
|
if self.args.strategy_path:
|
||||||
@ -186,7 +186,7 @@ class Configuration(object):
|
|||||||
:return: Returns the config if valid, otherwise throw an exception
|
:return: Returns the config if valid, otherwise throw an exception
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
validate(conf, Constants.CONF_SCHEMA)
|
validate(conf, constants.CONF_SCHEMA)
|
||||||
return conf
|
return conf
|
||||||
except ValidationError as exception:
|
except ValidationError as exception:
|
||||||
logger.fatal(
|
logger.fatal(
|
||||||
@ -194,7 +194,7 @@ class Configuration(object):
|
|||||||
exception
|
exception
|
||||||
)
|
)
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
best_match(Draft4Validator(Constants.CONF_SCHEMA).iter_errors(conf)).message
|
best_match(Draft4Validator(constants.CONF_SCHEMA).iter_errors(conf)).message
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_config(self) -> Dict[str, Any]:
|
def get_config(self) -> Dict[str, Any]:
|
||||||
|
@ -1,122 +1,116 @@
|
|||||||
# pragma pylint: disable=too-few-public-methods
|
# pragma pylint: disable=too-few-public-methods
|
||||||
|
|
||||||
"""
|
"""
|
||||||
List bot constants
|
bot constants
|
||||||
"""
|
"""
|
||||||
|
DYNAMIC_WHITELIST = 20 # pairs
|
||||||
|
PROCESS_THROTTLE_SECS = 5 # sec
|
||||||
|
TICKER_INTERVAL = 5 # min
|
||||||
|
HYPEROPT_EPOCH = 100 # epochs
|
||||||
|
RETRY_TIMEOUT = 30 # sec
|
||||||
|
DEFAULT_STRATEGY = 'DefaultStrategy'
|
||||||
|
|
||||||
|
# Required json-schema for user specified config
|
||||||
class Constants(object):
|
CONF_SCHEMA = {
|
||||||
"""
|
'type': 'object',
|
||||||
Static class that contain all bot constants
|
'properties': {
|
||||||
"""
|
'max_open_trades': {'type': 'integer', 'minimum': 1},
|
||||||
DYNAMIC_WHITELIST = 20 # pairs
|
'ticker_interval': {'type': 'integer', 'enum': [1, 5, 30, 60, 1440]},
|
||||||
PROCESS_THROTTLE_SECS = 5 # sec
|
'stake_currency': {'type': 'string', 'enum': ['BTC', 'ETH', 'USDT']},
|
||||||
TICKER_INTERVAL = 5 # min
|
'stake_amount': {'type': 'number', 'minimum': 0.0005},
|
||||||
HYPEROPT_EPOCH = 100 # epochs
|
'fiat_display_currency': {'type': 'string', 'enum': ['AUD', 'BRL', 'CAD', 'CHF',
|
||||||
RETRY_TIMEOUT = 30 # sec
|
'CLP', 'CNY', 'CZK', 'DKK',
|
||||||
DEFAULT_STRATEGY = 'DefaultStrategy'
|
'EUR', 'GBP', 'HKD', 'HUF',
|
||||||
|
'IDR', 'ILS', 'INR', 'JPY',
|
||||||
# Required json-schema for user specified config
|
'KRW', 'MXN', 'MYR', 'NOK',
|
||||||
CONF_SCHEMA = {
|
'NZD', 'PHP', 'PKR', 'PLN',
|
||||||
'type': 'object',
|
'RUB', 'SEK', 'SGD', 'THB',
|
||||||
'properties': {
|
'TRY', 'TWD', 'ZAR', 'USD']},
|
||||||
'max_open_trades': {'type': 'integer', 'minimum': 1},
|
'dry_run': {'type': 'boolean'},
|
||||||
'ticker_interval': {'type': 'integer', 'enum': [1, 5, 30, 60, 1440]},
|
'minimal_roi': {
|
||||||
'stake_currency': {'type': 'string', 'enum': ['BTC', 'ETH', 'USDT']},
|
'type': 'object',
|
||||||
'stake_amount': {'type': 'number', 'minimum': 0.0005},
|
'patternProperties': {
|
||||||
'fiat_display_currency': {'type': 'string', 'enum': ['AUD', 'BRL', 'CAD', 'CHF',
|
'^[0-9.]+$': {'type': 'number'}
|
||||||
'CLP', 'CNY', 'CZK', 'DKK',
|
},
|
||||||
'EUR', 'GBP', 'HKD', 'HUF',
|
'minProperties': 1
|
||||||
'IDR', 'ILS', 'INR', 'JPY',
|
},
|
||||||
'KRW', 'MXN', 'MYR', 'NOK',
|
'stoploss': {'type': 'number', 'maximum': 0, 'exclusiveMaximum': True},
|
||||||
'NZD', 'PHP', 'PKR', 'PLN',
|
'unfilledtimeout': {'type': 'integer', 'minimum': 0},
|
||||||
'RUB', 'SEK', 'SGD', 'THB',
|
'bid_strategy': {
|
||||||
'TRY', 'TWD', 'ZAR', 'USD']},
|
'type': 'object',
|
||||||
'dry_run': {'type': 'boolean'},
|
'properties': {
|
||||||
'minimal_roi': {
|
'ask_last_balance': {
|
||||||
'type': 'object',
|
'type': 'number',
|
||||||
'patternProperties': {
|
'minimum': 0,
|
||||||
'^[0-9.]+$': {'type': 'number'}
|
'maximum': 1,
|
||||||
|
'exclusiveMaximum': False
|
||||||
},
|
},
|
||||||
'minProperties': 1
|
|
||||||
},
|
},
|
||||||
'stoploss': {'type': 'number', 'maximum': 0, 'exclusiveMaximum': True},
|
'required': ['ask_last_balance']
|
||||||
'unfilledtimeout': {'type': 'integer', 'minimum': 0},
|
},
|
||||||
'bid_strategy': {
|
'exchange': {'$ref': '#/definitions/exchange'},
|
||||||
'type': 'object',
|
'experimental': {
|
||||||
'properties': {
|
'type': 'object',
|
||||||
'ask_last_balance': {
|
'properties': {
|
||||||
'type': 'number',
|
'use_sell_signal': {'type': 'boolean'},
|
||||||
'minimum': 0,
|
'sell_profit_only': {'type': 'boolean'}
|
||||||
'maximum': 1,
|
|
||||||
'exclusiveMaximum': False
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'required': ['ask_last_balance']
|
|
||||||
},
|
|
||||||
'exchange': {'$ref': '#/definitions/exchange'},
|
|
||||||
'experimental': {
|
|
||||||
'type': 'object',
|
|
||||||
'properties': {
|
|
||||||
'use_sell_signal': {'type': 'boolean'},
|
|
||||||
'sell_profit_only': {'type': 'boolean'}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'telegram': {
|
|
||||||
'type': 'object',
|
|
||||||
'properties': {
|
|
||||||
'enabled': {'type': 'boolean'},
|
|
||||||
'token': {'type': 'string'},
|
|
||||||
'chat_id': {'type': 'string'},
|
|
||||||
},
|
|
||||||
'required': ['enabled', 'token', 'chat_id']
|
|
||||||
},
|
|
||||||
'initial_state': {'type': 'string', 'enum': ['running', 'stopped']},
|
|
||||||
'internals': {
|
|
||||||
'type': 'object',
|
|
||||||
'properties': {
|
|
||||||
'process_throttle_secs': {'type': 'number'},
|
|
||||||
'interval': {'type': 'integer'}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'definitions': {
|
'telegram': {
|
||||||
'exchange': {
|
'type': 'object',
|
||||||
'type': 'object',
|
'properties': {
|
||||||
'properties': {
|
'enabled': {'type': 'boolean'},
|
||||||
'name': {'type': 'string'},
|
'token': {'type': 'string'},
|
||||||
'key': {'type': 'string'},
|
'chat_id': {'type': 'string'},
|
||||||
'secret': {'type': 'string'},
|
},
|
||||||
'pair_whitelist': {
|
'required': ['enabled', 'token', 'chat_id']
|
||||||
'type': 'array',
|
|
||||||
'items': {
|
|
||||||
'type': 'string',
|
|
||||||
'pattern': '^[0-9A-Z]+_[0-9A-Z]+$'
|
|
||||||
},
|
|
||||||
'uniqueItems': True
|
|
||||||
},
|
|
||||||
'pair_blacklist': {
|
|
||||||
'type': 'array',
|
|
||||||
'items': {
|
|
||||||
'type': 'string',
|
|
||||||
'pattern': '^[0-9A-Z]+_[0-9A-Z]+$'
|
|
||||||
},
|
|
||||||
'uniqueItems': True
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'required': ['name', 'key', 'secret', 'pair_whitelist']
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
'anyOf': [
|
'initial_state': {'type': 'string', 'enum': ['running', 'stopped']},
|
||||||
{'required': ['exchange']}
|
'internals': {
|
||||||
],
|
'type': 'object',
|
||||||
'required': [
|
'properties': {
|
||||||
'max_open_trades',
|
'process_throttle_secs': {'type': 'number'},
|
||||||
'stake_currency',
|
'interval': {'type': 'integer'}
|
||||||
'stake_amount',
|
}
|
||||||
'fiat_display_currency',
|
}
|
||||||
'dry_run',
|
},
|
||||||
'bid_strategy',
|
'definitions': {
|
||||||
'telegram'
|
'exchange': {
|
||||||
]
|
'type': 'object',
|
||||||
}
|
'properties': {
|
||||||
|
'name': {'type': 'string'},
|
||||||
|
'key': {'type': 'string'},
|
||||||
|
'secret': {'type': 'string'},
|
||||||
|
'pair_whitelist': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': {
|
||||||
|
'type': 'string',
|
||||||
|
'pattern': '^[0-9A-Z]+_[0-9A-Z]+$'
|
||||||
|
},
|
||||||
|
'uniqueItems': True
|
||||||
|
},
|
||||||
|
'pair_blacklist': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': {
|
||||||
|
'type': 'string',
|
||||||
|
'pattern': '^[0-9A-Z]+_[0-9A-Z]+$'
|
||||||
|
},
|
||||||
|
'uniqueItems': True
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'required': ['name', 'key', 'secret', 'pair_whitelist']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'anyOf': [
|
||||||
|
{'required': ['exchange']}
|
||||||
|
],
|
||||||
|
'required': [
|
||||||
|
'max_open_trades',
|
||||||
|
'stake_currency',
|
||||||
|
'stake_amount',
|
||||||
|
'fiat_display_currency',
|
||||||
|
'dry_run',
|
||||||
|
'bid_strategy',
|
||||||
|
'telegram'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
@ -18,7 +18,7 @@ from freqtrade import (
|
|||||||
DependencyException, OperationalException, exchange, persistence, __version__
|
DependencyException, OperationalException, exchange, persistence, __version__
|
||||||
)
|
)
|
||||||
from freqtrade.analyze import Analyze
|
from freqtrade.analyze import Analyze
|
||||||
from freqtrade.constants import Constants
|
from freqtrade import constants
|
||||||
from freqtrade.fiat_convert import CryptoToFiatConverter
|
from freqtrade.fiat_convert import CryptoToFiatConverter
|
||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
from freqtrade.rpc.rpc_manager import RPCManager
|
from freqtrade.rpc.rpc_manager import RPCManager
|
||||||
@ -111,7 +111,7 @@ class FreqtradeBot(object):
|
|||||||
elif state == State.RUNNING:
|
elif state == State.RUNNING:
|
||||||
min_secs = self.config.get('internals', {}).get(
|
min_secs = self.config.get('internals', {}).get(
|
||||||
'process_throttle_secs',
|
'process_throttle_secs',
|
||||||
Constants.PROCESS_THROTTLE_SECS
|
constants.PROCESS_THROTTLE_SECS
|
||||||
)
|
)
|
||||||
|
|
||||||
nb_assets = self.config.get('dynamic_whitelist', None)
|
nb_assets = self.config.get('dynamic_whitelist', None)
|
||||||
@ -175,7 +175,7 @@ class FreqtradeBot(object):
|
|||||||
|
|
||||||
except (requests.exceptions.RequestException, json.JSONDecodeError) as error:
|
except (requests.exceptions.RequestException, json.JSONDecodeError) as error:
|
||||||
logger.warning('%s, retrying in 30 seconds...', error)
|
logger.warning('%s, retrying in 30 seconds...', error)
|
||||||
time.sleep(Constants.RETRY_TIMEOUT)
|
time.sleep(constants.RETRY_TIMEOUT)
|
||||||
except OperationalException:
|
except OperationalException:
|
||||||
self.rpc.send_msg(
|
self.rpc.send_msg(
|
||||||
'*Status:* OperationalException:\n```\n{traceback}```{hint}'
|
'*Status:* OperationalException:\n```\n{traceback}```{hint}'
|
||||||
|
@ -10,7 +10,7 @@ import os
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from typing import Optional, Dict, Type
|
from typing import Optional, Dict, Type
|
||||||
|
|
||||||
from freqtrade.constants import Constants
|
from freqtrade import constants
|
||||||
from freqtrade.strategy.interface import IStrategy
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ class StrategyResolver(object):
|
|||||||
config = config or {}
|
config = config or {}
|
||||||
|
|
||||||
# Verify the strategy is in the configuration, otherwise fallback to the default strategy
|
# Verify the strategy is in the configuration, otherwise fallback to the default strategy
|
||||||
strategy_name = config.get('strategy') or Constants.DEFAULT_STRATEGY
|
strategy_name = config.get('strategy') or constants.DEFAULT_STRATEGY
|
||||||
self.strategy = self._load_strategy(strategy_name, extra_dir=config.get('strategy_path'))
|
self.strategy = self._load_strategy(strategy_name, extra_dir=config.get('strategy_path'))
|
||||||
|
|
||||||
# Set attributes
|
# Set attributes
|
||||||
|
@ -12,7 +12,7 @@ from sqlalchemy import create_engine
|
|||||||
from telegram import Chat, Message, Update
|
from telegram import Chat, Message, Update
|
||||||
|
|
||||||
from freqtrade.analyze import Analyze
|
from freqtrade.analyze import Analyze
|
||||||
from freqtrade.constants import Constants
|
from freqtrade import constants
|
||||||
from freqtrade.freqtradebot import FreqtradeBot
|
from freqtrade.freqtradebot import FreqtradeBot
|
||||||
|
|
||||||
logging.getLogger('').setLevel(logging.INFO)
|
logging.getLogger('').setLevel(logging.INFO)
|
||||||
@ -88,7 +88,7 @@ def default_conf():
|
|||||||
"initial_state": "running",
|
"initial_state": "running",
|
||||||
"loglevel": logging.DEBUG
|
"loglevel": logging.DEBUG
|
||||||
}
|
}
|
||||||
validate(configuration, Constants.CONF_SCHEMA)
|
validate(configuration, constants.CONF_SCHEMA)
|
||||||
return configuration
|
return configuration
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,25 +2,24 @@
|
|||||||
Unit test file for constants.py
|
Unit test file for constants.py
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from freqtrade.constants import Constants
|
from freqtrade import constants
|
||||||
|
|
||||||
|
|
||||||
def test_constant_object() -> None:
|
def test_constant_object() -> None:
|
||||||
"""
|
"""
|
||||||
Test the Constants object has the mandatory Constants
|
Test the Constants object has the mandatory Constants
|
||||||
"""
|
"""
|
||||||
assert hasattr(Constants, 'CONF_SCHEMA')
|
assert hasattr(constants, 'CONF_SCHEMA')
|
||||||
assert hasattr(Constants, 'DYNAMIC_WHITELIST')
|
assert hasattr(constants, 'DYNAMIC_WHITELIST')
|
||||||
assert hasattr(Constants, 'PROCESS_THROTTLE_SECS')
|
assert hasattr(constants, 'PROCESS_THROTTLE_SECS')
|
||||||
assert hasattr(Constants, 'TICKER_INTERVAL')
|
assert hasattr(constants, 'TICKER_INTERVAL')
|
||||||
assert hasattr(Constants, 'HYPEROPT_EPOCH')
|
assert hasattr(constants, 'HYPEROPT_EPOCH')
|
||||||
assert hasattr(Constants, 'RETRY_TIMEOUT')
|
assert hasattr(constants, 'RETRY_TIMEOUT')
|
||||||
assert hasattr(Constants, 'DEFAULT_STRATEGY')
|
assert hasattr(constants, 'DEFAULT_STRATEGY')
|
||||||
|
|
||||||
|
|
||||||
def test_conf_schema() -> None:
|
def test_conf_schema() -> None:
|
||||||
"""
|
"""
|
||||||
Test the CONF_SCHEMA is from the right type
|
Test the CONF_SCHEMA is from the right type
|
||||||
"""
|
"""
|
||||||
constant = Constants()
|
assert isinstance(constants.CONF_SCHEMA, dict)
|
||||||
assert isinstance(constant.CONF_SCHEMA, dict)
|
|
||||||
|
Loading…
Reference in New Issue
Block a user