def getAccountBalances(self): """Returns a list of dictionaries of the balances. Returns -1 if error. Example output: [ { "asset": "BTC", "free": "4723846.89208129", "locked": "0.00000000" }, { "asset": "LTC", "free": "4763368.68006011", "locked": "0.00000000" } ] """ rateLimitOK = self.rateLimits.update("ORDERS", 5) if rateLimitOK: ts = int((getTimeStamp() + self.timeStampOffset) * 1000) payload = {'timestamp': ts} authReq = self._prepareAuthRequest(self.URL + '/api/v3/account', payload, reqType = 'GET') s = requests.Session() r = s.send(authReq) if str(r.status_code)[0] == '4' or str(r.status_code)[0] == '5': logger.error('Return code error in getAccountBalances: ' + str(r.status_code) + ';' + str(r.content)) return -1 res = r.json() logger.debug('get account balances executed: ' + str(res)) return res['balances'] else: return -1
def placeOrder(self, symbol, side, ordType, quantity, clientOrderID, asMaker = False, price = 0, otherParams = {}): """ side - BUY or SELL ordtype - LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER quanity - required decimlar price - decimal (optional). If price = 0, order will be a market order. otherParams - optional list of additional key-value pairs to write to db (not otherwise used) """ rateLimitOK = self.rateLimits.update("ORDERS", 1) if rateLimitOK: if price == 0 and not ordType == 'MARKET': logger.error('price indicates Market order order but ordType is not market.' ) return -1 ts = int((getTimeStamp() + self.timeStampOffset) * 1000) #Apply filters to price and quantity price, quantity = self._applyFilters(price, quantity, symbol) if price == None: return -1 if price == 0: payload = {'symbol':symbol, 'side': side, 'type': ordType, 'quantity': quantity, 'timestamp': ts, 'newClientOrderId': clientOrderID} else: price = round(price, self.symbolExchInfo[symbol]['quotePrecision']) fmtStr= '{:.' + str(self.symbolExchInfo[symbol]['quotePrecision']) + 'f}' payload = {'symbol':symbol, 'side': side, 'type': ordType, 'quantity': quantity, 'timestamp': ts, 'price': fmtStr.format(price), 'timeInForce': 'GTC', 'newClientOrderId': clientOrderID} authReq = self._prepareAuthRequest(self.URL + '/api/v3/order', payload) s = requests.Session() r = s.send(authReq) if r.status_code != 200: logger.error('Return code error in placeOrder: ' + str(r.status_code) + " " + str(r.content)) return -1 res = r.json() newD = {'orderID': res['orderId'], 'exchange': 'binance', 'side': res['side'].lower(), 'amt':float(res['origQty']), 'amtFilled': float(res['executedQty']), 'amtRemaining': float(res['origQty']) - float(res['executedQty']), 'timestamp': res['transactTime']/1000, 'symbol': res['symbol'], 'clientTradeLabel': res['clientOrderId'], 'price' : float(res['price']), 'asMaker': asMaker} #add additional parameters to the dictionary for k in otherParams.keys(): if not k in newD: newD[k] = otherParams[k] return newD else: return -1
def getOpenOrders(self, symbol): """Get open orders on a symbol. Set symbol to None for all open orders. Returns -1 if an error. Example Response, a list of: { "symbol": "LTCBTC", "orderId": 1, "clientOrderId": "myOrder1", "price": "0.1", "origQty": "1.0", "executedQty": "0.0", "status": "NEW", "timeInForce": "GTC", "type": "LIMIT", "side": "BUY", "stopPrice": "0.0", "icebergQty": "0.0", "time": 1499827319559, "isWorking": trueO } """ rateLimitOK = self.rateLimits.update("ORDERS", 1) if rateLimitOK: ts = int((getTimeStamp() + self.timeStampOffset) * 1000) payload = {'timestamp': ts} if symbol: payload.update({'symbol': symbol}) authReq = self._prepareAuthRequest(self.URL + '/api/v3/openOrders', payload, reqType = 'GET') s = requests.Session() r = s.send(authReq) if str(r.status_code)[0] == '4' or str(r.status_code)[0] == '5': logger.error('Return code error in getOpenOrders: ' + str(r.status_code) + ';' + json.loads(r.content)['msg']) return -1 res = r.json() logger.debug('get open orders executed: ' + str(res)) outL = [] for d in res: newD = {'orderID': d['orderId'], 'exchange': 'binance', 'side': d['side'].lower(), 'amt': float(d['origQty']), 'amtFilled': float(d['executedQty']), 'amtRemaining': float(d['origQty']) - float(d['executedQty']), 'timestamp': d['time']/1000, 'symbol': d['symbol'], 'clientOrdID' : d['clientOrderId']} if newD['amtFilled'] < newD['amt']: outL.append(newD) return outL else: return -1
def update(self, weightType, weight): """Update the counter value of the REQUESTS or ORDERS weight. Returns False if the counter is above an acceptable limit.""" #increment counters blnOutput = True nowTS = getTimeStamp() self.lock.acquire() if weightType == 'REQUESTS': for d in self.rateLimits['REQUESTS']: #update counter and list of previous entries d['counter'] += weight d['lstOfEntries'].append((weight, nowTS)) #delete entries as appropriate deleteCount = 0 totalAdj = 0 for w, ts in d['lstOfEntries']: if nowTS - ts > d['interval']: totalAdj += w deleteCount += 1 else: break d['counter'] = d['counter'] - totalAdj del d['lstOfEntries'][:deleteCount] #delete expired entries #check if rate violation if d['counter'] >= d['limit']: blnOutput = False logger.info("Binance: Rate violation for REQUESTS type") elif weightType == 'ORDERS': for d in self.rateLimits['ORDERS']: d['counter'] += weight d['lstOfEntries'].append((weight, nowTS)) #delete entries as appropriate deleteCount = 0 totalAdj = 0 for w, ts in d['lstOfEntries']: if nowTS - ts < d['interval']: totalAdj += w deleteCount += 1 else: break d['counter'] = d['counter'] - totalAdj del d['lstOfEntries'][:deleteCount] #delete expired entries if d['counter'] >= d['limit']: blnOutput = False logger.info("Binance: Rate violation for ORDERS type") self.lock.release() return blnOutput
def getAggTrades(self, symbol, startTime = None, endTime = None): """ Get compressed, aggregate trades. Trades that fill at the time, from the same order, with the same price will have the quantity aggregated. Parameters: Name Type Mandatory Description symbol STRING YES startTime LONG NO Timestamp in ms to get aggregate trades from INCLUSIVE. endTime LONG NO Timestamp in ms to get aggregate trades until INCLUSIVE. If both startTime and endTime are sent, limit should not be sent AND the distance between startTime and endTime must be less than 24 hours. If frondId, startTime, and endTime are not sent, the most recent aggregate trades will be returned. Example Response: [ { "a": 26129, // Aggregate tradeId "p": "0.01633102", // Price "q": "4.70443515", // Quantity "f": 27781, // First tradeId "l": 27781, // Last tradeId "T": 1498793709153, // Timestamp "m": true, // Was the buyer the maker? "M": true // Was the trade the best price match? } ] """ rateLimitOK = self.rateLimits.update("ORDERS", 1) if rateLimitOK: ts = int((getTimeStamp() + self.timeStampOffset) * 1000) payload = {'timestamp': ts, 'symbol': symbol} if startTime != None: payload['startTime'] = startTime if endTime != None: payload['endTime'] = endTime authReq = self._prepareAuthRequest(self.URL + '/api/v1/aggTrades', payload, reqType = 'GET') s = requests.Session() r = s.send(authReq) if r.status_code != 200: logger.error('Return code error in getAccountBalances: ' + str(r.status_code) + ';' + str(r.content)) return -1 res = r.json() logger.debug('get aggTrade executed: ' + str(res)) return res else: return -1
def cancelOrder(self, orderID, symbol): """Returns a list of the orderIDs of the canceled orders.""" rateLimitOK = self.rateLimits.update("ORDERS", 1) if rateLimitOK: ts = int((getTimeStamp() + self.timeStampOffset) * 1000) payload = {'symbol':symbol, 'orderId': orderID, 'timestamp': ts} authReq = self._prepareAuthRequest(self.URL + '/api/v3/order', payload, reqType = 'DELETE') s = requests.Session() r = s.send(authReq) if str(r.status_code)[0] == '4' or str(r.status_code)[0] == '5': logger.debug('Return code error in cancelOrder: ' + str(r.status_code)) return -1 res = r.json() logger.info('Binance: Cancel order executed: ' + str(res)) return [res['orderId']] else: return -1
def queryOrder(self, orderId, symbol): """Check an order's status. Example response: { "symbol": "LTCBTC", "orderId": 1, "clientOrderId": "myOrder1", "price": "0.1", "origQty": "1.0", "executedQty": "0.0", "status": "NEW", "timeInForce": "GTC", "type": "LIMIT", "side": "BUY", "stopPrice": "0.0", "icebergQty": "0.0", "time": 1499827319559, "isWorking": true } """ rateLimitOK = self.rateLimits.update("ORDERS", 1) if rateLimitOK: ts = int((getTimeStamp() + self.timeStampOffset) * 1000) payload = {'symbol':symbol, 'orderId': orderId, 'timestamp': ts} authReq = self._prepareAuthRequest(self.URL + '/api/v3/order', payload, reqType = 'GET') s = requests.Session() r = s.send(authReq) if str(r.status_code)[0] == '4' or str(r.status_code)[0] == '5': logger.debug('Return code error in queryOrder: ' + str(r.status_code)) return None res = r.json() logger.info('Query order: ' + str(res)) return res else: return None
def getAllOrders(self, symbol, orderId = None): """If orderId is set, it will get orders >= that orderId. Otherwise most recent orders are returned.""" rateLimitOK = self.rateLimits.update("ORDERS", 5) if rateLimitOK: ts = int((getTimeStamp() + self.timeStampOffset) * 1000) payload = {'symbol':symbol, 'timestamp': ts} if orderId != None: payload['orderId'] = orderId authReq = self._prepareAuthRequest(self.URL + '/api/v3/allOrders', payload, reqType = 'GET') s = requests.Session() r = s.send(authReq) if r.status_code != 200: logger.error('Return code error in placeOrder: ' + str(r.status_code) + " " + str(r.content)) return -1 res = r.json() return res else: return -1
def processQuote(r): d = {'bidPrice': float(r['bidPrice']), 'bidQty': float(r['bidQty']), 'askPrice': float(r['askPrice']), 'askQty': float(r['askQty']), 'timeStamp': getTimeStamp()} return r['symbol'], d