webcerebrium / java-binance-api

Java Binance API Client

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ERROR: -1013, Filter failure: LOT_SIZE

spapapan opened this issue · comments

When I try to place an order I get this error:

com.webcerebrium.binance.api.BinanceApiException: ERROR: -1013, Filter failure: LOT_SIZE

How can I resolve this?

yes, this may happen either because it is lower than minimal order allowed

or

it can be also because you are using incorrect precision that is not allowed for this market
for example if you trade BNB, it allows you only buy/sell integer values - and when you try to set up order with more decimals - you could have same type of error.

LOT_SIZE issue can be solved by https://www.binance.com/api/v1/exchangeInfo parsing.
Is there any plan for LOT_SIZE api?

@chongjae yes, exchangeInfo endpoint will be added.

But this API wrapper tend to be pretty low level.
It doesn't "solve" this issue - this is rather a frequently asked question, and you should take care of what order you are placing on your application level. There will be still a plenty of room to place order incorrectly. Anyway you are welcome with ideas and pull requests to be reviewed

exchangeInfo() was added in todays Release 1.0.8

Example of how LOT SIZE could be retrieved, is added to the README
https://github.com/webcerebrium/java-binance-api#getting-exchange-market-information-lot-sizes

When I switch out "BNB" for other coin names, I get "no value" error for some of them

commented

exchangeInfo() was added in todays Release 1.0.8

Example of how LOT SIZE could be retrieved, is added to the README
https://github.com/webcerebrium/java-binance-api#getting-exchange-market-information-lot-sizes

Can't Binance server just omits extra decimals in requests' lot size?

This took me by surprise but the reason is that maybe you are using decimal precision with say 5 for symbols and maybe you should use 6. So be careful and note how much decimal precision you use. .. at least that was my case and it works. Another way to find out is https://www.binance.com/api/v1/exchangeInfo parsing, but a quick trick is also to use the mobile app by counting the decimals for a quick solution, but of course it is not the best, of anyways I hope this helps someone else like me. Good luck ! :D

Here, I have found and used the following code that works well in a lot of cases:

try:
                buy_your_coin()
            except BinanceAPIException as a:
                print(a)
                if a.message == 'Filter failure: LOT_SIZE':
                    decimal_place = 15
                    while decimal_place > -1:
                        try:
                            buy_your_coin()
                            break
                        except:
                            decimal_place -= 1
                            quantity = round(float(self.quantity), decimal_quantity)

but for certain coins, no float value from 15 decimal places down to 0 will solve this problem for me.

Anyone have any ideas?

Is Kraken or Bittrex a better overall option in terms of automated/api algotrading?

https://www.binance.com/api/v1/exchangeInfo for BTCUSDT returns:

...
baseAsset: "BTC",
baseAssetPrecision: 8,
quoteAsset: "USDT",
quotePrecision: 8,
quoteAssetPrecision: 8,
baseCommissionPrecision: 8,
quoteCommissionPrecision: 8,
...

