sammchardy / python-binance

Binance Exchange API python implementation for automated trading
https://python-binance.readthedocs.io/en/latest/
MIT License
5.97k stars 2.19k forks source link

APIError(code=-1111): Precision is over the maximum defined for this asset #296

Closed mark-antony1 closed 2 years ago

mark-antony1 commented 6 years ago

There is an issue placing orders on binance for xmr/btc

The ticker information is as follows for the pair. {'symbol': 'XMRBTC', 'status': 'TRADING', 'baseAsset': 'XMR', 'baseAssetPrecision': 8, 'quoteAsset': 'BTC', 'quotePrecision': 8, 'orderTypes': ['LIMIT', 'LIMIT_MAKER', 'MARKET', 'STOP_LOSS_LIMIT', 'TAKE_PROFIT_LIMIT'], 'icebergAllowed': False, 'filters': [{'filterType': 'PRICE_FILTER', 'minPrice': '0.00000100', 'maxPrice': '100000.00000000', 'tickSize': '0.00000100'}, {'filterType': 'LOT_SIZE', 'minQty': '0.00100000', 'maxQty': '10000000.00000000', 'stepSize': '0.00100000'}, {'filterType': 'MIN_NOTIONAL', 'minNotional': '0.00100000'}]}

However, If i were to submit a buy where the quantity submitted is precise to 8 decimals, i.e. 0.44500000 It will return with the error binance.exceptions.BinanceAPIException: APIError(code=-1111): Precision is over the maximum defined for this asset.

What is the issue here?

CJ1976 commented 5 years ago

https://github.com/sammchardy/python-binance/issues/57

tnpxu commented 4 years ago

Did u guys solve this ? I got this error too.

Podzied commented 3 years ago

Use the round function and round your quantity or price to the precision needed like:

quantity = float(round(quantity, precision))

Abdulrahmantommy commented 3 years ago

best fix is quantity = float(round(quantity, 6))

avatar-lavventura commented 3 years ago
decimal_count = 4
quantity = f"{float(value):.{decimal_count}f}"
ArthurDetaille commented 3 years ago

All of this is not working for me with quantity=round(self.quantity, self.precisions[self.coinName]) where, you guessed it, precisions is a dict of all needed precisions for each coin. This is still throwing an error.

I tried transforming it to string : same error. substracting random numbers from precision (1, 2, 3, ...) : same error. manually trying in a loop all possible precisions from 1 to 1000 : same error. Transforming it to DECIMAL : same error.

Help me please, I might cut my veins soon

avatar-lavventura commented 3 years ago

@ArthurDetaille Try this:

 _entryPrice = _entryPrice.rstrip("0").rstrip(".") if "." in _entryPrice else _entryPrice
decimal_count = len(str(_entryPrice).split(".")[1])
try:
    self.order_limit(symbol, _amount, _side, _entryPrice, decimal_count)
except:
    self.order_limit(symbol, _amount, _side, _entryPrice, decimal_count - 1)  # here you are attempting with 1 lower decimal value
ArthurDetaille commented 3 years ago

