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
예제 #2
0
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"
예제 #4
0
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'])
예제 #6
0
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")
예제 #7
0
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'])