I`m trying to place order with "quantity=0.00197505" (8 decimal places) and API returns:

 {'code': -1013, 'msg': 'Filter failure: LOT_SIZE'}

If I try to put "quantity=0.001975" (6 decimal places) - API works fine.

Could someone explain me what is wrong? How can I get possible decimal places before call
Thanks.

commented

@VolodymyrLavrenchuk check exchangeinfo full response:

{
    "symbol": "BTCUSDT",
    "status": "TRADING",
    "baseAsset": "BTC",
    "baseAssetPrecision": 8,
    "quoteAsset": "USDT",
    "quotePrecision": 8,
    "quoteAssetPrecision": 8,
    "baseCommissionPrecision": 8,
    "quoteCommissionPrecision": 8,
    "orderTypes": [
        "LIMIT",
        "LIMIT_MAKER",
        "MARKET",
        "STOP_LOSS_LIMIT",
        "TAKE_PROFIT_LIMIT"
    ],
    "icebergAllowed": true,
    "ocoAllowed": true,
    "quoteOrderQtyMarketAllowed": true,
    "isSpotTradingAllowed": true,
    "isMarginTradingAllowed": true,
    "filters": [
        {
            "filterType": "PRICE_FILTER",
            "minPrice": "0.01000000",
            "maxPrice": "1000000.00000000",
            "tickSize": "0.01000000"
        },
        {
            "filterType": "PERCENT_PRICE",
            "multiplierUp": "5",
            "multiplierDown": "0.2",
            "avgPriceMins": 5
        },
        {
            "filterType": "LOT_SIZE",
            "minQty": "0.00000100",
            "maxQty": "9000.00000000",
            "stepSize": "0.00000100"
        },
        {
            "filterType": "MIN_NOTIONAL",
            "minNotional": "10.00000000",
            "applyToMarket": true,
            "avgPriceMins": 5
        },
        {
            "filterType": "ICEBERG_PARTS",
            "limit": 10
        },
        {
            "filterType": "MARKET_LOT_SIZE",
            "minQty": "0.00000000",
            "maxQty": "84.18997572",
            "stepSize": "0.00000000"
        },
        {
            "filterType": "MAX_NUM_ORDERS",
            "maxNumOrders": 200
        },
        {
            "filterType": "MAX_NUM_ALGO_ORDERS",
            "maxNumAlgoOrders": 5
        }
    ],
    "permissions": [
        "SPOT",
        "MARGIN"
    ]
}

LOT_SIZE is defined as a filter:

{
    "filterType": "LOT_SIZE",
    "minQty": "0.00000100",
    "maxQty": "9000.00000000",
    "stepSize": "0.00000100"
}

Your quantity 0.00197505 does not fill in stepSize limited to 0.000001.

I just came across this problem myself. I am a noob at python and and coding in general , most of the code I keep seeing as a solution for this seems overly complicated but I figured it out on my side atleast.

def check_decimals():
    info = client.get_symbol_info(symbol_name)
    val = info['filters'][2]['stepSize']
    decimal = 0
    is_dec = False
    for c in val:
        if is_dec is True:
            decimal += 1
        if c == '1':
            break
        if c == '.':
            is_dec = True
    return decimal

then when placing an order, for quantity just go, for ex: "round(11.0/current_price, decimal)"

https://www.binance.com/api/v1/exchangeInfo for BTCUSDT returns:

...
baseAsset: "BTC",
baseAssetPrecision: 8,
quoteAsset: "USDT",
quotePrecision: 8,
quoteAssetPrecision: 8,
baseCommissionPrecision: 8,
quoteCommissionPrecision: 8,
...

I`m trying to place order with "quantity=0.00197505" (8 decimal places) and API returns:

 {'code': -1013, 'msg': 'Filter failure: LOT_SIZE'}

If I try to put "quantity=0.001975" (6 decimal places) - API works fine.

Could someone explain me what is wrong? How can I get possible decimal places before call
Thanks.

hey i am facing the same issue. could you please tell me how to solve this error?

Here, I have found and used the following code that works well in a lot of cases:

try:
                buy_your_coin()
            except BinanceAPIException as a:
                print(a)
                if a.message == 'Filter failure: LOT_SIZE':
                    decimal_place = 15
                    while decimal_place > -1:
                        try:
                            buy_your_coin()
                            break
                        except:
                            decimal_place -= 1
                            quantity = round(float(self.quantity), decimal_quantity)

but for certain coins, no float value from 15 decimal places down to 0 will solve this problem for me.

Anyone have any ideas?

Is Kraken or Bittrex a better overall option in terms of automated/api algotrading?

this code part working prettily but you have to be know some times give 0.0 quantity value.

Hello I think that the best solution use the Binance Online information thought: https://www.binance.com/api/v1/exchangeInfo
Using Python you can fill one dataframe with this result adding the filter information: "filterType":"LOT_SIZE" taken the value of "stepSize"
My DF looks this way:
df_exchangeInfo
symbol baseAssetPrecision stepSize
0 BTCUSDT 8 0.00001000
1 ETHUSDT 8 0.00010000
2 BNBUSDT 8 0.00100000

and I created the following function to limit the stepsize per token

def stepsize_limit(value,symbol):
	# Find the stepsize to symbol gived in df_exchangeInfo
	stepsize = df_exchangeInfo['stepSize'].loc[df_exchangeInfo['symbol'] == symbol]
	stepsize = stepsize.iloc[0]
	if '1.' in stepsize:
		# Only whole accepted truncate to zero decimals 
		return truncate(value,0)
	else:
		# Ony decimals value:
		stepsize = stepsize.replace('0.','')
		# finding 1 position:
		posc_1 = stepsize.find('1') + 1 
		# precision = len(stepsize)
		return truncate(value,posc_1)

