示例#1
0
 def __init__(self, json_file, json_log_size, exchange):
     self._lent = ''
     self._daysRemaining = ''
     self.output = JsonOutput(json_file, json_log_size, exchange)
     self.compactLog = bool(Config.get('BOT', 'jsonlogcompact', False))
     self.refreshStatus()
     self.persistStatus()
示例#2
0
 def __init__(self, file, logLimit, exchange=''):
     self.jsonOutputFile = file
     self.jsonOutput = {}
     self.clearStatusValues()
     self.jsonOutputLog = RingBuffer(logLimit)
     self.jsonOutput['exchange'] = exchange
     self.jsonOutput['label'] = Config.get("BOT", "label", "Lending Bot")
示例#3
0
 def __init__(self, cfg, weblog):
     super(Poloniex, self).__init__(cfg, weblog)
     self.logger = logging.getLogger(__name__)
     self.req_per_period = 6
     self.default_req_period = 1000  # milliseconds
     self.req_period = self.default_req_period
     self.req_time_log = RingBuffer(self.req_per_period)
     self.lock = threading.RLock()
     self.timeout = int(Config.get("BOT", "timeout", 30, 1, 180))
     self.url_public = 'https://poloniex.com/public'
     self.url_private = 'https://poloniex.com/tradingApi'
示例#4
0
    def get_rate_list(self, cur, seconds):
        """
        Query the database (cur) for rates that are within the supplied number of seconds and now.

        :param cur: The currency (database) to remove data from
        :param seconds: The number of seconds between the oldest order returned and now.

        :return: A pandas DataFrame object with named columns ('time', 'rate0', 'rate1',...)
        """
        # Request more data from the DB than we need to allow for skipped seconds
        request_seconds = int(seconds * 1.1)
        full_list = Config.get_all_currencies()
        if isinstance(cur, sqlite.Connection):
            db_con = cur
        else:
            if cur not in full_list:
                raise ValueError(
                    "{0} is not a valid currency, must be one of {1}".format(
                        cur, full_list))
            if cur not in self.currencies_to_analyse:
                return []
            db_con = self.create_connection(cur)

        price_levels = ['rate0']
        rates = self.get_rates_from_db(db_con,
                                       from_date=time.time() - request_seconds,
                                       price_levels=price_levels)
        if len(rates) == 0:
            return []

        df = pd.DataFrame(rates)

        columns = ['time']
        columns.extend(price_levels)
        try:
            df.columns = columns
        except Exception as ex:
            self.logger.error(
                "get_rate_list: cols: {0} rates:{1} db:{2}".format(
                    columns, rates, db_con))
            raise ex

        # convert unixtimes to datetimes so we can resample
        df.time = pd.to_datetime(df.time, unit='s')
        # If we don't have enough data return df, otherwise the resample will fill out all values with the same data.
        # Missing data tolerance allows for a percentage to be ignored and filled in by resampling.
        if len(df) < seconds * (self.data_tolerance / 100):
            return df
        # Resample into 1 second intervals, average if we get two in the same second and fill any empty spaces with the
        # previous value
        df = df.resample('1s', on='time').mean().ffill()
        return df
示例#5
0
    def create_connection(self, cur, db_path=None, db_type='sqlite3'):
        """
        Create a connection to the sqlite DB. This will create a new file if one doesn't exist.  We can use :memory:
        here for db_path if we don't want to store the data on disk

        :param cur: The currency (database) in the DB
        :param db_path: DB directory
        :return: Connection object or None
        """
        if db_path is None:
            prefix = Config.get_exchange()
            db_path = os.path.join(self.db_dir,
                                   '{0}-{1}.db'.format(prefix, cur))
        try:
            con = sqlite.connect(db_path)
            return con
        except Error as ex:
            self.logger.error(ex.message)
# pytest to work
import os
import sys
import inspect
currentdir = os.path.dirname(
    os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir)

from coinlendingbot.MarketAnalysis import MarketAnalysis  # nopep8
from coinlendingbot.Configuration import get_all_currencies  # nopep8
from coinlendingbot.Poloniex import Poloniex  # nopep8
import coinlendingbot.Configuration as Config  # nopep8
import coinlendingbot.Data as Data  # nopep8

Config.init(open('poloniex_test.cfg'), Data)
api = Poloniex(Config, None)
Data.init(api, None)
MA = MarketAnalysis(Config, api)


def new_db():
    db_con = MA.create_connection(None, ':memory:')
    MA.create_rate_table(db_con, 3)
    return db_con