I'm afraid it's not working either :(

ArthurDetaille commented 3 years ago

Allright, add me on discord 'Ærth uur#0767'

ArthurDetaille commented 3 years ago

Maybe you could give you yours ? (thank again for your time)

dvdieu commented 3 years ago

API exchangeInfo https://api.binance.com/api/v3/exchangeInfo https://fapi.binance.com/fapi/v1/exchangeInfo

GeorgKantsedal commented 3 years ago

I solve in this way: price = float(open_inf['entryPrice']) round_len = len(str(price).rsplit('.', 1)[-1]) (use round_len for your purposes, price - any that you get from binance)

teranoib commented 3 years ago
tradingPairs = ['BTCUSDT','ETHUSDT','BNBUSDT']

#Loop though cryptos

for i in range(0,len(tradingPairs)):

info = client.futures_exchange_info()

if info['symbols'][0]['pair'] == tradingPairs[i]:

print("Price Pre ",info['symbols'][0]['pricePrecision'])

pricePrecision = info['symbols'][0]['pricePrecision']
quantityS = 5.2
quantityB = "{:0.0{}f}".format(quantityS, pricePrecision)
PabloBorda commented 3 years ago

This is so frustrating I have been for a few days dealing with this, if not this error then other filter errors, isn't there any API to get to the closest feasible number that the exchange will accept?

And what about other exchanges? How do they manage this problem?


  def normalize_number(self,my_float_number):
        amount_int = int(float(my_float_number) / float(self.symbol.get_step_size()))
        quote_step_size = float(self.symbol.get_step_size())
        amount = 0
        quote_asset_precision = self.symbol.get_base_asset_precision()
        for i in range(0,amount_int):    
            amount = amount + quote_step_size
        return "{:0.0{}f}".format(amount, quote_asset_precision)
  def val(self):
        min_qty_i_can_buy = self.symbol.min_quantity_i_can_buy()
        max_qty_i_can_buy = self.symbol.max_quantity_i_can_buy()
        if float(self.get_base_float()) <= max_qty_i_can_buy:
            if float(self.get_base_float()) > min_qty_i_can_buy:

                exchange_format_value = self.normalize_number(float(self.get_base_float()))
                return float(exchange_format_value)
                #return float(round(float(exchange_format_value),self.symbol.get_base_asset_precision()))

            else:
                exchange_format_value = self.normalize_number(float(self.symbol.min_quantity_i_can_buy()))
                return exchange_format_value

And then I do:


        float_amount = self.amount.val()
        exchange.futures_create_order(symbol=symbol.uppercase_format(), side='BUY', type='MARKET', quantity=float_amount)
teranoib commented 3 years ago

For Futures i used this and it worked very well url = "https://api.binance.com/api/v3/exchangeInfo?symbol="+symbol info_data = requests.get(url).json() pricePrecision = info_data['symbols'][0]['baseAssetPrecision'] minQty = info_data['symbols'][0]['filters'][2]['minQty'] qtyTrueQ = info_data['symbols'][0]['filters'][1]['avgPriceMins'] quantityS = float(qtyTrueQ) quantityB = D.from_float(quantityS).quantize(D(str(pricePrecision)))

sevivq commented 2 years ago

None of the answers you have given have helped me.

I have a variable with the available quantity on futures (av_quantity). And I want that when I create the order quantity = av_quantity and it gives me the "APIError (code = -1111): Precision is over the maximum defined for this asset".

Any suggestion?

lr2bmail commented 2 years ago
    def round_down( client, quantity, symbol):
        info = client.get_symbol_info(symbol)
        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(quantity * 10 ** decimals) / 10 ** decimals
jsgaston commented 2 years ago

hi .... I've seen that TP = float(round((tp) , 2)) only works with ethusdt .... how do I make it work for other pairs? how do I use the def described above? can make an example? thanks

PabloBorda commented 2 years ago

Hey ! That. Is bit of a hassle but I found the way by using this on pyhon 3.9.5, THAT IS THE ONLY THING THAT WORKED FOR ME , I WASTED SO MUCH TIME ON THIS SH 1T

There is bina

from binance.helpers import round_step_size

def get_rounded_base_quantity(self):
    return round_step_size((float(self.get_quote_value())/float(self.get_symbol().get_current_price())), float(self.get_symbol().get_step_size()))

On 2 Jan 2022, at 20:09, jsgaston @.***> wrote:

hi .... I've seen that TP = float(round((tp) , 2)) only works with ethusdt .... how do I make it work for other pairs? how do I use the def described above? can make an example? thanks

— Reply to this email directly, view it on GitHub https://github.com/sammchardy/python-binance/issues/296#issuecomment-1003768426, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABDNE45YY44VIRDVDKO4M23UUCWGNANCNFSM4FFYSZCQ. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you commented.

jsgaston commented 2 years ago

HI, can't make it work (just tried with bnbusdt) . I've imported the libreries. ... dont really know what to do to make it work... can u please tell me what I need to do to make it wokr?

PabloBorda commented 2 years ago

If you

You can add me to telegram if you wish I am : @com_goldenthinker_trade_pablo

I noticed here that the trick with this is as follows, lets say you want to place an order to buy, ETHUSDT

You say to the exchange: create_market_buy_order worth for a quote amount of 20 USD

The exchange receives the order, but in between the exchange UPDATED THE PRICE, and the API only will accept EXACT numbers, and the quote amounts you pass have to be divisible per the new ETH quotation in USD.

The other solution is instead of passing the QUOTE value in USD, is to pass the BASE QUANTITY value you want to buy in ETH which is more exact and you do not depend on the timing and the exchange updating the price behind. BUT the amount that you pass have to be divisible per the STEP_SIZE of the base currency, that you can obtain from the EXCHANGE INFO API .

Is kind of a mess and the API should be able to accept and pass any number disregarding if it passes or does not pass the FILTERS. You should be able to pass ANY number, and the API should convert that number to the closest number that complies with the FILTERS. ]

