def authenticate(self, key=None, secret=None, key_file=None): """Authenticate a user. :param key: User's public key. :param secret: User's private key. :param key_file: A ke file with public and private keys. :return True if authentication was successful If key file is provided, it will override values provided via key and secret """ self._key = key self._secret = secret self._keyFile = key_file self.logger.info('Authenticating ...') rest_client = BinanceRESTClient(key=key, secret=secret, key_file=key_file) ret = rest_client.create_listen_key() try: self._listenKey = ret['listenKey'] self.logger.info('Authentication successful') except: self.logger.info('Authentication failed') return False # get a snapshot of open orders open_orders = rest_client.open_orders() if open_orders is not None: for order in open_orders: order_id = int(order['orderId']) timestamp = int(order['timestamp']) symbol = order['symbol'] order_type = order['type'] side = order['side'] price = float(order['price']) amount = float(order['amount']) filled = float(order['filled']) total = price * amount percent_filled = '{:.2f}'.format(100 * filled / amount) self._orders.append([ order_id, timestamp, symbol, order_type, side, price, amount, percent_filled, total ]) # get a snapshot of balances self._balances = rest_client.balance() if self._balances is None: self._balances = {} self._subscribe(self._listenKey) self.authenticated = True return True
def subscribe_trades(self, symbol, update_handler=None): """Subscribe to the channel for trades. :param symbol: A symbol for a ticker (pair). :param update_handler: A callback handler that should handle the asynchronous update of trades. :return: A tuple of a string that represents a stream (channel) identifier and a snapshot. :raises ExchangeException """ try: symbol = symbol.lower() stream = symbol + '@trade' if update_handler: dispatcher.connect(update_handler, signal=stream, sender='binance') if stream not in self._subscriptions: self.logger.info(f'Subscribing to trades for {symbol} ...') # get trades snapshot using the REST api init_trade_data = BinanceRESTClient().trades(symbol.lower()) if init_trade_data is None: init_trade_data = [] self._data[stream] = BinanceTrades(stream, init_trade_data) self._subscribe(stream) else: self.logger.info(f'Already subscribed to {symbol} trades') return stream, self._data[stream].snapshot() except Exception as e: raise ExchangeException( self.name(), 'Exception while trying to subscribe to a channel for trades', orig_exception=e, logger=self.logger)
def demo_binance_listen_key(file_path): """Runs a demo of setting up and using listen key on Binance. :param file_path the full path to the key file Signs and sends a request using the REST client to create, ping and close the listen key. NOTE: the key file must be provided in the exchanges/api_keys folder with the name binance.key """ try: binance = BinanceRESTClient(key_file=file_path) print() print('CREATE LISTEN KEY\n' + '-' * 30) listen_key = binance.create_listen_key()['listenKey'] print(binance.create_listen_key()) print() print() print('PING LISTEN KEY\n' + '-' * 30) print(binance.ping_listen_key(listen_key)) print() print() print('CLOSE LISTEN KEY\n' + '-' * 30) print(binance.close_listen_key(listen_key)) print() except ExchangeException as e: print(e) print(''.join(traceback.format_exc()))
def setUpClass(cls) -> None: key_file = 'exchanges/api_keys/binance.key' if not path.exists(key_file) or not path.isfile(key_file): print( "Testing Binance authenticated channels requires an API key!") print( "Please, provide the key file named 'binance.key' in the exchanges/api_keys folder." ) raise unittest.SkipTest('Key file not found or invalid!') cls.client = BinanceRESTClient(key_file=key_file) if not cls.client.authenticated: raise unittest.SkipTest( 'Authentication failed using given key file!')
def subscribe_candles(self, symbol, interval='1m', update_handler=None): """Subscribe to the channel for candles. :param symbol: A symbol for a ticker (pair). :param interval Time interval for a candle. :param update_handler: A callback handler that should handle the asynchronous update of trades. :return: A tuple of a string that represents a stream (channel) identifier and a snapshot. :raises ExchangeException """ valid_intervals = [ '1m', '3m', '5m', '15m', '30m', '1h', '2h', '4h', '6h', '8h', '12h', '1d', '3d', '1w', '1M' ] if interval not in valid_intervals: raise ExchangeException( self.name(), f'Unsupported candle interval. Must be one of {valid_intervals}' ) try: stream = symbol.lower() + '@kline_' + interval if update_handler is not None: dispatcher.connect(update_handler, signal=stream, sender='binance') if stream not in self._subscriptions: self.logger.info( f'Subscribing to {interval} candles for {symbol} ...') # Get candle snapshot using the rest api init_candle_data = BinanceRESTClient().candles( symbol.lower(), interval=interval) if init_candle_data is None: init_candle_data = [] self._data[stream] = BinanceCandles(stream, init_candle_data) self._subscribe(stream) else: self.logger.info(f'Already subscribed to {symbol} candles') return stream, self._data[stream].snapshot() except Exception as e: raise ExchangeException( self.name(), 'Exception while trying to subscribe to a channel for candles', orig_exception=e, logger=self.logger)
def subscribe_order_book(self, symbol, update_handler=None, **kwargs): """Subscribe to order book channel. :param symbol: A symbol for a ticker (pair). :param update_handler: A callback handler that should handle the asynchronous update of the order book. :param kwargs: Additional parameters that differ between exchanges. :return: A tuple of a string that represents a stream (channel) identifier and a snapshot. :raises ExchangeException """ try: symbol = symbol.lower() stream = symbol + '@depth' if update_handler is not None: dispatcher.connect(update_handler, signal=stream, sender='binance') if stream not in self._subscriptions: self.logger.info(f'Subscribing to order book for {symbol} ...') # Get a depth snapshot using the rest api init_book_data = BinanceRESTClient().order_book(symbol) if not init_book_data: init_book_data = {'bids': [], 'asks': []} self._data[stream] = BinanceOrderBook(stream, init_book_data) self._subscribe(stream) else: self.logger.info(f'Already subscribed to {symbol} book') return stream, self._data[stream].snapshot() except Exception as e: raise ExchangeException( self.name(), 'Exception while trying to subscribe to an order book', orig_exception=e, logger=self.logger)
class BinanceRESTPublicClientTestCase(unittest.TestCase): client = BinanceRESTClient() def test_ping(self): self.assertTrue(self.client.ping()) def test_quote_currencies(self): currencies = self.client.quote_currencies() self.assertIs(type(currencies), list) self.assertTrue('BTC' in currencies) self.assertTrue('USDT' in currencies) def test_symbols(self): try: symbols = self.client.symbols() except Exception as e: self.fail("Method threw an exception: {}".format(e)) self.assertIs(type(symbols), list) self.assertTrue('BTCUSDT' in symbols) self.assertTrue('BNBBTC' in symbols) def test_symbols_details(self): try: symbols_details = self.client.symbols_details() except Exception as e: self.fail("Method threw an exception: {}".format(e)) self.assertIs(type(symbols_details), dict) self.assertTrue('BTCUSDT' in symbols_details) self.assertEqual(symbols_details['BTCUSDT']['baseAsset'], 'BTC') self.assertEqual(symbols_details['BTCUSDT']['quoteAsset'], 'USDT') self.assertEqual(symbols_details['BTCUSDT']['minAmount'], '0.00000100') def test_candle_intervals(self): try: intervals = self.client.candle_intervals() except Exception as e: self.fail("Method threw an exception: {}".format(e)) self.assertIs(type(intervals), list) self.assertTrue('1m' in intervals) def test_ticker(self): try: ticker = self.client.ticker('BTCUSDT') except Exception as e: self.fail("Method threw an exception: {}".format(e)) self.assertIs(type(ticker), list) self.assertEqual(len(ticker), 8) def test_all_tickers(self): try: tickers = self.client.all_tickers() except Exception as e: self.fail("Method threw an exception: {}".format(e)) self.assertIs(type(tickers), dict) self.assertTrue('BTCUSDT' in tickers) self.assertIs(type(tickers['BTCUSDT']), list) self.assertEqual(len(tickers['BTCUSDT']), 8) def test_order_book(self): try: book = self.client.order_book('BTCUSDT') except Exception as e: self.fail("Method threw an exception: {}".format(e)) self.assertIs(type(book), dict) self.assertTrue('bids' in book) self.assertTrue('asks' in book) def test_trades(self): try: trades = self.client.trades('BTCUSDT') except Exception as e: self.fail("Method threw an exception: {}".format(e)) self.assertIs(type(trades), list) self.assertIs(type(trades[0]), list) self.assertEqual(len(trades[0]), 4) self.assertTrue('buy' in trades[0] or 'sell' in trades[0]) def test_candles(self): # this also covers testing the historical_candles method try: candles = self.client.candles('BTCUSDT', '1m', startTime=1560696720000, endTime=1560696780000) except Exception as e: self.fail("Method threw an exception: {}".format(e)) self.assertIs(type(candles), list) self.assertListEqual(candles[0], [ 1560696720000, "9215.67000000", "9230.00000000", "9215.01000000", "9226.26000000", "38.22828700" ])
def demo_binance_authenticated_api(file_path): """Runs a demo of Binance authenticated endpoints. :param file_path the full path to the key file For a set of Binance authenticated endpoints, signs and sends a request using the REST client and the provided key_file and prints the formatted result in the console NOTE: the key file must be provided in the exchanges/api_keys folder with the name binance.key Endpoints tested: server_time balance user_trades place_limit_order order open_orders open_orders_for all_orders all_orders_since cancel_order """ # 1. Make sure to update the key file before running this demo # 2. Set the prices so that they do not get filled (i.e. buy price bellow current price) try: binance = BinanceRESTClient(key_file=file_path) assert binance.authenticated print('=' * 100) print(' TESTING Binance authenticated endpoints') print('=' * 100) print() print() print('SERVER TIME\n' + '-' * 30) print(binance.server_time()) print() print('BALANCES\n' + '-' * 30) print(binance.balance()['BTC']) print() print('MY TRADES\n' + '-' * 30) print(binance.user_trades('BNBBTC', limit=10)) print() print('PLACE LIMIT ORDER\n' + '-' * 30) order1 = binance.place_limit_order('buy', 'bnbbtc', 1, 0.0010655) print(order1) print() print('PLACE LIMIT ORDER\n' + '-' * 30) order2 = binance.place_limit_order('buy', 'trxbtc', 1000, 0.00000085) print(order2) print() print('PLACE LIMIT ORDER\n' + '-' * 30) order3 = binance.place_limit_order('buy', 'bnbbtc', 1, 0.00113) print(order3) print() print('GET A SINGLE ORDER STATUS\n' + '-' * 30) res = binance.order(order1['orderId'], 'BNBBTC') for r in res.items(): print(r) print() print('GET ALL OPEN ORDERS\n' + '-' * 30) res = binance.open_orders() for r in res: print(r) print() print('GET ALL OPEN ORDERS FOR A SYMBOL\n' + '-' * 30) res = binance.open_orders_for(order1['symbol']) for r in res: print(r) print() print('GET ALL ORDERS FOR A SYMBOL\n' + '-' * 30) res = binance.all_orders(order1['symbol'], limit=10) for r in res: print(r) print() print('GET ALL ORDERS STARTING FROM THE FIRST ORDER\n' + '-' * 30) res = binance.all_orders_since(order1['symbol'], order1['orderId']) for r in res: print(r) print() print('CANCEL ORDER\n' + '-' * 30) print(binance.cancel_order(order1['orderId'], order1['symbol'])) print() print('CANCEL ORDER\n' + '-' * 30) print(binance.cancel_order(order2['orderId'], order2['symbol'])) print() print('CANCEL ORDER\n' + '-' * 30) print(binance.cancel_order(order3['orderId'], order3['symbol'])) except ExchangeException as e: print(e) print(''.join(traceback.format_exc()))
def demo_binance_public_api(): """Runs a demo of Binance public endpoints. For a set of Binance public endpoints, sends a request using the REST client and prints the formatted result in the console Endpoints tested: ping server_time symbols symbols_details ticker all_tickers order_book trades candles historical_candles """ try: binance = BinanceRESTClient() print('=' * 100) print(' TESTING Binance public endpoints') print('=' * 100) print() print('STATUS\n' + '-' * 30) print(binance.ping()) print() print('SERVER TIME\n' + '-' * 30) print(binance.server_time()) print() print('SYMBOLS\n' + '-' * 30) print(binance.symbols()) print() print('SYMBOL DETAILS\n' + '-' * 30) print(binance.symbols_details()['BNBBTC']) print() print('TICKER\n' + '-' * 30) print(binance.ticker('bnbbtc')) print() print('ALL TICKERS (only showing the ones starting with A)\n' + '-' * 30) res = binance.all_tickers() for k in res.keys(): if k.startswith('A'): print(k, res[k]) print() print('ORDER BOOK\n' + '-' * 30) res = binance.order_book('bnbbtc', limit=10) for r in res: print(r) for i in res[r]: print(i) print() print('TRADES\n' + '-' * 30) res = binance.trades('bnbbtc', limit=10) for r in res: print(r) print() print('CANDLES\n' + '-' * 30) res = binance.candles('bnbbtc', '1m', limit=10) for r in res: print(r) print() print('HISTORIC CANDLES\n' + '-' * 30) res = binance.historical_candles('bnbbtc', '1m', start_time=1519862400000, end_time=1519863300000) for r in res: print(r) print() except ExchangeException as e: print(e) print(''.join(traceback.format_exc()))