use jsonschema instead of custom type validations
This commit is contained in:
parent
6f05648087
commit
e3eaad07b1
@ -11,4 +11,5 @@ matplotlib==2.0.2
|
||||
PYQT5==5.9
|
||||
scikit-learn==0.19.0
|
||||
scipy==0.19.1
|
||||
stockstats==0.2.0
|
||||
stockstats==0.2.0
|
||||
jsonschema==2.6.0
|
144
utils.py
144
utils.py
@ -1,102 +1,82 @@
|
||||
import json
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from jsonschema import validate
|
||||
from wrapt import synchronized
|
||||
from bittrex.bittrex import Bittrex
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_cur_conf = None
|
||||
|
||||
|
||||
# Required json-schema for user specified config
|
||||
_conf_schema = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'max_open_trades': {'type': 'integer'},
|
||||
'stake_currency': {'type': 'string'},
|
||||
'stake_amount': {'type': 'number'},
|
||||
'dry_run': {'type': 'boolean'},
|
||||
'minimal_roi': {
|
||||
'type': 'object',
|
||||
'patternProperties': {
|
||||
'^[0-9.]+$': {'type': 'number'}
|
||||
},
|
||||
'minProperties': 1
|
||||
},
|
||||
'poloniex': {'$ref': '#/definitions/exchange'},
|
||||
'bittrex': {'$ref': '#/definitions/exchange'},
|
||||
'telegram': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'enabled': {'type': 'boolean'},
|
||||
'token': {'type': 'string'},
|
||||
'chat_id': {'type': 'string'},
|
||||
},
|
||||
'required': ['enabled', 'token', 'chat_id']
|
||||
}
|
||||
},
|
||||
'definitions': {
|
||||
'exchange': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'enabled': {'type': 'boolean'},
|
||||
'key': {'type': 'string'},
|
||||
'secret': {'type': 'string'},
|
||||
'pair_whitelist': {
|
||||
'type': 'array',
|
||||
'items': {'type': 'string'},
|
||||
'uniqueItems': True
|
||||
}
|
||||
},
|
||||
'required': ['enabled', 'key', 'secret', 'pair_whitelist']
|
||||
}
|
||||
},
|
||||
'anyOf': [
|
||||
{'required': ['poloniex']},
|
||||
{'required': ['bittrex']}
|
||||
],
|
||||
'required': [
|
||||
'max_open_trades',
|
||||
'stake_currency',
|
||||
'stake_amount',
|
||||
'dry_run',
|
||||
'minimal_roi',
|
||||
'telegram'
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@synchronized
|
||||
def get_conf(filename: str='config.json') -> dict:
|
||||
"""
|
||||
Loads the config into memory and returns the instance of it
|
||||
Loads the config into memory validates it
|
||||
and returns the singleton instance
|
||||
:return: dict
|
||||
"""
|
||||
global _cur_conf
|
||||
if not _cur_conf:
|
||||
with open(filename) as file:
|
||||
_cur_conf = json.load(file)
|
||||
validate_conf(_cur_conf)
|
||||
validate(_cur_conf, _conf_schema)
|
||||
return _cur_conf
|
||||
|
||||
|
||||
def validate_conf(conf: dict) -> None:
|
||||
"""
|
||||
Validates if the minimal possible config is provided
|
||||
:param conf: config as dict
|
||||
:return: None, raises ValueError if something is wrong
|
||||
"""
|
||||
if not isinstance(conf.get('max_open_trades'), int):
|
||||
raise ValueError('max_open_trades must be a int')
|
||||
if not isinstance(conf.get('stake_currency'), str):
|
||||
raise ValueError('stake_currency must be a str')
|
||||
if not isinstance(conf.get('stake_amount'), float):
|
||||
raise ValueError('stake_amount must be a float')
|
||||
if not isinstance(conf.get('dry_run'), bool):
|
||||
raise ValueError('dry_run must be a boolean')
|
||||
if not isinstance(conf.get('minimal_roi'), dict):
|
||||
raise ValueError('minimal_roi must be a dict')
|
||||
|
||||
for index, (minutes, threshold) in enumerate(conf.get('minimal_roi').items()):
|
||||
if not isinstance(minutes, str):
|
||||
raise ValueError('minimal_roi[{}].key must be a string'.format(index))
|
||||
if not isinstance(threshold, float):
|
||||
raise ValueError('minimal_roi[{}].value must be a float'.format(index))
|
||||
|
||||
if conf.get('telegram'):
|
||||
telegram = conf.get('telegram')
|
||||
if not isinstance(telegram.get('token'), str):
|
||||
raise ValueError('telegram.token must be a string')
|
||||
if not isinstance(telegram.get('chat_id'), str):
|
||||
raise ValueError('telegram.chat_id must be a string')
|
||||
|
||||
if conf.get('poloniex'):
|
||||
poloniex = conf.get('poloniex')
|
||||
if not isinstance(poloniex.get('key'), str):
|
||||
raise ValueError('poloniex.key must be a string')
|
||||
if not isinstance(poloniex.get('secret'), str):
|
||||
raise ValueError('poloniex.secret must be a string')
|
||||
if not isinstance(poloniex.get('pair_whitelist'), list):
|
||||
raise ValueError('poloniex.pair_whitelist must be a list')
|
||||
if poloniex.get('enabled', False):
|
||||
raise ValueError('poloniex is currently not implemented')
|
||||
#if not poloniex.get('pair_whitelist'):
|
||||
# raise ValueError('poloniex.pair_whitelist must contain some pairs')
|
||||
|
||||
if conf.get('bittrex'):
|
||||
bittrex = conf.get('bittrex')
|
||||
if not isinstance(bittrex.get('key'), str):
|
||||
raise ValueError('bittrex.key must be a string')
|
||||
if not isinstance(bittrex.get('secret'), str):
|
||||
raise ValueError('bittrex.secret must be a string')
|
||||
if not isinstance(bittrex.get('pair_whitelist'), list):
|
||||
raise ValueError('bittrex.pair_whitelist must be a list')
|
||||
if bittrex.get('enabled', False):
|
||||
if not bittrex.get('pair_whitelist'):
|
||||
raise ValueError('bittrex.pair_whitelist must contain some pairs')
|
||||
validate_bittrex_pairs(bittrex.get('pair_whitelist'))
|
||||
|
||||
if conf.get('poloniex', {}).get('enabled', False) \
|
||||
and conf.get('bittrex', {}).get('enabled', False):
|
||||
raise ValueError('Cannot use poloniex and bittrex at the same time')
|
||||
|
||||
logger.info('Config is valid ...')
|
||||
|
||||
|
||||
def validate_bittrex_pairs(pairs: List[str]) -> None:
|
||||
"""
|
||||
Validates if all given pairs exist on bittrex
|
||||
:param pairs: list of str
|
||||
:return: None
|
||||
"""
|
||||
data = Bittrex(None, None).get_markets()
|
||||
if not data['success']:
|
||||
raise RuntimeError('BITTREX: {}'.format(data['message']))
|
||||
available_markets = [market['MarketName'].replace('-', '_')for market in data['result']]
|
||||
for pair in pairs:
|
||||
if pair not in available_markets:
|
||||
raise ValueError('Invalid pair: {}'.format(pair))
|
||||
|
Loading…
Reference in New Issue
Block a user