Python-binance: Filter failure: LOT_SIZE

Created on 19 Mar 2018  路  20Comments  路  Source: sammchardy/python-binance

I cannot get the API to properly make a buy order. My current process is to first get my current USDT total, multiply it by 0.9995 to compensate for the 0.050% fee and then take that USDT total and put it into the "quantity=[amount]". When I do this, I get:

binance.exceptions.BinanceAPIException: APIError(code=-1013): Filter failure: LOT_SIZE

How can I overcome this?

balance = client.get_asset_balance(asset='USDT')
print(balance['free'])
quantity = (float(balance['free']))*0.9995
print(quantity)
order = client.order_market_buy(symbol='BTCUSDT', quantity=(float(quantity)))
orders = client.get_open_orders(symbol='BTCUSDT')
print(orders)

Most helpful comment

I've found a fix after reading a lot of different stuff. Essentially what I had to do was round off the number that came from dividing my current USDT totals into the current BTC price to 6 decimals only. The number I was getting had 18 decimal points.

Here is the code I used to get what I needed, I was close earlier, but did not realize I had to limit the decimal points.

balance = client.get_asset_balance(asset='USDT')
trades = client.get_recent_trades(symbol='BTCUSDT')
quantity = (float(balance['free']))/float(trades[0]['price'])*0.9995
order = client.order_market_buy(symbol='BTCUSDT', quantity=(round(quantity, 6)))

All 20 comments

I'd also like to point out that in the BTCUSDT market that all transactions are done in BTC. Meaning when you buy BTC, you don't input the amount of USDT you have, you need to put in the BTC equivalent.

So if you have 100 USDT, that is around 0.01 BTC right now. When I did a test order, and divided my amount of USDT by BTC current price, and then put that number as the 'quantity', it worked. 50 USDT / 8350 (current USD price of BTC).

Here is the line I came up with to try and compensate for this, but it still does not work, and I still get a LOT_SIZE filter error.

balance = client.get_asset_balance(asset='USDT')
trades = client.get_recent_trades(symbol='BTCUSDT')
quantity = (float(balance['free']))/(float(trades[0]['price']))*0.9995
price = (float(trades[0]['price']))
order = client.order_limit_buy(symbol='BTCUSDT', quantity=quantity, price=price)
orders = client.get_open_orders(symbol='BTCUSDT')

I've found a fix after reading a lot of different stuff. Essentially what I had to do was round off the number that came from dividing my current USDT totals into the current BTC price to 6 decimals only. The number I was getting had 18 decimal points.

Here is the code I used to get what I needed, I was close earlier, but did not realize I had to limit the decimal points.

balance = client.get_asset_balance(asset='USDT')
trades = client.get_recent_trades(symbol='BTCUSDT')
quantity = (float(balance['free']))/float(trades[0]['price'])*0.9995
order = client.order_market_buy(symbol='BTCUSDT', quantity=(round(quantity, 6)))

Thanks for sharing, this is helpful.

Instead of rounding to hard-coded 6 digits, you can find actual precision using this API (it can be different for different tokens): https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#lot_size (stepSize). To convert stepSize to the precision, I use this:
precision = int(round(-math.log(stepSize, 10), 0)), and then do round(quantity, precision).

thank you so much! @goldan @cc345
sym_info = self._client.get_symbol_info('BATBNB')
filters = sym_info['filters']
for f in filters:
print("filter~~~~ " + str(f))
if f['filterType'] == 'LOT_SIZE':
self._step_size = float(f['stepSize'])
break

def quan(self):
    bal = self._client.get_asset_balance(asset='BNB')
    quantity = (float(bal['free']))/self._price*0.9995
    precision = int(round(-math.log(self._step_size, 10), 0))
    quantity = float(round(quantity, precision))
    return quantity

Why do we have to /self._price*0.9995 on all coins

Why do we have to /self._price*0.9995 on all coins

It's to compensate the 0.050% transaction fee

thank you so much! @goldan @cc345
sym_info = self._client.get_symbol_info('BATBNB')
filters = sym_info['filters']
for f in filters:
print("filter~~~~ " + str(f))
if f['filterType'] == 'LOT_SIZE':
self._step_size = float(f['stepSize'])
break