The function Truncate is the next:

def truncate(f, n):
	'''Truncates/pads a float f to n decimal places without rounding'''
	s = '{}'.format(f)
	if 'e' in s or 'E' in s:
		str_value = '{0:.{1}f}'.format(f, n)
		return float(str_value)#'{0:.{1}f}'.format(f, n)
	i, p, d = s.partition('.')
	str_value ='.'.join([i, (d+'0'*n)[:n]])
	return float(str_value)

I noticed that there were several tokens with stepsize to only whole value, You will careful with that.
This function work with any token and always is updated because I refresh df_exchangeInfo in my program.

@VolodymyrLavrenchuk check exchangeinfo full response:

{
    "symbol": "BTCUSDT",
    "status": "TRADING",
    "baseAsset": "BTC",
    "baseAssetPrecision": 8,
    "quoteAsset": "USDT",
    "quotePrecision": 8,
    "quoteAssetPrecision": 8,
    "baseCommissionPrecision": 8,
    "quoteCommissionPrecision": 8,
    "orderTypes": [
        "LIMIT",
        "LIMIT_MAKER",
        "MARKET",
        "STOP_LOSS_LIMIT",
        "TAKE_PROFIT_LIMIT"
    ],
    "icebergAllowed": true,
    "ocoAllowed": true,
    "quoteOrderQtyMarketAllowed": true,
    "isSpotTradingAllowed": true,
    "isMarginTradingAllowed": true,
    "filters": [
        {
            "filterType": "PRICE_FILTER",
            "minPrice": "0.01000000",
            "maxPrice": "1000000.00000000",
            "tickSize": "0.01000000"
        },
        {
            "filterType": "PERCENT_PRICE",
            "multiplierUp": "5",
            "multiplierDown": "0.2",
            "avgPriceMins": 5
        },
        {
            "filterType": "LOT_SIZE",
            "minQty": "0.00000100",
            "maxQty": "9000.00000000",
            "stepSize": "0.00000100"
        },
        {
            "filterType": "MIN_NOTIONAL",
            "minNotional": "10.00000000",
            "applyToMarket": true,
            "avgPriceMins": 5
        },
        {
            "filterType": "ICEBERG_PARTS",
            "limit": 10
        },
        {
            "filterType": "MARKET_LOT_SIZE",
            "minQty": "0.00000000",
            "maxQty": "84.18997572",
            "stepSize": "0.00000000"
        },
        {
            "filterType": "MAX_NUM_ORDERS",
            "maxNumOrders": 200
        },
        {
            "filterType": "MAX_NUM_ALGO_ORDERS",
            "maxNumAlgoOrders": 5
        }
    ],
    "permissions": [
        "SPOT",
        "MARGIN"
    ]
}

LOT_SIZE is defined as a filter:

{
    "filterType": "LOT_SIZE",
    "minQty": "0.00000100",
    "maxQty": "9000.00000000",
    "stepSize": "0.00000100"
}

Your quantity 0.00197505 does not fill in stepSize limited to 0.000001.

The solution for this is simple, using this quoted answer as an example for this context.

Imagine the quantity as a progress bar and the stepSize the way you walk through the progress bar in order to fill it in.

You need to divide the quantity by the stepSize:

0.00197505 / 0.00000100 = 1.975,05

If the division gives a remainder of zero e.g. if ((quantity % stepSize) == 0) so it means it fits the stepSize otherwise as in this case, you need to get the result and cast it to an integer which gives 1.975 or round it up according to your business logic and multiply the stepSize by the casted/rounded integer result = 0.00000100 * 1.975 = 0.001975, so now it fills in stepSize.

You don't have to worry about the previous workarounds which truncate stuff and is too much work for a simple solution like this.

LOT SIZE give you the amount of decimals you should set.
For instance:
if you have:

{
    "filterType": "LOT_SIZE",
    "minQty": "0.00100000",
    "maxQty": "9000.00000000",
    "stepSize": "0.00000100"
}

that means that if you have 0.0011 it will fail, you can only send in this case 3 decimals.
That worked for me!