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()
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)
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)