Kind Regards

On 2 Jan 2022, at 20:44, jsgaston @.***> wrote:

HI, can't make it work (just tried with bnbusdt) . I've imported the libreries. ... dont really know what to do to make it work... can u tell me what I need to do to make it wokr?

— Reply to this email directly, view it on GitHub https://github.com/sammchardy/python-binance/issues/296#issuecomment-1003772386, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABDNE4Y4TWOVBX7TPXNVRCDUUC2JHANCNFSM4FFYSZCQ. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you commented.

predirsec commented 2 years ago

I keep getting "APIEError(code=-1111): Precision is over the maximum defined for this asset" while I'm trying to execute a trade using a JSON payload that is sent from tradingview to my bot.

I have tried rounding the order amount before sending the request, this was successful in shortening the precision, but it resulted in the same error (resulted in a float being sent). I then tried using Decimal to shorten the precision, this was also successful in shortening the precision, but it resulted in the same error (decimal.Decimal was sent).

Here is my code:

Order Code:

def order(side, quantity, symbol, order_type=ORDER_TYPE_MARKET): try: print(f"sending order {order_type} - {side} {quantity} {symbol}") order = client.futures_create_order(symbol=symbol, side=side, type=order_type, quantity=quantity) except Exception as e: print("an exception occurred - {}".format(e)) return False

return order

Webapp code:

@app.route('/webhook3', methods=['POST'])

def webhook3():

print(request.data)
data = json.loads(request.data)
price = data["strategy"]["order_price"]
getcontext().prec = 6
urquantity = Decimal(str(lot3)) / Decimal(str(price))

if data["passphrase"] != config.WEBHOOK_PASSPHRASE:
    return {
        "code": "error",
        "message": "Invalid Request"
    }

side = data["strategy"]["order_action"].upper()
quantity = urquantity
symbol = data["ticker"]
order_response = order(side, quantity, symbol)

print(type(urquantity))
print(type(quantity))

I use insomnia to send the request to the locally hosted webapp and I get this result:

b'\n{\n "passphrase": "",\n "time": "2021-12-22T23:05:00Z",\n "exchange": "BINANCE",\n "ticker": "SUSHIUSDT",\n "bar": {\n "time": "2021-12-22T23:05:00Z",\n "open": 6.46,\n "high": 6.46,\n "low": 6.46,\n "close": 6.46,\n "volume": 5.1\n },\n "strategy": {\n "position_size": 100,\n "order_action" : "buy",\n "order_contracts": 10,\n "order_price": 6.46,\n "order_id": "long",\n "market_position": "long",\n "market_position_size": 10,\n "prev_marke t_position": "short",\n "prev_market_position_size": 0\n }\n}'

sending order MARKET - BUY 10.5139 SUSHIUSDT

an exception occurred - APIError(code=-1111): Precision is over the maximum defined for this asset.

<class 'decimal.Decimal'> <class 'decimal.Decimal'> order failed

I can only get orders to succeed if I send an int to Binance through the bot but even if the order is 10.5 it will still fail for the same error. Max precision is much higher than what I'm sending. If anyone has any suggestions or has a solution, your help would be greatly appreciated. I'm new to coding so my knowledge base is limited.

