class BinanceStore(with_metaclass(MetaSingleton, object)):
    _GRANULARITIES = {
        (TimeFrame.Minutes, 1): '1m',
        (TimeFrame.Minutes, 3): '3m',
        (TimeFrame.Minutes, 5): '5m',
        (TimeFrame.Minutes, 15): '15m',
        (TimeFrame.Minutes, 30): '30m',
        (TimeFrame.Minutes, 60): '1h',
        (TimeFrame.Minutes, 120): '2h',
        (TimeFrame.Minutes, 240): '4h',
        (TimeFrame.Minutes, 360): '6h',
        (TimeFrame.Minutes, 480): '8h',
        (TimeFrame.Minutes, 720): '12h',
        (TimeFrame.Days, 1): '1d',
        (TimeFrame.Days, 3): '3d',
        (TimeFrame.Weeks, 1): '1w',
        (TimeFrame.Months, 1): '1M'
    }

    BrokerCls = None  # Broker class will autoregister
    DataCls = None  # Data class will auto register

    @classmethod
    def getdata(cls, *args, **kwargs):
        """Returns ``DataCls`` with args, kwargs"""
        return cls.DataCls(*args, **kwargs)

    @classmethod
    def getbroker(cls, *args, **kwargs):
        """Returns broker with *args, **kwargs from registered ``BrokerCls``"""
        return cls.BrokerCls(*args, **kwargs)

    def __init__(self,
                 api_key,
                 api_secret,
                 coin_refer,
                 coin_target,
                 retries=5):
        self.binance = Client(api_key, api_secret)
        self.binance_socket = BinanceSocketManager(self.binance)
        self.coin_refer = coin_refer
        self.coin_target = coin_target
        self.symbol = coin_refer + coin_target
        self.retries = retries

        self.step_size = None
        self.tick_size = None
        self.get_filters()

        self._cash = 0
        self._value = 0
        self.get_balance()

    def _format_value(self, value, step):
        precision = step.find('1') - 1
        if precision > 0:
            return '{:0.0{}f}'.format(value, precision)
        return floor(int(value))

    def retry(func):
        @wraps(func)
        def wrapper(self, *args, **kwargs):
            for attempt in range(1, self.retries + 1):
                time.sleep(60 / 1200)  # API Rate Limit
                try:
                    return func(self, *args, **kwargs)
                except (BinanceAPIException, ConnectTimeout,
                        ConnectionError) as err:
                    if isinstance(err,
                                  BinanceAPIException) and err.code == -1021:
                        # Recalculate timestamp offset between local and Binance's server
                        res = self.binance.get_server_time()
                        self.binance.timestamp_offset = res[
                            'serverTime'] - int(time.time() * 1000)

                    if attempt == self.retries:
                        raise

        return wrapper

    @retry
    def cancel_open_orders(self):
        orders = self.binance.get_open_orders(symbol=self.symbol)
        for o in orders:
            self.cancel_order(o['orderId'])

    @retry
    def cancel_order(self, order_id):
        try:
            self.binance.cancel_order(symbol=self.symbol, orderId=order_id)
        except BinanceAPIException as api_err:
            if api_err.code == -2011:  # Order filled
                return
            else:
                raise api_err
        except Exception as err:
            raise err

    @retry
    def create_order(self, side, type, size, price):
        params = dict()
        if type in [ORDER_TYPE_LIMIT, ORDER_TYPE_STOP_LOSS_LIMIT]:
            params.update({'timeInForce': TIME_IN_FORCE_GTC})
        if type != ORDER_TYPE_MARKET:
            params.update({'price': self.format_price(price)})

        return self.binance.create_order(symbol=self.symbol,
                                         side=side,
                                         type=type,
                                         quantity=self.format_quantity(size),
                                         **params)

    def format_price(self, price):
        return self._format_value(price, self.tick_size)

    def format_quantity(self, size):
        return self._format_value(size, self.step_size)

    @retry
    def get_asset_balance(self, asset):
        balance = self.binance.get_asset_balance(asset)
        return float(balance['free']), float(balance['locked'])

    def get_balance(self):
        free, locked = self.get_asset_balance(self.coin_target)
        self._cash = free
        self._value = free + locked

    def get_filters(self):
        symbol_info = self.get_symbol_info(self.symbol)
        for f in symbol_info['filters']:
            if f['filterType'] == 'LOT_SIZE':
                self.step_size = f['stepSize']
            elif f['filterType'] == 'PRICE_FILTER':
                self.tick_size = f['tickSize']

    def get_interval(self, timeframe, compression):
        return self._GRANULARITIES.get((timeframe, compression))

    @retry
    def get_symbol_info(self, symbol):
        return self.binance.get_symbol_info(symbol)

    def start_socket(self):
        if self.binance_socket.is_alive():
            return
        self.binance_socket.daemon = True
        self.binance_socket.start()

    def stop_socket(self):
        self.binance_socket.close()
        reactor.stop()
