Nassim
Nassim

Reputation: 171

python-Binance api: APIError(code=-1013): Filter failure: LOT_SIZE

When trying to place a buy or sell order with the python-binance API I got the following error:

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

Now I've seen at iceberg_parts that this means there is probably something wrong with my buying or selling quantity. I've tried to increase the quantity by a factor 10 but this only gives me another related error:

APIError(code=-1013): Filter failure: MIN_NOTIONAL.

Here's some of my code:

diff = current_price - prev_price
if diff <= 0.0001:
    order = client.order_market_buy(symbol = market , quantity = '0.0001')
    print('buy order')
        
if diff >= 0.00040:
    order = client.order_market_sell(symbol =market, quantity ='0.0001')
    print('sell order')

Do you know how to fix this?

Upvotes: 17

Views: 55822

Answers (13)

Don Coder
Don Coder

Reputation: 556

This is not about MARKET_LOT_SIZE. This is MIN_NOTIONAL. Let's say ETHUSDT's minQty (under MARKET_LOT_SIZE filter) is 0.001 but you can still not place an order as notional (under MIN_NOTIONAL filter) is 20. Your order value must be above 20 (MIN_NOTIONAL) and your qty must over 0.001 (minQty). You want to grab these filters via exchangeInfo

Check out docs

Upvotes: 0

Stack
Stack

Reputation: 1129

This error appears because you are trying to create an order with a quantity lower than the minimun required.

You can access the minimun required of a specific pair with:

info = client.get_symbol_info('ETHUSDT')
print(info)

Output a dictionary with information about that pair. Now you can access the minimun quantity required with:

print(info['filters'][2]['minQty'])
# 0.00001

Upvotes: 20

Binance
Binance

Reputation: 192

Maybe this can explain why the server returns this error.

Filters

From the endpoint GET /api/v3/exchangeInfo, you can find all details regarding the trading symbols. It includes many filters that clients need to follow to place an order. For example, the BTCUSDT has the filters as of today(2022-08-31)

"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.00001000",
        "maxQty": "9000.00000000",
        "stepSize": "0.00001000"
    },
    {
        "filterType": "MIN_NOTIONAL",
        "minNotional": "10.00000000",
        "applyToMarket": true,
        "avgPriceMins": 5
    },
    {
        "filterType": "ICEBERG_PARTS",
        "limit": 10
    },
    {
        "filterType": "MARKET_LOT_SIZE",
        "minQty": "0.00000000",
        "maxQty": "282.39806510",
        "stepSize": "0.00000000"
    },
    {
        "filterType": "TRAILING_DELTA",
        "minTrailingAboveDelta": 10,
        "maxTrailingAboveDelta": 2000,
        "minTrailingBelowDelta": 10,
        "maxTrailingBelowDelta": 2000
    },
    {
        "filterType": "MAX_NUM_ORDERS",
        "maxNumOrders": 200
    },
    {
        "filterType": "MAX_NUM_ALGO_ORDERS",
        "maxNumAlgoOrders": 5
    }
]

LOT_SIZE validation

minQty

If you place an order on this BTCUSDT with parameters:

price=19000
side=BUY
type=LIMIT
quantity=0.000005

that is a LIMIT BUY order with price of $19,000, but the quantity is less than minQty in the LOT_SIZE:

0.000005 < 0.00001000

then the server will reject the order, because the request can't pass this filter validation.


LOT_SIZE.minQty

stepSize

Can I place an order with the same parameters but only change the quantity to 0.000015? That is:

price=19000
side=BUY
type=LIMIT
quantity=0.000015

You will still receive this error, because the quantity is not able to pass the stepSize size validation: (quantity- minQty) % stepSize == 0

(0.000015 - 0.00001) % 0.00001 != 0


LOT_SIZE.minQty
LOT_SIZE.stepSize

MIN_NOTIONAL Validation

Alright, let us change the quantity to 0.00002, with same parameters:

price=19000
side=BUY
type=LIMIT
quantity=0.00002

The order will still be rejected with a different error because it can't pass the filter MIN_NOTIONAL validation.

19000 x 0.00002 = 0.38 < 10 (MIN_NOTIONAL.minNotional)

Note:

  • minNotional defines the minimum notional value that required for each order.
  • For MARKET order, the average price is used over the last avgPriceMins minutes.

LOT_SIZE.minQty
LOT_SIZE.stepSize
MIN_NOTIONAL.minNotional

Upvotes: 6

Shujaath Khan
Shujaath Khan

Reputation: 1384

Hi adding a bit further to @stack if I've 20 dollars to buy then my quantity would be as below

I've done like below

    decimal_places=abs(Decimal(symbl_info['filters'][2]["stepSize"]).normalize().as_tuple().exponent)
print("DECIMAL PLACES {0}".format(decimal_places))
buy_qauntity= round((20/order_input["askPrice"].values[0]),decimal_places)
print(buy_qauntity)

Upvotes: 0

Handro
Handro

Reputation: 9

I have read through all of these forum questions and no one has mentioned the fact that Binance charges a 0.1% fee on all transactions. Meaning you do not have your original buying quantity available to sell back when the sell is triggered.

I have attempted to solve this with:

buy_quantity = round(buy_amount * 0.999, len(str(lotsize).split('.')[1]))

Multiplying my original purchase quantity by 0.999 should reduce it by the amount needed to be able to sell it back.

Upvotes: 1

ndiecodes
ndiecodes

Reputation: 11