def quan(self):
    bal = self._client.get_asset_balance(asset='BNB')
    quantity = (float(bal['free']))/self._price*0.9995
    precision = int(round(-math.log(self._step_size, 10), 0))
    quantity = float(round(quantity, precision))
    return quantity

thank you very much! really useful :)
We can improve it a little more: instead of hard coding 0.9995 as fee, this can be taken dynamically with API and then turn into % with:
(100 - symbol_fee) / 100

Why API do NOT automatically round the order?
Why do we need to make it via extra code?
Any meaningful reason?

Why API do NOT automatically round the order?
Why do we need to make it via extra code?
Any meaningful reason?

I think it used to serve highly precision data, and because not everybody has to use this rounded quantity.

Instead of rounding to hard-coded 6 digits, you can find actual precision using this API (it can be different for different tokens): https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#lot_size (stepSize). To convert stepSize to the precision, I use this:
precision = int(round(-math.log(stepSize, 10), 0)), and then do round(quantity, precision).

how do u find the stepsize .can u please share the stepsize code in python.THANKS

Instead of rounding to hard-coded 6 digits, you can find actual precision using this API (it can be different for different tokens): https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#lot_size (stepSize). To convert stepSize to the precision, I use this:
precision = int(round(-math.log(stepSize, 10), 0)), and then do round(quantity, precision).

how do u find the stepsize .can u please share the stepsize code in python.THANKS

https://python-binance.readthedocs.io/en/latest/binance.html#binance.client.Client.get_symbol_info

This method is valid for the Spot wallet and for the Margin Wallet, while for the Futures Wallet things change a bit ..

