def test_enum_can_be_created_from_values(): assert Granularity.convert_to_enum(60) == Granularity.ONE_MINUTE assert Granularity.convert_to_enum("1m") == Granularity.ONE_MINUTE assert Granularity.convert_to_enum("1min") == Granularity.ONE_MINUTE assert Granularity.convert_to_enum("1T") == Granularity.ONE_MINUTE
import time import json import pandas as pd from models.PyCryptoBot import PyCryptoBot from models.exchange import kucoin from models.helper.TelegramBotHelper import TelegramBotHelper as TGBot from models.Trading import TechnicalAnalysis from models.exchange.binance import PublicAPI as BPublicAPI from models.exchange.coinbase_pro import PublicAPI as CPublicAPI from models.exchange.kucoin import PublicAPI as KPublicAPI from models.exchange.Granularity import Granularity from models.exchange.ExchangesEnum import Exchange GRANULARITY = Granularity(Granularity.ONE_HOUR) try: with open("scanner.json", encoding='utf8') as json_file: config = json.load(json_file) except IOError as err: print(err) for exchange in config: ex = Exchange(exchange) app = PyCryptoBot(exchange=ex) for quote in config[ex.value]["quote_currency"]: if ex == Exchange.BINANCE: api = BPublicAPI() elif ex == Exchange.COINBASEPRO: api = CPublicAPI() elif ex == Exchange.KUCOIN: api = KPublicAPI()
def test_exception_thrown_when_invalid_value(): with pytest.raises(ValueError) as exc_info: Granularity(10000000) assert exc_info.type is ValueError assert exc_info.value.args[0] == "10000000 is not a valid Granularity"
def load_configs(): exchanges_loaded = [] try: with open("screener.json", encoding='utf8') as json_file: config = json.load(json_file) except IOError as err: raise (err) try: with open("config.json", encoding='utf8') as json_file: bot_config = json.load(json_file) except IOError as err: print(err) try: for exchange in config: ex = CryptoExchange(exchange) exchange_config = config[ex.value] if ex == CryptoExchange.BINANCE: binance_app = PyCryptoBot(exchange=ex) binance_app.public_api = BPublicAPI( bot_config[ex.value]["api_url"]) binance_app.scanner_quote_currencies = exchange_config.get( 'quote_currency', ['USDT']) binance_app.granularity = Granularity( Granularity.convert_to_enum( exchange_config.get('granularity', '1h'))) binance_app.adx_threshold = exchange_config.get( 'adx_threshold', 25) binance_app.volatility_threshold = exchange_config.get( 'volatility_threshold', 9) binance_app.minimum_volatility = exchange_config.get( 'minimum_volatility', 5) binance_app.minimum_volume = exchange_config.get( 'minimum_volume', 20000) binance_app.volume_threshold = exchange_config.get( 'volume_threshold', 20000) binance_app.minimum_quote_price = exchange_config.get( 'minimum_quote_price', 0.0000001) binance_app.selection_score = exchange_config.get( 'selection_score', 10) binance_app.tv_screener_ratings = [ rating.upper() for rating in exchange_config.get( 'tv_screener_ratings', ['STRONG_BUY']) ] exchanges_loaded.append(binance_app) elif ex == CryptoExchange.COINBASEPRO: coinbase_app = PyCryptoBot(exchange=ex) coinbase_app.public_api = CPublicAPI() coinbase_app.scanner_quote_currencies = exchange_config.get( 'quote_currency', ['USDT']) coinbase_app.granularity = Granularity( Granularity.convert_to_enum( int(exchange_config.get('granularity', '3600')))) coinbase_app.adx_threshold = exchange_config.get( 'adx_threshold', 25) coinbase_app.volatility_threshold = exchange_config.get( 'volatility_threshold', 9) coinbase_app.minimum_volatility = exchange_config.get( 'minimum_volatility', 5) coinbase_app.minimum_volume = exchange_config.get( 'minimum_volume', 20000) coinbase_app.volume_threshold = exchange_config.get( 'volume_threshold', 20000) coinbase_app.minimum_quote_price = exchange_config.get( 'minimum_quote_price', 0.0000001) coinbase_app.selection_score = exchange_config.get( 'selection_score', 10) coinbase_app.tv_screener_ratings = [ rating.upper() for rating in exchange_config.get( 'tv_screener_ratings', ['STRONG_BUY']) ] exchanges_loaded.append(coinbase_app) elif ex == CryptoExchange.KUCOIN: kucoin_app = PyCryptoBot(exchange=ex) kucoin_app.public_api = KPublicAPI( bot_config[ex.value]["api_url"]) kucoin_app.scanner_quote_currencies = exchange_config.get( 'quote_currency', ['USDT']) kucoin_app.granularity = Granularity( Granularity.convert_to_enum( exchange_config.get('granularity', '1h'))) kucoin_app.adx_threshold = exchange_config.get( 'adx_threshold', 25) kucoin_app.volatility_threshold = exchange_config.get( 'volatility_threshold', 9) kucoin_app.minimum_volatility = exchange_config.get( 'minimum_volatility', 5) kucoin_app.minimum_volume = exchange_config.get( 'minimum_volume', 20000) kucoin_app.volume_threshold = exchange_config.get( 'volume_threshold', 20000) kucoin_app.minimum_quote_price = exchange_config.get( 'minimum_quote_price', 0.0000001) kucoin_app.selection_score = exchange_config.get( 'selection_score', 10) kucoin_app.tv_screener_ratings = [ rating.upper() for rating in exchange_config.get( 'tv_screener_ratings', ['STRONG_BUY']) ] exchanges_loaded.append(kucoin_app) else: raise ValueError(f"Invalid exchange found in config: {ex}") except AttributeError as e: print(f"Invalid exchange: {e}...ignoring.") return exchanges_loaded
def parser(app, coinbase_config, args={}): #print('CoinbasePro Configuration parse') if not app: raise Exception('No app is passed') if isinstance(coinbase_config, dict): if 'api_key' in coinbase_config or 'api_secret' in coinbase_config or 'api_passphrase' in coinbase_config: print(f'>>> migrating api keys to coinbasepro.key <<<\n') # create 'coinbasepro.key' fh = open('coinbasepro.key', 'w') fh.write(f"{coinbase_config['api_key']}\n{coinbase_config['api_secret']}\n{coinbase_config['api_passphrase']}") fh.close() if os.path.isfile('config.json') and os.path.isfile('coinbasepro.key'): coinbase_config['api_key_file'] = coinbase_config.pop('api_key') coinbase_config['api_key_file'] = 'coinbasepro.key' del coinbase_config['api_secret'] del coinbase_config['api_passphrase'] # read 'coinbasepro' element from config.json fh = open('config.json', 'r') config_json = ast.literal_eval(fh.read()) config_json['coinbasepro'] = coinbase_config fh.close() # write new 'coinbasepro' element fh = open('config.json', 'w') fh.write(json.dumps(config_json, indent=4)) fh.close() api_key_file = None if 'api_key_file' in args and args['api_key_file'] is not None: api_key_file = args['api_key_file'] elif 'api_key_file' in coinbase_config: api_key_file = coinbase_config['api_key_file'] if api_key_file is not None: try : with open( api_key_file, 'r') as f : key = f.readline().strip() secret = f.readline().strip() password = f.readline().strip() coinbase_config['api_key'] = key coinbase_config['api_secret'] = secret coinbase_config['api_passphrase'] = password except : raise RuntimeError(f"Unable to read {api_key_file}") if 'api_key' in coinbase_config and 'api_secret' in coinbase_config and \ 'api_passphrase' in coinbase_config and 'api_url' in coinbase_config: # validates the api key is syntactically correct p = re.compile(r"^[a-f0-9]{32}$") if not p.match(coinbase_config['api_key']): raise TypeError('Coinbase Pro API key is invalid') app.api_key = coinbase_config['api_key'] # validates the api secret is syntactically correct p = re.compile(r"^[A-z0-9+\/]+==$") if not p.match(coinbase_config['api_secret']): raise TypeError('Coinbase Pro API secret is invalid') app.api_secret = coinbase_config['api_secret'] # validates the api passphrase is syntactically correct p = re.compile(r"^[A-z0-9#$%=@!{},`~&*()<>?.:;_|^/+\[\]]{8,32}$") if not p.match(coinbase_config['api_passphrase']): raise TypeError('Coinbase Pro API passphrase is invalid') app.api_passphrase = coinbase_config['api_passphrase'] valid_urls = [ 'https://api.pro.coinbase.com/', 'https://api.pro.coinbase.com', 'https://public.sandbox.pro.coinbase.com', 'https://public.sandbox.pro.coinbase.com/' ] # validate Coinbase Pro API if coinbase_config['api_url'] not in valid_urls: raise ValueError('Coinbase Pro API URL is invalid') app.api_url = coinbase_config['api_url'] else: coinbase_config = {} config = merge_config_and_args(coinbase_config, args) defaultConfigParse(app, config) if 'base_currency' in config and config['base_currency'] is not None: if not isCurrencyValid(config['base_currency']): raise TypeError('Base currency is invalid.') app.base_currency = config['base_currency'] if 'quote_currency' in config and config['quote_currency'] is not None: if not isCurrencyValid(config['quote_currency']): raise TypeError('Quote currency is invalid.') app.quote_currency = config['quote_currency'] if 'market' in config and config['market'] is not None: app.market, app.base_currency, app.quote_currency = parseMarket(config['market']) if app.base_currency != '' and app.quote_currency != '': app.market = app.base_currency + '-' + app.quote_currency if 'granularity' in config and config['granularity'] is not None: if isinstance(config['granularity'], str) and config['granularity'].isnumeric() is True: app.granularity = Granularity.convert_to_enum(int(config['granularity'])) elif isinstance(config['granularity'], int): app.granularity = Granularity.convert_to_enum(config['granularity'])
def defaultConfigParse(app, config): if "live" in config: if isinstance(config["live"], int): if config["live"] in [0, 1]: app.is_live = config["live"] else: raise TypeError("live must be of type int") if "verbose" in config: if isinstance(config["verbose"], int): if config["verbose"] in [0, 1]: app.is_verbose = config["verbose"] else: raise TypeError("verbose must be of type int") if "graphs" in config: if isinstance(config["graphs"], int): if config["graphs"] in [0, 1]: app.save_graphs = config["graphs"] else: raise TypeError("graphs must be of type int") if "sim" in config: if isinstance(config["sim"], str): if config["sim"] in ["slow", "fast"]: app.is_live = 0 app.is_sim = 1 app.sim_speed = config["sim"] if config["sim"] in ["slow-sample", "fast-sample"]: app.is_live = 0 app.is_sim = 1 app.sim_speed = config["sim"] if "simstartdate" in config: app.simstartdate = config["simstartdate"] if "simenddate" in config: app.simenddate = config["simenddate"] else: raise TypeError("sim must be of type str") if "nobuynearhighpcnt" in config: if isinstance(config["nobuynearhighpcnt"], (int, float, str)): p = re.compile(r"^\-*[0-9\.]{1,5}$") if isinstance(config["nobuynearhighpcnt"], str) and p.match( config["nobuynearhighpcnt"] ): if float(config["nobuynearhighpcnt"]) > 0: app.nobuynearhighpcnt = float(config["nobuynearhighpcnt"]) else: raise ValueError("nobuynearhighpcnt must be positive") elif ( isinstance(config["nobuynearhighpcnt"], (int, float)) and config["nobuynearhighpcnt"] >= 0 and config["nobuynearhighpcnt"] <= 100 ): if float(config["nobuynearhighpcnt"]) > 0: app.nobuynearhighpcnt = float(config["nobuynearhighpcnt"]) else: raise ValueError("nobuynearhighpcnt must be positive") elif ( isinstance(config["nobuynearhighpcnt"], (int, float)) and config["nobuynearhighpcnt"] < 0 ): raise ValueError("nobuynearhighpcnt must be positive") else: raise TypeError("nobuynearhighpcnt must be of type int or str") if "sellupperpcnt" in config: if isinstance(config["sellupperpcnt"], (int, float, str)): p = re.compile(r"^\-*[0-9\.]{1,5}$") if isinstance(config["sellupperpcnt"], str) and p.match( config["sellupperpcnt"] ): if float(config["sellupperpcnt"]) > 0: app.sell_upper_pcnt = float(config["sellupperpcnt"]) else: raise ValueError("sellupperpcnt must be positive") elif ( isinstance(config["sellupperpcnt"], (int, float)) and config["sellupperpcnt"] >= 0 and config["sellupperpcnt"] <= 100 ): if float(config["sellupperpcnt"]) > 0: app.sell_upper_pcnt = float(config["sellupperpcnt"]) else: raise ValueError("sellupperpcnt must be positive") elif ( isinstance(config["sellupperpcnt"], (int, float)) and config["sellupperpcnt"] < 0 ): raise ValueError("sellupperpcnt must be positive") else: raise TypeError("sellupperpcnt must be of type int or str") if "selllowerpcnt" in config: if isinstance(config["selllowerpcnt"], (int, float, str)): p = re.compile(r"^\-*[0-9\.]{1,5}$") if isinstance(config["selllowerpcnt"], str) and p.match( config["selllowerpcnt"] ): if float(config["selllowerpcnt"]) < 0: app.sell_lower_pcnt = float(config["selllowerpcnt"]) else: raise ValueError("selllowerpcnt must be negative") elif ( isinstance(config["selllowerpcnt"], (int, float)) and config["selllowerpcnt"] >= -100 and config["selllowerpcnt"] <= 0 ): if float(config["selllowerpcnt"]) < 0: app.sell_lower_pcnt = float(config["selllowerpcnt"]) else: raise ValueError("selllowerpcnt must be negative") elif ( isinstance(config["selllowerpcnt"], (int, float)) and config["selllowerpcnt"] >= 0 ): raise ValueError("selllowerpcnt must be negative") else: raise TypeError("selllowerpcnt must be of type int or str") if "nosellmaxpcnt" in config: if isinstance(config["nosellmaxpcnt"], (int, float, str)): p = re.compile(r"^\-*[0-9\.]{1,5}$") if isinstance(config["nosellmaxpcnt"], str) and p.match( config["nosellmaxpcnt"] ): if float(config["nosellmaxpcnt"]) > 0: app.nosellmaxpcnt = float(config["nosellmaxpcnt"]) else: raise ValueError("nosellmaxpcnt must be positive") elif ( isinstance(config["nosellmaxpcnt"], (int, float)) and config["nosellmaxpcnt"] >= 0 and config["nosellmaxpcnt"] <= 100 ): if float(config["nosellmaxpcnt"]) > 0: app.nosellmaxpcnt = float(config["nosellmaxpcnt"]) else: raise ValueError("nosellmaxpcnt must be positive") elif ( isinstance(config["nosellmaxpcnt"], (int, float)) and config["nosellmaxpcnt"] < 0 ): raise ValueError("nosellmaxpcnt must be positive") else: raise TypeError("nosellmaxpcnt must be of type int or str") if "nosellminpcnt" in config: if isinstance(config["nosellminpcnt"], (int, float, str)): p = re.compile(r"^\-*[0-9\.]{1,5}$") if isinstance(config["nosellminpcnt"], str) and p.match( config["nosellminpcnt"] ): if float(config["nosellminpcnt"]) < 0: app.nosellminpcnt = float(config["nosellminpcnt"]) else: raise ValueError("nosellminpcnt must be negative") elif ( isinstance(config["nosellminpcnt"], (int, float)) and config["nosellminpcnt"] >= -100 and config["nosellminpcnt"] <= 0 ): if float(config["nosellminpcnt"]) < 0: app.nosellminpcnt = float(config["nosellminpcnt"]) else: raise ValueError("nosellminpcnt must be negative") elif ( isinstance(config["nosellminpcnt"], (int, float)) and config["nosellminpcnt"] >= 0 ): raise ValueError("nosellminpcnt must be negative") else: raise TypeError("nosellminpcnt must be of type int or str") if "trailingstoploss" in config: if isinstance(config["trailingstoploss"], (int, float, str)): p = re.compile(r"^\-*[0-9\.]{1,5}$") if isinstance(config["trailingstoploss"], str) and p.match( config["trailingstoploss"] ): if float(config["trailingstoploss"]) < 0: app.trailing_stop_loss = float(config["trailingstoploss"]) else: raise ValueError("trailingstoploss must be negative") elif ( isinstance(config["trailingstoploss"], (int, float)) and config["trailingstoploss"] >= -100 and config["trailingstoploss"] <= 0 ): if float(config["trailingstoploss"]) < 0: app.trailing_stop_loss = float(config["trailingstoploss"]) else: raise ValueError("trailingstoploss must be negative") elif ( isinstance(config["trailingstoploss"], (int, float)) and config["trailingstoploss"] >= 0 ): raise ValueError("trailingstoploss must be negative") else: raise TypeError("trailingstoploss must be of type int or str") if "trailingstoplosstrigger" in config: if isinstance(config["trailingstoplosstrigger"], (int, float, str)): p = re.compile(r"^\-*[0-9\.]{1,5}$") if isinstance(config["trailingstoplosstrigger"], str) and p.match( config["trailingstoplosstrigger"] ): if float(config["trailingstoplosstrigger"]) >= 0: app.trailing_stop_loss_trigger = float( config["trailingstoplosstrigger"] ) else: raise ValueError("trailingstoplosstrigger must be positive") elif ( isinstance(config["trailingstoplosstrigger"], (int, float)) and config["trailingstoplosstrigger"] >= 0 and config["trailingstoplosstrigger"] <= 100 ): if float(config["trailingstoplosstrigger"]) >= 0: app.trailing_stop_loss_trigger = float( config["trailingstoplosstrigger"] ) else: raise ValueError("trailingstoplosstrigger must be positive") elif ( isinstance(config["trailingstoplosstrigger"], (int, float)) and config["trailingstoplosstrigger"] <= 0 ): raise ValueError("trailingstoplosstrigger must be positive") else: raise TypeError("trailingstoplosstrigger must be of type int or str") if "autorestart" in config: if isinstance(config["autorestart"], int): if config["autorestart"] in [0, 1]: app.autorestart = bool(config["autorestart"]) else: raise TypeError("autorestart must be of type int") if "stats" in config: if isinstance(config["stats"], int): if bool(config["stats"]): app.stats = True if "statgroup" in config: app.statgroup = config["statgroup"] if "statstartdate" in config: app.statstartdate = config["statstartdate"] if "statdetail" in config: app.statdetail = config["statdetail"] else: raise TypeError("stats must be of type int") if "sellatloss" in config: if isinstance(config["sellatloss"], int): if config["sellatloss"] in [0, 1]: app.sell_at_loss = config["sellatloss"] if app.sell_at_loss == 0: app.sell_lower_pcnt = None else: raise TypeError("sellatloss must be of type int") if "preventloss" in config: if isinstance(config["preventloss"], int): if bool(config["preventloss"]): app.preventloss = True else: raise TypeError("preventloss must be of type int") if "preventlosstrigger" in config: if isinstance(config["preventlosstrigger"], (int, float)): if config["preventlosstrigger"] is not None: app.preventlosstrigger = float(config["preventlosstrigger"]) else: raise TypeError("preventlossmargin must be of type int or float") elif app.preventloss: if app.nosellmaxpcnt is not None: app.preventlosstrigger = app.nosellmaxpcnt else: app.preventlosstrigger = 1 if "preventlossmargin" in config: if isinstance(config["preventlossmargin"], (int, float)): if config["preventlossmargin"] is not None: app.preventlossmargin = config["preventlossmargin"] else: raise TypeError("preventlossmargin must be of type int or float") elif app.preventloss: app.preventlossmargin = 0.1 if "simresultonly" in config: if isinstance(config["simresultonly"], int): if bool(config["simresultonly"]): app.simresultonly = True else: raise TypeError("simresultonly must be of type int") if "sellatresistance" in config: if isinstance(config["sellatresistance"], int): if config["sellatresistance"] in [0, 1]: app.sellatresistance = bool(config["sellatresistance"]) else: raise TypeError("sellatresistance must be of type int") if "disablebullonly" in config: if isinstance(config["disablebullonly"], int): if config["disablebullonly"] in [0, 1]: app.disablebullonly = bool(config["disablebullonly"]) else: raise TypeError("disablebullonly must be of type int") if "disablebuynearhigh" in config: if isinstance(config["disablebuynearhigh"], int): if config["disablebuynearhigh"] in [0, 1]: app.disablebuynearhigh = bool(config["disablebuynearhigh"]) else: raise TypeError("disablebuynearhigh must be of type int") if "disablebuymacd" in config: if isinstance(config["disablebuymacd"], int): if config["disablebuymacd"] in [0, 1]: app.disablebuymacd = bool(config["disablebuymacd"]) else: raise TypeError("disablebuymacd must be of type int") if "disablebuyema" in config: if isinstance(config["disablebuyema"], int): if config["disablebuyema"] in [0, 1]: app.disablebuyema = bool(config["disablebuyema"]) else: raise TypeError("disablebuyema must be of type int") if "disablebuyobv" in config: if isinstance(config["disablebuyobv"], int): if config["disablebuyobv"] in [0, 1]: app.disablebuyobv = bool(config["disablebuyobv"]) else: raise TypeError("disablebuyobv must be of type int") if "disablebuyelderray" in config: if isinstance(config["disablebuyelderray"], int): if config["disablebuyelderray"] in [0, 1]: app.disablebuyelderray = bool(config["disablebuyelderray"]) else: raise TypeError("disablebuyelderray must be of type int") if "disablefailsafefibonaccilow" in config: if isinstance(config["disablefailsafefibonaccilow"], int): if config["disablefailsafefibonaccilow"] in [0,1 ]: app.disablefailsafefibonaccilow = bool(config["disablefailsafefibonaccilow"]) else: raise TypeError("disablefailsafefibonaccilow must be of type int") if "disablefailsafelowerpcnt" in config: if isinstance(config["disablefailsafelowerpcnt"], int): if config["disablefailsafelowerpcnt"] in [0, 1]: app.disablefailsafelowerpcnt = bool(config["disablefailsafelowerpcnt"]) else: raise TypeError("disablefailsafelowerpcnt must be of type int") if "disableprofitbankupperpcnt" in config: if isinstance(config["disableprofitbankupperpcnt"], int): if config["disableprofitbankupperpcnt"] in [0, 1]: app.disableprofitbankupperpcnt = bool(config["disableprofitbankupperpcnt"]) else: raise TypeError("disableprofitbankupperpcnt must be of type int") if "disableprofitbankreversal" in config: if isinstance(config["disableprofitbankreversal"], int): if config["disableprofitbankreversal"] in [0, 1]: app.disableprofitbankreversal = bool(config["disableprofitbankreversal"]) else: raise TypeError("disableprofitbankreversal must be of type int") if "disabletelegram" in config: if isinstance(config["disabletelegram"], int): if config["disabletelegram"] in [0, 1]: app.disabletelegram = bool(config["disabletelegram"]) else: raise TypeError("disabletelegram must be of type int") if "telegramtradesonly" in config: if isinstance(config["telegramtradesonly"], int): if config["telegramtradesonly"] in [0, 1]: app.telegramtradesonly = bool(config["telegramtradesonly"]) else: raise TypeError("telegramtradesonly must be of type int") if "disabletelegramerrormsgs" in config: if isinstance(config["disabletelegramerrormsgs"], int): if config["disabletelegramerrormsgs"] in [0, 1]: app.disabletelegramerrormsgs = bool(config["disabletelegramerrormsgs"]) else: raise TypeError("disabletelegramerrormsgs must be of type int") if "disablelog" in config: if isinstance(config["disablelog"], int): if config["disablelog"] in [0, 1]: app.disablelog = bool(config["disablelog"]) else: raise TypeError("disablelog must be of type int") if "disabletracker" in config: if isinstance(config["disabletracker"], int): if config["disabletracker"] in [0, 1]: app.disabletracker = bool(config["disabletracker"]) else: raise TypeError("disabletracker must be of type int") if "enableml" in config: if isinstance(config["enableml"], int): if config["enableml"] in [0, 1]: app.enableml = bool(config["enableml"]) else: raise TypeError("enableml must be of type int") if "websocket" in config: if isinstance(config["websocket"], int): if config["websocket"] in [0, 1]: app.websocket = bool(config["websocket"]) else: raise TypeError("websocket must be of type int") if "enableinsufficientfundslogging" in config: if isinstance(config["enableinsufficientfundslogging"], int): if config["enableinsufficientfundslogging"] in [0, 1]: app.enableinsufficientfundslogging = bool(config["enableinsufficientfundslogging"]) else: raise TypeError("enableinsufficientfundslogging must be of type int") if "enabletelegrambotcontrol" in config: if isinstance(config["enabletelegrambotcontrol"], int): if config["enabletelegrambotcontrol"] in [0, 1]: app.enabletelegrambotcontrol = bool(config["enabletelegrambotcontrol"]) else: raise TypeError("enabletelegrambotcontrol must be of type int") if "enableimmediatebuy" in config: if isinstance(config["enableimmediatebuy"], int): if config["enableimmediatebuy"] in [0, 1]: app.enableimmediatebuy = bool(config["enableimmediatebuy"]) else: raise TypeError("enableimmediatebuy must be of type int") if "sellsmartswitch" in config: if isinstance(config["sellsmartswitch"], int): if config["sellsmartswitch"] in [0, 1]: app.sell_smart_switch = config["sellsmartswitch"] if app.sell_smart_switch == 1: app.sell_smart_switch = 1 else: app.sell_smart_switch = 0 else: raise TypeError("sellsmartswitch must be of type int") # backward compatibility if "nosellatloss" in config: if isinstance(config["nosellatloss"], int): if config["nosellatloss"] in [0, 1]: app.sell_at_loss = int(not config["nosellatloss"]) if app.sell_at_loss == 0: app.sell_lower_pcnt = None app.trailing_stop_loss = None else: raise TypeError("nosellatloss must be of type int") if "smartswitch" in config: if isinstance(config["smartswitch"], int): if config["smartswitch"] in [0, 1]: app.smart_switch = config["smartswitch"] if app.smart_switch == 1: app.smart_switch = 1 else: app.smart_switch = 0 else: raise TypeError("smartswitch must be of type int") if "buypercent" in config: if isinstance(config["buypercent"], int): if config["buypercent"] > 0 and config["buypercent"] <= 100: app.buypercent = config["buypercent"] else: raise TypeError("buypercent must be of type int") if "sellpercent" in config: if isinstance(config["sellpercent"], int): if config["sellpercent"] > 0 and config["sellpercent"] <= 100: app.sellpercent = config["sellpercent"] else: raise TypeError("sellpercent must be of type int") if "lastaction" in config: if isinstance(config["lastaction"], str): if config["lastaction"] in ["BUY", "SELL"]: app.last_action = config["lastaction"] else: raise TypeError("lastaction must be of type str") if "buymaxsize" in config: if isinstance(config["buymaxsize"], (int, float)): if config["buymaxsize"] > 0: app.buymaxsize = config["buymaxsize"] else: raise TypeError("buymaxsize must be of type int or float") if "buyminsize" in config: if isinstance(config["buyminsize"], (int, float)): if config["buyminsize"] > 0: app.buyminsize = config["buyminsize"] else: raise TypeError("buyminsize must be of type int or float") if "buylastsellsize" in config: if isinstance(config["buylastsellsize"], int): if bool(config["buylastsellsize"]): app.buylastsellsize = True else: raise TypeError("buylastsellsize must be of type int") if "trailingbuypcnt" in config: if isinstance(config["trailingbuypcnt"], (int, float)): if config["trailingbuypcnt"] > 0: app.trailingbuypcnt = config["trailingbuypcnt"] else: raise TypeError("trailingbuypcnt must be of type int or float") if "trailingimmediatebuy" in config: if isinstance(config["trailingimmediatebuy"], int): if config["trailingimmediatebuy"] in [0, 1]: app.trailingimmediatebuy = bool(config["trailingimmediatebuy"]) else: raise TypeError("trailingimmediatebuy must be of type int") if "marketmultibuycheck" in config: if isinstance(config["marketmultibuycheck"], int): if config["marketmultibuycheck"] in [0, 1]: app.marketmultibuycheck = bool(config["marketmultibuycheck"]) else: raise TypeError("marketmultibuycheck must be of type int") if "logbuysellinjson" in config: if isinstance(config["logbuysellinjson"], int): if config["logbuysellinjson"] in [0, 1]: app.logbuysellinjson = bool(config["logbuysellinjson"]) else: raise TypeError("logbuysellinjson must be of type int") if 'granularity' in config and config['granularity'] is not None: app.smart_switch = 0 if isinstance(config['granularity'], str) and not config['granularity'].isnumeric() is True: app.granularity = Granularity.convert_to_enum(config['granularity']) else: app.granularity = Granularity.convert_to_enum(int(config['granularity'])) if "usekucoincache" in config: if isinstance(config["usekucoincache"], int): if bool(config["usekucoincache"]): app.usekucoincache = True else: raise TypeError("usekucoincache must be of type int")
def parser(app, kucoin_config, args={}): #print('Kucoin Configuration parse') if not app: raise Exception('No app is passed') if isinstance(kucoin_config, dict): if 'api_key' in kucoin_config or 'api_secret' in kucoin_config or 'api_passphrase' in kucoin_config: print('>>> migrating api keys to kucoin.key <<<', "\n") # create 'kucoin.key' fh = open('kucoin.key', 'w', encoding='utf8') fh.write(kucoin_config['api_key'] + "\n" + kucoin_config['api_secret'] + "\n" + kucoin_config['api_passphrase']) fh.close() if os.path.isfile('config.json') and os.path.isfile('kucoin.key'): kucoin_config['api_key_file'] = kucoin_config.pop('api_key') kucoin_config['api_key_file'] = 'kucoin.key' del kucoin_config['api_secret'] del kucoin_config['api_passphrase'] # read 'Kucoin' element from config.json fh = open('config.json', 'r', encoding='utf8') config_json = ast.literal_eval(fh.read()) config_json['kucoin'] = kucoin_config fh.close() # write new 'Kucoin' element fh = open('config.json', 'w') fh.write(json.dumps(config_json, indent=4)) fh.close() else: print('migration failed (io error)', "\n") api_key_file = None if 'api_key_file' in args and args['api_key_file'] is not None: api_key_file = args['api_key_file'] elif 'api_key_file' in kucoin_config: api_key_file = kucoin_config['api_key_file'] if api_key_file is not None: try: with open(api_key_file, 'r') as f: key = f.readline().strip() secret = f.readline().strip() password = f.readline().strip() kucoin_config['api_key'] = key kucoin_config['api_secret'] = secret kucoin_config['api_passphrase'] = password except: raise RuntimeError(f"Unable to read {api_key_file}") if 'api_key' in kucoin_config and 'api_secret' in kucoin_config and \ 'api_passphrase' in kucoin_config and 'api_url' in kucoin_config: # validates the api key is syntactically correct p = re.compile(r"^[A-z0-9]{24,24}$") if not p.match(kucoin_config['api_key']): raise TypeError('Kucoin API key is invalid') app.api_key = kucoin_config['api_key'] # validates the api secret is syntactically correct p = re.compile(r"^[A-z0-9-]{36,36}$") if not p.match(kucoin_config['api_secret']): raise TypeError('Kucoin API secret is invalid') app.api_secret = kucoin_config['api_secret'] # validates the api passphrase is syntactically correct p = re.compile(r"^[A-z0-9#$%=@!{},`~&*()<>?.:;_|^/+\[\]]{8,32}$") if not p.match(kucoin_config['api_passphrase']): raise TypeError('Kucoin API passphrase is invalid') app.api_passphrase = kucoin_config['api_passphrase'] valid_urls = [ 'https://api.kucoin.com/', 'https://api.kucoin.com', 'https://openapi-sandbox.kucoin.com/', 'https://openapi-sandbox.kucoin.com', ] # validate Kucoin API if kucoin_config['api_url'] not in valid_urls: raise ValueError('Kucoin API URL is invalid') app.api_url = kucoin_config['api_url'] app.base_currency = 'BTC' app.quote_currency = 'GBP' else: kucoin_config = {} config = merge_config_and_args(kucoin_config, args) defaultConfigParse(app, config) if 'base_currency' in config and config['base_currency'] is not None: if not isCurrencyValid(config['base_currency']): raise TypeError('Base currency is invalid.') app.base_currency = config['base_currency'] if 'quote_currency' in config and config['quote_currency'] is not None: if not isCurrencyValid(config['quote_currency']): raise TypeError('Quote currency is invalid.') app.quote_currency = config['quote_currency'] if 'market' in config and config['market'] is not None: app.market, app.base_currency, app.quote_currency = parseMarket( config['market']) if app.base_currency != '' and app.quote_currency != '': app.market = app.base_currency + '-' + app.quote_currency if 'granularity' in config and config['granularity'] is not None: if isinstance(config['granularity'], str) and config['granularity'].isnumeric() is True: app.granularity = Granularity.convert_to_enum( int(config['granularity'])) elif isinstance(config['granularity'], int): app.granularity = Granularity.convert_to_enum( config['granularity'])