title: Error when trying to access binance API: 'Binance' object has no attribute 'binance_keys'
body: <p>Please assist, i am coding a bot working with Binance and get the error stated when i try access the API to make a purchase. the API key is stored in a txt file:</p>
  <p>line 332, in signRequest
  signature = hmac.new(self.binance_keys['secret_key'].encode('utf-8'), query_string.encode('utf-8'), hashlib.sha256)
  AttributeError: 'Binance' object has no attribute 'binance_keys'</p>
  <p>Code line 332:</p>
  <pre><code>import requests 
  import json
  import decimal
  import hmac
  import time
  import pandas as pd
  import hashlib
  from decimal import Decimal
  
  request_delay = 1000
  
  class Binance:
  
      ORDER_STATUS_NEW = 'NEW'
      ORDER_STATUS_PARTIALLY_FILLED = 'PARTIALLY_FILLED'
      ORDER_STATUS_FILLED = 'FILLED'
      ORDER_STATUS_CANCELED = 'CANCELED'
      ORDER_STATUS_PENDING_CANCEL = 'PENDING_CANCEL'
      ORDER_STATUS_REJECTED = 'REJECTED'
      ORDER_STATUS_EXPIRED = 'EXPIRED'
  
      SIDE_BUY = 'BUY'
      SIDE_SELL = 'SELL'
  
      ORDER_TYPE_LIMIT = 'LIMIT'
      ORDER_TYPE_MARKET = 'MARKET'
      ORDER_TYPE_STOP_LOSS = 'STOP_LOSS'
      ORDER_TYPE_STOP_LOSS_LIMIT = 'STOP_LOSS_LIMIT'
      ORDER_TYPE_TAKE_PROFIT = 'TAKE_PROFIT'
      ORDER_TYPE_TAKE_PROFIT_LIMIT = 'TAKE_PROFIT_LIMIT'
      ORDER_TYPE_LIMIT_MAKER = 'LIMIT_MAKER'
  
      KLINE_INTERVALS = ['1m', '3m', '5m', '15m', '30m', '1h', '2h', '4h', '6h', '8h', '12h', '1d', '3d', '1w', '1M']
  
      def __init__(self, filename=None):
  
          self.base = 'https://api.binance.com'
  
          self.endpoints = {
              &quot;order&quot;: '/api/v3/order',
              &quot;testOrder&quot;: '/api/v3/order/test',
              &quot;allOrders&quot;: '/api/v3/allOrders',
              &quot;klines&quot;: '/api/v3/klines',
              &quot;exchangeInfo&quot;: '/api/v3/exchangeInfo',
              &quot;24hrTicker&quot; : '/api/v3/ticker/24hr',
              &quot;averagePrice&quot; : '/api/v3/avgPrice',
              &quot;orderBook&quot; : '/api/v3/depth',
              &quot;account&quot; : '/api/v3/account'
          }
          self.account_access = False
  
          if filename == None:
              return
      
          f = open(filename, &quot;r&quot;)
          contents = []
          if f.mode == 'r':
              contents = f.read().split('\n')
  
          self.binance_keys = dict(api_key = contents[0], secret_key=contents[1])
  
          self.headers = {&quot;X-MBX-APIKEY&quot;: self.binance_keys['api_key']}
  
          self.account_access = True
      
      def _get(self, url, params=None, headers=None) -&gt; dict:
          &quot;&quot;&quot; Makes a Get Request &quot;&quot;&quot;
          try: 
              response = requests.get(url, params=params, headers=headers)
              data = json.loads(response.text)
              data['url'] = url
          except Exception as e:
              print(&quot;Exception occured when trying to access &quot;+url)
              print(e)
              data = {'code': '-1', 'url':url, 'msg': e}
          return data
  
      def _post(self, url, params=None, headers=None) -&gt; dict:
          &quot;&quot;&quot; Makes a Post Request &quot;&quot;&quot;
          try: 
              response = requests.post(url, params=params, headers=headers)
              data = json.loads(response.text)
              data['url'] = url
          except Exception as e:
              print(&quot;Exception occured when trying to access &quot;+url)
              print(e)
              data = {'code': '-1', 'url':url, 'msg': e}
          return data
  
      def GetTradingSymbols(self, quoteAssets:list=None):
          ''' Gets All symbols which are tradable (currently) '''
          url = self.base + self.endpoints[&quot;exchangeInfo&quot;]
          data = self._get(url)
          if data.__contains__('code'):
              return []
  
          symbols_list = []
          for pair in data['symbols']:
              if pair['status'] == 'TRADING':
                  if quoteAssets != None and pair['quoteAsset'] in quoteAssets:
                      symbols_list.append(pair['symbol'])
  
          return symbols_list
  
      def GetSymbolDataOfSymbols(self, symbols:list=None):
          ''' Gets All symbols which are tradable (currently) '''
          url = self.base + self.endpoints[&quot;exchangeInfo&quot;]
          data = self._get(url)
          if data.__contains__('code'):
              return []
  
          symbols_list = []
  
          for pair in data['symbols']:
              if pair['status'] == 'TRADING':
                  if symbols != None and pair['symbol'] in symbols:
                      symbols_list.append(pair)
  
          return symbols_list
  
      def GetSymbolKlinesExtra(self, symbol:str, interval:str, limit:int=1000, end_time=False):
          # Basicall, we will be calling the GetSymbolKlines as many times as we need 
          # in order to get all the historical data required (based on the limit parameter)
          # and we'll be merging the results into one long dataframe.
  
          repeat_rounds = 0
          if limit &gt; 1000:
              repeat_rounds = int(limit/1000)
          initial_limit = limit % 1000
          if initial_limit == 0:
              initial_limit = 1000
          # First, we get the last initial_limit candles, starting at end_time and going
          # backwards (or starting in the present moment, if end_time is False)
          df = self.GetSymbolKlines(symbol, interval, limit=initial_limit, end_time=end_time)
          while repeat_rounds &gt; 0:
              # Then, for every other 1000 candles, we get them, but starting at the beginning
              # of the previously received candles.
              df2 = self.GetSymbolKlines(symbol, interval, limit=1000, end_time=df['time'][0])
              df = df2.append(df, ignore_index = True)
              repeat_rounds = repeat_rounds - 1
          
          return df
  
      def GetAccountData(self) -&gt; dict:
          &quot;&quot;&quot; Gets Balances &amp; Account Data &quot;&quot;&quot;
  
          url = self.base + self.endpoints[&quot;account&quot;]
          
          params = {
          'recvWindow': 6000,
          'timestamp': int(round(time.time()*1000)) + request_delay
          }
          self.signRequest(params)
          
          return self._get(url, params, self.headers)
  
      def Get24hrTicker(self, symbol:str):
          url = self.base + self.endpoints['24hrTicker'] + &quot;?symbol=&quot;+symbol
          return self._get(url)
  
      def GetSymbolKlines(self, symbol:str, interval:str, limit:int=1000, end_time=False):
          ''' 
          Gets trading data for one symbol 
          
          Parameters
          --
              symbol str:        The symbol for which to get the trading data
  
              interval str:      The interval on which to get the trading data
                  minutes      '1m' '3m' '5m' '15m' '30m'
                  hours        '1h' '2h' '4h' '6h' '8h' '12h'
                  days         '1d' '3d'
                  weeks        '1w'
                  months       '1M;
          '''
  
          if limit &gt; 1000:
              return self.GetSymbolKlinesExtra(symbol, interval, limit, end_time)
          
          params = '?&amp;symbol='+symbol+'&amp;interval='+interval+'&amp;limit='+str(limit)
          if end_time:
              params = params + '&amp;endTime=' + str(int(end_time))
  
          url = self.base + self.endpoints['klines'] + params
  
          # download data
          data = requests.get(url)
          dictionary = json.loads(data.text)
  
          # put in dataframe and clean-up
          df = pd.DataFrame.from_dict(dictionary)
          df = df.drop(range(6, 12), axis=1)
  
          # rename columns
          col_names = ['time', 'open', 'high', 'low', 'close', 'volume']
          df.columns = col_names
  
          # transform values from strings to floats
          for col in col_names:
              df[col] = df[col].astype(float)
  
          df['date'] = pd.to_datetime(df['time'] * 1000000, infer_datetime_format=True)
  
          return df
      
      def PlaceOrderFromDict(self, params, test:bool=False):
          &quot;&quot;&quot; Places order from params dict &quot;&quot;&quot;
  
          params['recvWindow'] = 5000
          params['timestamp'] = int(round(time.time()*1000)) + request_delay
          
          self.signRequest(params)
          url = ''
          if test: 
              url = self.base + self.endpoints['testOrder']
          else:
              url = self.base + self.endpoints['order']
          return self._post(url, params, self.headers)
  
      def PlaceOrder(self, symbol:str, side:str, type:str, quantity:float=0, price:float=0, test:bool=True):
          '''
          Places an order on Binance
          Parameters
          --
              symbol str:        The symbol for which to get the trading data
              side str:          The side of the order 'BUY' or 'SELL'
              type str:          The type, 'LIMIT', 'MARKET', 'STOP_LOSS'
              quantity float:    .....
  
          '''
  
          params = {
              'symbol': symbol,
              'side': side,           # BUY or SELL
              'type': type,               # MARKET, LIMIT, STOP LOSS etc
              'quoteOrderQty': quantity,
              'recvWindow': 5000,
              'timestamp': int(round(time.time()*1000)) + request_delay
          }
  
          if type != 'MARKET':
              params['timeInForce'] = 'GTC'
              params['price'] = Binance.floatToString(price)
  
          self.signRequest(params)
  
          url = ''
          if test: 
              url = self.base + self.endpoints['testOrder']
          else:
              url = self.base + self.endpoints['order']
  
          return self._post(url, params=params, headers=self.headers)
  
      def CancelOrder(self, symbol:str, orderId:str):
          '''
              Cancels the order on a symbol based on orderId
          '''
  
          params = {
              'symbol': symbol,
              'orderId' : orderId,
              'recvWindow': 5000,
              'timestamp': int(round(time.time()*1000)) + request_delay
          }
  
          self.signRequest(params)
  
          url = self.base + self.endpoints['order']
  
          try: 
              response = requests.delete(url, params=params, headers=self.headers)
              data = response.text
          except Exception as e:
              print(&quot;Exception occured when trying to cancel order on &quot;+url)
              print(e)
              data = {'code': '-1', 'msg':e}
          
          return json.loads(data)
  
      def GetOrderInfo(self, symbol:str, orderId:str):
          '''
              Gets info about an order on a symbol based on orderId
          '''
  
          params = {
              'symbol': symbol,
              'origClientOrderId' : orderId,
              'recvWindow': 5000,
              'timestamp': int(round(time.time()*1000)) + request_delay
          }
  
          self.signRequest(params)
  
          url = self.base + self.endpoints['order']
  
          return self._get(url, params=params, headers=self.headers)
  
      def GetAllOrderInfo(self, symbol:str):
          '''
              Gets info about all order on a symbol
          '''
  
          params = {
              'symbol': symbol,
              'timestamp': int(round(time.time()*1000)) + request_delay
          }
  
          self.signRequest(params)
  
          url = self.base + self.endpoints['allOrders']
  
          try: 
              response = requests.get(url, params=params, headers=self.headers)
              data = response.text
          except Exception as e:
              print(&quot;Exception occured when trying to get info on all orders on &quot;+url)
              print(e)
              data = {'code': '-1', 'msg':e}
  
          return json.loads(data)
  
      def signRequest(self, params:dict):
          ''' Signs the request to the Binance API '''
  
          query_string = '&amp;'.join([&quot;{}={}&quot;.format(d, params[d]) for d in params])
          signature = hmac.new(self.binance_keys['secret_key'].encode('utf-8'), query_string.encode('utf-8'), hashlib.sha256)
          params['signature'] = signature.hexdigest()
      
      @classmethod
      def floatToString(cls, f:float):
          ''' Converts the given float to a string,
          without resorting to the scientific notation '''
  
          ctx = decimal.Context()
          ctx.prec = 12
          d1 = ctx.create_decimal(repr(f))
          return format(d1, 'f')
  
      @classmethod
      def get10Factor(cls, num):
          &quot;&quot;&quot; Returns the number of 0s before the first non-0 digit of a number 
          (if |num| is &lt; than 1) or negative the number of digits between the first 
          integer digit and the last, (if |num| &gt;= 1) 
          
          get10Factor(0.00000164763) = 6
          get10Factor(1600623.3) = -6
          &quot;&quot;&quot;
          p = 0
          for i in range(-20, 20):
              if num == num % 10**i:
                  p = -(i - 1)
                  break
          return p
  
      @classmethod
      def RoundToValidPrice(cls, symbol_data, desired_price, round_up:bool=False) -&gt; Decimal:
          &quot;&quot;&quot; Returns the minimum quantity of a symbol we can buy,
          closest to desiredPrice &quot;&quot;&quot;
          
          pr_filter = {}
          
          for fil in symbol_data[&quot;filters&quot;]:
              if fil[&quot;filterType&quot;] == &quot;PRICE_FILTER&quot;:
                  pr_filter = fil
                  break
          
          if not pr_filter.keys().__contains__(&quot;tickSize&quot;):
              raise Exception(&quot;Couldn't find tickSize or PRICE_FILTER in symbol_data.&quot;)
              return
  
          round_off_number = int(cls.get10Factor((float(pr_filter[&quot;tickSize&quot;]))))
  
          number = round(Decimal(desired_price), round_off_number)
          if round_up:
              number = number + Decimal(pr_filter[&quot;tickSize&quot;])
  
          return number
  
      @classmethod
      def RoundToValidQuantity(cls, symbol_data, desired_quantity, round_up:bool=False) -&gt; Decimal:
          &quot;&quot;&quot; Returns the minimum quantity of a symbol we can buy,
          closest to desiredPrice &quot;&quot;&quot;
          
          lot_filter = {}
          
          for fil in symbol_data[&quot;filters&quot;]:
              if fil[&quot;filterType&quot;] == &quot;LOT_SIZE&quot;:
                  lot_filter = fil
                  break
          
          if not lot_filter.keys().__contains__(&quot;stepSize&quot;):
              raise Exception(&quot;Couldn't find stepSize or PRICE_FILTER in symbol_data.&quot;)
              return
  
          round_off_number = int(cls.get10Factor((float(lot_filter[&quot;stepSize&quot;]))))
  
          number = round(Decimal(desired_quantity), round_off_number)
          if round_up:
              number = number + Decimal(lot_filter[&quot;stepSize&quot;])
  
          return number
  
  
  def Main():
  
      symbol = 'NEOBTC'
      client_id = '73a40bae-61c7-11ea-8e67-f40f241d61b4'
      exchange = Binance('credentials.txt')
  
      d = exchange.GetOrderInfo(symbol, client_id)
      print(d)
  
  
  if __name__ == '__main__':
      Main()
  </code></pre>