Here's a very helpful code using binance-python package

  ...
  // Full code: https://github.com/ndiecodes/binance-trading-bot/blob/main/main.py

  def get_round_step_quantity(self, qty):
    info = self.client.get_symbol_info(Config.TRADESYMBOL)
    for x in info["filters"]:
        if x["filterType"] == "LOT_SIZE":
            self.minQty = float(x["minQty"])
            self.maxQty = float(x["maxQty"])
            self.stepSize= float(x["stepSize"])
    if qty < self.minQty:
        qty = self.minQty
    return round_step_size(quantity=qty, step_size=self.stepSize)

Upvotes: 0

Reinis Gaņģis
Reinis Gaņģis

Reputation: 41

So I was struggling with the LOT_SIZE error myself.

Previously I was using the round_step_size function from the python-binance library, however, I had to edit this function to deal with this API error.

Here is a function that I use:

from decimal import Decimal, ROUND_DOWN
import math
from typing import Union

def round_step_size(quantity: Union[float, Decimal], step_size: Union[float, Decimal]) -> float:
    if step_size == 1.0:
        return math.floor(quantity)
    elif step_size < 1.0:
        return Decimal(f'{quantity}').quantize(Decimal(f'{step_size}'), rounding=ROUND_DOWN)

Upvotes: -1

amijaljevic
amijaljevic

Reputation: 19

https://python-binance.readthedocs.io/en/latest/account.html

from binance.helpers import round_step_size

# to get a lot size
def getLotSize(self):
    info = self.apiCall(lambda: self.client.get_symbol_info(self.pair))
    lotSize = float(info['filters'][2]['minQty'])
    return lotSize


# get ceiling value and correct format for a lot size
def getCeilingVal(self):
    pairData = self.apiCall(lambda: 
    self.client.get_symbol_ticker(symbol=self.pair))
    pairPrice = pairData["price"]
    ceilingVal = float(self.dInv) / float(pairPrice)

    aLotSize = self.getLotSize()
    rounded_amount = round_step_size(ceilingVal, aLotSize)

    return rounded_amount

Upvotes: 0

Vladimir Filin
Vladimir Filin

Reputation: 123

We can use the Log10 function to get rounding precision from the Binance /api/v3/exchangeinfo endpoint data.

CurrencyRoundNum = int(math.Abs(math.Log10(stepSize)))
PriceRoundNum = int(math.Abs(math.Log10(tickSize)))

The full version on golang is here, or at go playground. I'm sorry that code is not on python.

Upvotes: -1

Yugenswitch
Yugenswitch

Reputation: 185

I've just gone through this same problem. As a noob, some of the code in these answers seem quite complicated so I came up with a solution.

Code:

def check_decimals(symbol):
    info = client.get_symbol_info(symbol)
    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 you place the order, just do for ex: (make sure qty is a float or decimal)

  B_order = round(qty / symbol_price, decimal)
  order = client.order_market_buy(
            symbol=symbol_name,
            quantity=B_order)

Upvotes: 5

abdulsamed kayaduman
abdulsamed kayaduman

Reputation: 602

I write a function like that. It's working for me.

def getPriceLotFormat(self, priceOrg, quantityOrg):
    price = float(priceOrg)
    quantity = float(quantityOrg)
    response = self.get_symbol_info(car.pair) #self is client btw
    priceFilterFloat = format(float(response["filters"][0]["tickSize"]), '.20f')
    lotSizeFloat = format(float(response["filters"][2]["stepSize"]), '.20f')
    # PriceFilter
    numberAfterDot = str(priceFilterFloat.split(".")[1])
    indexOfOne = numberAfterDot.find("1")
    if indexOfOne == -1:
        price = int(price)
    else:
        price = round(float(price), int(indexOfOne - 1))
    # LotSize
    numberAfterDotLot = str(lotSizeFloat.split(".")[1])
    indexOfOneLot = numberAfterDotLot.find("1")
    if indexOfOneLot == -1:
        quantity = int(quantity)
    else:
        quantity = round(float(quantity), int(indexOfOneLot))
    print(f"""
    ##### SELL #####
    Pair : {str(car.pair)}
    Cash : {str(car.price)}
    Quantity : {str(car.quantity)}
    Price : {str(car.price)}
        """)

Upvotes: -1

jrm
jrm

Reputation: 609

Here is some code.

def round_down(self, coin, number):
    info = self.client.get_symbol_info('%sUSDT' % coin)
    step_size = [float(_['stepSize']) for _ in info['filters'] if _['filterType'] == 'LOT_SIZE'][0]
    step_size = '%.8f' % step_size
    step_size = step_size.rstrip('0')
    decimals = len(step_size.split('.')[1])
    return math.floor(number * 10 ** decimals) / 10 ** decimals

Upvotes: 1

Carlo A. Fernandez B.
Carlo A. Fernandez B.

Reputation: 149

The buying or selling quantity has to be >= 10.3 USD or 10.3/price, pass the quantity and price to these decimal settings/filters with the amounts set with decimal

from decimal import Decimal as D, ROUND_DOWN, ROUND_UP
import decimal

info = client.get_symbol_info(symbol=pair)
price_filter = float(info['filters'][0]['tickSize'])
ticker = client.get_symbol_ticker(symbol=pair)
price = float(ticker['price'])
price = D.from_float(price).quantize(D(str(price_filter)))
minimum = float(info['filters'][2]['minQty']) # 'minQty'
quant = D.from_float(quantity).quantize(D(str(minimum))) # if quantity >= 10.3/price

Upvotes: 4

Related Questions