define constants on module level (#596)

This commit is contained in:
Michael Egger 2018-04-02 16:42:53 +02:00 committed by GitHub
parent 9cb5591007
commit 9019f6492f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 129 additions and 137 deletions

View File

@ -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',
) )

View File

@ -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]:

View File

@ -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'
]
}

View File

@ -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}'

View File

@ -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

View File

@ -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

View File

@ -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)