use jsonschema instead of custom type validations
This commit is contained in:
		| @@ -12,3 +12,4 @@ PYQT5==5.9 | ||||
| scikit-learn==0.19.0 | ||||
| scipy==0.19.1 | ||||
| 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)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user