Thanks!

P.S. Pablo, you're a legend for trying to help so many people!

jstrausd commented 2 years ago

Has anyone a solution to create a order with decimals? I tried various ways for solving this problem, but didn't find one which is working. It also doesn't make sense to not accept floats which are formatted to the precision of the specific coin.

RubyBosss commented 2 years ago

Has anyone found a solution? I am having the same issue

predirsec commented 2 years ago

It's not exactly an easy answer (as far as I've been able to figure). First you need to get the quantity precision of the asset you want to trade. Lots of people mention step size and price precision, but if you have the same issues I did, it's actually quantityPrecision that's messing you up. If you're doing market orders, this is most likely your issue.

I wrote this to print out the quantity Precision for all of the symbols on Binance:

response_object = request.get("https://fapi.binance.com/fapi/v1/exchangeInfo")

for contract in response_object.json()['symbols']:
> print('QP_' + (contract['pair']) + ' = ' + str(contract['quantityPrecision']))

Then I added a truncate feature to my bot with this:

` import math

def truncate(number, decimals=0):

if not isinstance(decimals, int):

raise TypeError("decimal places must be an integer.") elif decimals < 0: raise ValueError("decimal places must be an integer.") elif decimals == 0: return math.trunc(number)

factor = 10.0 ** decimals return math.trunc(number + factor) / factor

`

THENNN, when I add quantity to my order I do it this way:

quantity = truncate(round((spend / price), quantityPrecision))

In the above, spend is just the amount I want to spend, price is the current price of the asset, and quantityPrecision is that precision I got from earlier. I round it because if you're truncating to 2 or 3 decimals places (2 or 3 precision), and your asset is worth $100, I feel like it's closer to what I want if I round it.

This is ugly, but it works. PS, I couldn't get the formatting to work well, but if you want more info on truncating just google it, that's where I got that block of code.

Fistash commented 2 years ago

you can get these values from the exchange: GET /fapi/v1/exchangeInfo

Karlheinzniebuhr commented 2 years ago

Rounding to 1 decimal worked for me. I guess this comes from the new $0.1 tick size

duyngha commented 1 year ago

API exchangeInfo https://api.binance.com/api/v3/exchangeInfo https://fapi.binance.com/fapi/v1/exchangeInfo

This is answer

Karlheinzniebuhr commented 1 year ago

API is still returning the wrong precision from endpoints. Any plans to solve this issue?

PLQin commented 1 year ago

Yes, using quantityPrecision solves my problem. This field comes from the interface:/exchangeInfo

eg:


var exchangeInfo = await getExchangeInfo();
    exchangeInfo = JSON.parse(exchangeInfo);

var quantityPrecision = exchangeInfo.symbols.find(item => { return item.symbol === currency.symbol }).quantityPrecision

// 55 usdt 
var quantity = new bigNumber(55).div(currency.price).toFixed(quantityPrecision);
await order({
  symbol: currency.symbol,
  side: 'BUY',
  type: 'MARKET',
  quantity,
  positionSide: 'LONG', // BOTH 单一持仓操作    LONG 多头(双向持仓下)操作    SHORT 空头(双向持仓下)操作
  timestamp: Date.now()
}).then(res => {
  console.log(`success`, res);
}).catch(error => {
  console.log(`line ${getCurrentLine()} error:`, error);
})
ardaakay0 commented 11 months ago

I had the same issue and solved it as following:

def getRoundCount(symbol):
    exchance_info = binance_client.exchange_info()
    symbols = exchance_info["symbols"] 
    for i in symbols:
        if i["symbol"] == symbol:
            filters = i["filters"]
            df_filters = pd.DataFrame(filters)
            df_filters.set_index("filterType", inplace=True)
            lot_size_row = df_filters.loc["LOT_SIZE"]
            minQty = lot_size_row["minQty"]
            count_after_decimal = str(minQty)[::-1].find('.')
            return count_after_decimal

Code might not be optimal since I am a beginner but it does the job.