예제 #1
0
    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
예제 #2
0
    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!')
예제 #5
0
    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)
예제 #6
0
    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()))