def random_rates():
    return lists(floats(min_value=0.00001,
                        max_value=100,
                        allow_nan=False,
示例#7
0
def main(config, logconfig, dryrun):
    logging.config.fileConfig(logconfig)
    logger = logging.getLogger('main')
    logger.debug('config: {}, logconfig: {}, dryrun: {}'.format(
        config, logconfig, dryrun))

    Config.init(config)

    output_currency = Config.get('BOT', 'outputCurrency', 'BTC')
    end_date = Config.get('BOT', 'endDate')
    exchange = Config.get_exchange()

    json_output_enabled = Config.has_option(
        'BOT', 'jsonfile') and Config.has_option('BOT', 'jsonlogsize')
    jsonfile = Config.get('BOT', 'jsonfile', '')

    # Configure web server
    web_server_enabled = Config.getboolean('BOT', 'startWebServer')
    if web_server_enabled:
        logger.info('Web server enabled.')
        if json_output_enabled is False:
            # User wants webserver enabled. Must have JSON enabled. Force logging with defaults.
            json_output_enabled = True
            jsonfile = Config.get('BOT', 'jsonfile', 'www/botweblog.json')
        WebServer.initialize_web_server(Config)

    # Configure logging to display on webpage
    weblog = Logger(jsonfile, Decimal(Config.get('BOT', 'jsonlogsize', 200)),
                    exchange)

    welcome = 'Welcome to {} on {}'.format(
        Config.get("BOT", "label", "Lending Bot"), exchange)
    logger.info(welcome)
    weblog.log(welcome)

    # initialize the remaining stuff
    api = ExchangeApiFactory.createApi(exchange, Config, weblog)
    MaxToLend.init(Config, weblog)
    Data.init(api, weblog)
    Config.init(config, Data)
    notify_conf = Config.get_notification_config()
    if Config.has_option('MarketAnalysis', 'analyseCurrencies'):
        logger.info('MarketAnalysis enabled.')
        from coinlendingbot.MarketAnalysis import MarketAnalysis
        # Analysis.init(Config, api, Data)
        analysis = MarketAnalysis(Config, api)
        analysis.run()
    else:
        analysis = None
    Lending.init(Config, api, weblog, Data, MaxToLend, dryrun, analysis,
                 notify_conf)

    # load plugins
    PluginsManager.init(Config, api, weblog, notify_conf)

    try:
        while True:
            try:
                logger.info('New round.')
                Data.update_conversion_rates(output_currency,
                                             json_output_enabled)
                PluginsManager.before_lending()
                Lending.transfer_balances()
                Lending.cancel_all()
                Lending.lend_all()
                PluginsManager.after_lending()
                weblog.refreshStatus(
                    Data.stringify_total_lent(*Data.get_total_lent()),
                    Data.get_max_duration(end_date, "status"))
                weblog.persistStatus()
                logger.info('Round finished.')
                time.sleep(Lending.get_sleep_time())
            except KeyboardInterrupt:
                # allow existing the main bot loop
                raise
            except Exception as ex:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                logger.debug(ex)
                logger.debug(repr(traceback.format_tb(exc_traceback)))
                weblog.log_error(ex.message)
                weblog.persistStatus()
                if 'Invalid API key' in ex.message:
                    logger.critical(
                        "!!! Troubleshooting !!! Are your API keys correct? No quotation. Just plain keys."
                    )
                    exit(1)
                elif 'Nonce must be greater' in ex.message:
                    logger.critical(
                        "!!! Troubleshooting !!! Are you reusing the API key in multiple applications? "
                        + "Use a unique key for every application.")
                    exit(1)
                elif 'Permission denied' in ex.message:
                    logger.critical(
                        "!!! Troubleshooting !!! Are you using IP filter on the key?"
                    )
                    exit(1)
                elif 'timed out' in ex.message:
                    logger.warn("Timed out, will retry in " +
                                str(Lending.get_sleep_time()) + "sec")
                elif isinstance(ex, BadStatusLine):
                    logger.warn(
                        "Caught BadStatusLine exception from Poloniex, ignoring."
                    )
                elif 'Error 429' in ex.message:
                    additional_sleep = max(130.0 - Lending.get_sleep_time(), 0)
                    sum_sleep = additional_sleep + Lending.get_sleep_time()
                    msg = 'IP has been banned due to many requests. Sleeping for {} seconds'.format(
                        sum_sleep)
                    weblog.log_error(msg)
                    logger.warn(msg)
                    if Config.has_option('MarketAnalysis',
                                         'analyseCurrencies'):
                        if api.req_period <= api.default_req_period * 1.5:
                            api.req_period += 3
                        logger.warn(
                            "Caught ERR_RATE_LIMIT, sleeping capture and increasing request delay. Current"
                            + " {0}ms".format(api.req_period))
                        weblog.log_error(
                            'Expect this 130s ban periodically when using MarketAnalysis, '
                            + 'it will fix itself')
                    time.sleep(additional_sleep)
                # Ignore all 5xx errors (server error) as we can't do anything about it (https://httpstatuses.com/)
                elif isinstance(ex, URLError):
                    logger.error("Caught {0} from exchange, ignoring.".format(
                        ex.message))
                elif isinstance(ex, ApiError):
                    logger.error(
                        "Caught {0} reading from exchange API, ignoring.".
                        format(ex.message))
                else:
                    logger.error(traceback.format_exc())
                    logger.error(
                        "v{0} Unhandled error, please open a Github issue so we can fix it!"
                        .format(Data.get_bot_version()))
                    if notify_conf['notify_caught_exception']:
                        weblog.notify(
                            "{0}\n-------\n{1}".format(ex,
                                                       traceback.format_exc()),
                            notify_conf)
                time.sleep(Lending.get_sleep_time())

    except KeyboardInterrupt:
        if web_server_enabled:
            WebServer.stop_web_server()
        PluginsManager.on_bot_exit()
        weblog.log('bye')
        logger.info('bye')
# Hack to get relative imports - probably need to fix the dir structure instead but we need this at the minute for
# pytest to work
import os
import sys
import inspect

currentdir = os.path.dirname(
    os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir)

from coinlendingbot.Bitfinex import Bitfinex  # nopep8
import coinlendingbot.Configuration as Config  # nopep8
import coinlendingbot.Data as Data  # nopep8

Config.init(open('bitfinex_test.cfg'), Data)
api = Bitfinex(Config, None)
start_time = time.time()


def multiple_api_queries(n):
    try:
        for i in range(n):
            print("Thread {}".format(i + 1))
            thread1 = threading.Thread(target=call_get_open_loan_offers,
                                       args=[(i + 1)])
            thread1.start()
    except Exception as e:
        assert False, 'Thread ' + str(i + 1) + ':' + e.message