Example #2
0
class BinanceStore(with_metaclass(MetaSingleton, object)):
    _GRANULARITIES = {
        (TimeFrame.Minutes, 1): '1m',
        (TimeFrame.Minutes, 3): '3m',
        (TimeFrame.Minutes, 5): '5m',
        (TimeFrame.Minutes, 15): '15m',
        (TimeFrame.Minutes, 30): '30m',
        (TimeFrame.Minutes, 60): '1h',
        (TimeFrame.Minutes, 120): '2h',
        (TimeFrame.Minutes, 240): '4h',
        (TimeFrame.Minutes, 360): '6h',
        (TimeFrame.Minutes, 480): '8h',
        (TimeFrame.Minutes, 720): '12h',
        (TimeFrame.Days, 1): '1d',
        (TimeFrame.Days, 3): '3d',
        (TimeFrame.Weeks, 1): '1w',
        (TimeFrame.Months, 1): '1M',
    }

    BrokerCls = None  # Broker class will autoregister
    DataCls = None  # Data class will auto register

    @classmethod
    def getdata(cls, *args, **kwargs):
        """Returns ``DataCls`` with args, kwargs"""
        return cls.DataCls(*args, **kwargs)

    @classmethod
    def getbroker(cls, *args, **kwargs):
        """Returns broker with *args, **kwargs from registered ``BrokerCls``"""
        return cls.BrokerCls(*args, **kwargs)

    def __init__(self,
                 api_key,
                 api_secret,
                 coin_refer,
                 coin_target,
                 retries=5):
        self.binance = Client(api_key, api_secret)
        self.binance_socket = BinanceSocketManager(self.binance)
        self.coin_refer = coin_refer
        self.coin_target = coin_target
        self.retries = retries

        self._precision = None
        self._step_size = None

        self._cash = 0
        self._value = 0
        self.get_balance()

    def retry(method):
        @wraps(method)
        def retry_method(self, *args, **kwargs):
            for i in range(self.retries):
                time.sleep(500 / 1000)  # Rate limit
                try:
                    return method(self, *args, **kwargs)
                except BinanceAPIException:
                    if i == self.retries - 1:
                        raise

        return retry_method

    @retry
    def cancel_order(self, order_id):
        try:
            self.binance.cancel_order(symbol=self.symbol, orderId=order_id)
        except BinanceAPIException as api_err:
            if api_err.code == -2011:  # Order filled
                return
            else:
                raise api_err
        except Exception as err:
            raise err

    @retry
    def create_order(self, side, type, size, price):
        return self.binance.create_order(symbol=self.symbol,
                                         side=side,
                                         type=type,
                                         timeInForce=TIME_IN_FORCE_GTC,
                                         quantity=self.format_quantity(size),
                                         price=self.strprecision(price))

    @retry
    def close_open_orders(self):
        orders = self.binance.get_open_orders(symbol=self.symbol)
        for o in orders:
            self.cancel_order(o['orderId'])

    def format_quantity(self, size):
        precision = self.step_size.find('1') - 1
        if precision > 0:
            return '{:0.0{}f}'.format(size, precision)
        return floor(int(size))

    @retry
    def get_asset_balance(self, asset):
        balance = self.binance.get_asset_balance(asset)
        return float(balance['free']), float(balance['locked'])

    def get_balance(self):
        free, locked = self.get_asset_balance(self.coin_target)
        self._cash = free
        self._value = free + locked

    def get_interval(self, timeframe, compression):
        return self._GRANULARITIES.get((timeframe, compression))

    def get_precision(self):
        symbol_info = self.get_symbol_info(self.symbol)
        self._precision = symbol_info['baseAssetPrecision']

    def get_step_size(self):
        symbol_info = self.get_symbol_info(self.symbol)
        for f in symbol_info['filters']:
            if f['filterType'] == 'LOT_SIZE':
                self._step_size = f['stepSize']

    @retry
    def get_symbol_info(self, symbol):
        return self.binance.get_symbol_info(symbol)

    @property
    def precision(self):
        if not self._precision:
            self.get_precision()
        return self._precision

    def start_socket(self):
        if self.binance_socket.is_alive():
            return

        self.binance_socket.daemon = True
        self.binance_socket.start()

    @property
    def step_size(self):
        if not self._step_size:
            self.get_step_size()

        return self._step_size

    def stop_socket(self):
        self.binance_socket.close()
        reactor.stop()
        self.binance_socket.join()

    def strprecision(self, value):
        return '{:.{}f}'.format(value, self.precision)

    @property
    def symbol(self):
        return '{}{}'.format(self.coin_refer, self.coin_target)
Example #3
0
            else:
                p_is_msg('-' * 20)
                mon_popup()  # later send to notification - telegram - ...
            #  (short version) is_oco = False if is_oco else p_is_msg('-' * 20); mon_popup()


bm = BinanceSocketManager(client)
conn_key = bm.start_user_socket(process_message)  # start user sockets
bm.start()  # Start the socket manager

try:
    is_counter = 96  # Run x * countdown and then exit program
    while is_counter > 0:
        countdown(60 * 14)  # countdown x seconds 1800 = 30 minutes
        is_counter -= 1
        if bm.is_alive():
            print(bm.is_alive())
            #  send keepalive
            client.ping()
        else:
            #  Connect to user socket
            print(bm.is_alive())
            conn_key = bm.start_user_socket(process_message)
            #  then start the socket manager
            bm.start()
except KeyboardInterrupt:
    print(bm.is_alive())
    print('Exiting the script')

#  Stop sockets
bm.stop_socket(conn_key)