This is what I have been using (I'm horrible at Python), but it seems to work:
for filters:

       ```

sym_info = self._client.get_symbol_info(self._pair)

        filters = sym_info['filters']
        self._min_notional = filters
        for f in filters:
            print("filter~~~~~~~~~~~~ " + str(f))
            if f['filterType'] == 'LOT_SIZE': 
                self._step_size = float(f['stepSize'])
                self._precision_quan = int(round(-math.log(self._step_size, 10), 0))
                print("F precision_quan: " + str(self._precision_quan))
...........
`self.val_to_str(self.quantity_token_I_can_buy(p), self._precision_quan)`
'''''''''''
def does_MIN_NOTIONAL_pass(self, quantity, price):
    print ("in MIN notional " + str(quantity) + " " + str(price) + " " + str(self._min_notional) )
    return (float(quantity) * float(price)) >= float(self._min_notional)
Also, I've notice that Python is doing some funny things when converting long decimals to strings (losing precision, not truncating without rounding up, scientific notation), so I wrote my own function. I'll be happy to hear from you, if you have a more elegant way of doing it:
#
def val_to_str(self, val, precision=14):
    if (precision == None):
        print("!!! precision is None, setting to 14")
        precision = 14
    if(val == None) : return None
    print("val_to_str value:")
    print(val)
    if(precision < 0):
        print("val_to_str output:")
        print(None)
        return None
    string = ""
    if(val < 0): 
        string += "-"
        val *= -1
    whole = float(val) - float(val) % float(1.0)
    print("whole: " + str(whole))
    decimal = val - whole
    print("decimal: " + str(decimal))
    if(whole == 0.0 and decimal == 0.0):
        print("val_to_str output:")
        print("0")
        return "0"
    string += str(int(whole)) +"."
    for i in range (1, precision+1):
        w = int(decimal * 10)
        decimal = decimal * 10.0 - w
        string += str(int(w))

    string = string.rstrip("0").rstrip(".")
    print("val_to_str output:")
    print(string)
    return string
#

```

You can also take an example from my repo, see among the methods. In a few days I publish a new version with Futures.
https://github.com/nedludd0/binance-exchange-python-api

This is what I have been using (I'm horrible at Python), but it seems to work:
for filters:

       ```

sym_info = self._client.get_symbol_info(self._pair)

        filters = sym_info['filters']
        self._min_notional = filters
        for f in filters:
            print("filter~~~~~~~~~~~~ " + str(f))
            if f['filterType'] == 'LOT_SIZE': 
                self._step_size = float(f['stepSize'])
                self._precision_quan = int(round(-math.log(self._step_size, 10), 0))
                print("F precision_quan: " + str(self._precision_quan))
...........
`self.val_to_str(self.quantity_token_I_can_buy(p), self._precision_quan)`
'''''''''''
def does_MIN_NOTIONAL_pass(self, quantity, price):
    print ("in MIN notional " + str(quantity) + " " + str(price) + " " + str(self._min_notional) )
    return (float(quantity) * float(price)) >= float(self._min_notional)
Also, I've notice that Python is doing some funny things when converting long decimals to strings (losing precision, not truncating without rounding up, scientific notation), so I wrote my own function. I'll be happy to hear from you, if you have a more elegant way of doing it:
#
def val_to_str(self, val, precision=14):
    if (precision == None):
        print("!!! precision is None, setting to 14")
        precision = 14
    if(val == None) : return None
    print("val_to_str value:")
    print(val)
    if(precision < 0):
        print("val_to_str output:")
        print(None)
        return None
    string = ""
    if(val < 0): 
        string += "-"
        val *= -1
    whole = float(val) - float(val) % float(1.0)
    print("whole: " + str(whole))
    decimal = val - whole
    print("decimal: " + str(decimal))
    if(whole == 0.0 and decimal == 0.0):
        print("val_to_str output:")
        print("0")
        return "0"
    string += str(int(whole)) +"."
    for i in range (1, precision+1):
        w = int(decimal * 10)
        decimal = decimal * 10.0 - w
        string += str(int(w))

    string = string.rstrip("0").rstrip(".")
    print("val_to_str output:")
    print(string)
    return string
#

Use Decimal instead of float which is more accurate, imho

from binance.exceptions import *

to import Exception of python-binance

try:
    SELL_YOUR_COIN(coin,amount)
except BinanceAPIException as a:
    if a.message == 'Filter failure: LOT_SIZE':
        na = 3
        while True:
            try:
                SELL_YOUR_COIN(coin,amount)
                break
            except:
                na -= 1
                amount = round(float(amount), na)

Guys, can you help me out?

I am trying to make a market BUY order using 'quoteOrderQty' instead of 'quantity'. Most time I am getting the error related to 'LOT_SIZE' filter.

Reference code:

qty = self.round_quantity()

        order = client.order_market_buy(
            symbol=self.trade_pair,
            quantity=qty
        )

def round_quantity(self, quantity: float) -> Decimal:
        fee = Decimal(0.9995)
        getcontext().rounding = ROUND_DOWN
        qty = Decimal(quantity)
        min_qty, max_qty, step_size = Account.get_lot_size_info(pair=self.trade_pair)
        precision = int(round(-math.log(Decimal(step_size), 10), 0))
        rounded = Decimal(round(qty, precision))
        return rounded

from binance.exceptions import *

to import Exception of python-binance

try:
    SELL_YOUR_COIN(coin,amount)
except BinanceAPIException as a:
    if a.message == 'Filter failure: LOT_SIZE':
        na = 3
        while True:
            try:
                SELL_YOUR_COIN(coin,amount)
                break
            except:
                na -= 1
                amount = round(float(amount), na)

this is a really efficient solution to the problem

from binance.exceptions import *
to import Exception of python-binance

try:
    SELL_YOUR_COIN(coin,amount)
except BinanceAPIException as a:
    if a.message == 'Filter failure: LOT_SIZE':
        na = 3
        while True:
            try:
                SELL_YOUR_COIN(coin,amount)
                break
            except:
                na -= 1
                amount = round(float(amount), na)

this is a really efficient solution to the problem

though this doesn't always work i've found. Decimal places can be a pretty high number. Overall, this still works well for me because I can find the right stepSize (starting higher than 3) without having to go all the way out to get the exchange info and dig thru the response for each individual coin, but every once in a while I will stumble on a coin that will not accept any decimal place float quantity that I give it. anyone know why?

Hi,
I think the following code will solve your problem

info = client.get_symbol_info(symbol=pair)
f = [i["stepSize"] for i in info["filters"] if i["filterType"] == "LOT_SIZE"][0]
qty = round(qty, f.index("1") - 1)

Was this page helpful?
0 / 5 - 0 ratings