ccxt: Can't execute createMarketBuyOrder due to "insufficient balance" error

  • OS: Windows 7
  • Programming Language version: Javascript
  • CCXT version: 1.13.19
  • Exchange: Binance
  • Method: createMarketBuyOrder

I executed the code below:

console.log(tradingPairs[BEST_TRADING_PAIR_INDEX][SYMBOL_INDEX], balance.USDT.free)
//above code print out "ETH/USDT 18.87629041"
exchange.createMarketBuyOrder (tradingPairs[BEST_TRADING_PAIR_INDEX][SYMBOL_INDEX], balance.USDT.free)

However, I got this error:

(node:12940) UnhandledPromiseRejectionWarning: Error: binance {"code":-2010,"msg":"Account has insufficient balance for requested action."}
    at binance.handleErrors (C:\Users\workshop\node_modules\ccxt\js\binance.js:862:31)
    at response.text.then (C:\Users\workshop\node_modules\ccxt\js\base\Exchange.js:513:18)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)
(node:12940) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:12940) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Any idea why? Is it related to the fee? I ran similar code with market sell order and there is no issue. Thanks in advance.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 1
  • Comments: 18 (9 by maintainers)

Most upvoted comments

It’s a bit more involved.

In general, your order is bound by:

  • amount/price/cost min/max limits (stored in market.limits property)
  • your available balance
  • precisions for price and amount (stored in market.precisions property)

So first, you estimate your target amount with balance / price.

Then you truncate amount to the required precision with https://github.com/ccxt/ccxt/blob/334ebc682e9c5139ae5042434e437cadcefebebd/js/base/Exchange.js#L1012

If you take your price from orderbook then it’s ready to use. But if it’s the result of some calculation then you need to round it up or down (depending on your logic) to the precision… That’s a bit tricky as ccxt rounds it to the nearest neighbor with priceToPrecision. Maybe guys will make it directional but at the moment you’ll need to enforce the direction by yourself.

Then you calculate the cost (i.e. truncated amount * rounded price).

Then you check if all three (amount/price/cost) passes the limits.

Then you place your order!

It may sound scary but these are few lines of code in reality.

I wouldn’t say it’s tricky… Think of it from another perspective:

  • when you place a market order it’s said that you’re guaranteed time (immediate), amount (unless your order is so huge that eats up all the orderbook) but not price (in case someone jumps in front of you)

  • when you place a limit order it’s said that you’re guaranteed price but not time (you can wait forever until it’s executed)

The problem with providing the amount of base currency…

Traders treat this base currency as inventory. They try to make money by managing this inventory. And they never want to have an unspecified amount of inventory. It’s just hard to manage.

the orderbook bid price might increase before the order gets submitted. Any workaround for this issue?

Not only bid price may increase, bid amount may change too. It happens all the time and is called “slippage”.

Should I just use limitBuyOrder, so I won’t get the error?

I’d say yes because in general, it’s practical to be conscious about the price and amount.

I mean, I actually read your question as “I want to buy at any price for all available money” and this sounds a bit weird as to me.

Let’s say you want to make sausage and eggs breakfast and you need to buy some tomatoes for it… So you go to a farmer market, pick tomatoes you like, check the price and say smth like: “Hey, sell me these three tomatoes”. You never come to a random seller and say “Hey, I don’t care reading the price tag but here is my wallet, give me as many tomatoes as possible with that money in it”.

Likewise, when you buy inventory you probably want to buy it cheaper and to sell it with profit. And in order to “buy cheaper”, you need to be confident about the price. Put it in another way, if you don’t check the price how can you be sure you buy cheaper?

The problem with providing the amount of base currency in marketBuyOrder is that I might occasionally get an InsufficientFunds error, because the orderbook bid price might increase before the order get submitted (due to network delay)… Any workaround for this issue? Should I just use limitBuyOrder, so I won’t get the error?

Currently, I subtract the computed amount (USDT / bid price) with market.limits.amount.min, though it only works if there is only a very slight change on the bid price…

Shouldn’t I just need to put the USDT amount when I want to buy ETH?

  • When you buy – you buy ETH for USDT.
  • When you sell – you sell ETH for USDT.

So all amounts are in base currency, all prices are in quote currency:

https://github.com/ccxt/ccxt/wiki/Manual#consistency-of-base-and-quote-currencies

base currency ↓
             BTC / USDT
             ETH / BTC
            DASH / ETH
                    ↑ quote currency

This is a normal mode of operation of practically any FX system or crypto exchange. Some exchanges will allow to specify the money to spend in the quote currency, but most of them won’t. You need to consult their exchange-specific docs for that.

Hope this answers your questions. Let us know if not.

Did you mean that you have to manually add up the volume * price of the sell orders (when buying) and keep going until the cumulated (price * amount) hits how much you have in quote?

While your explanation is correct I didn’t mean that, actually. I didn’t touch how to come up with price and amount. I was talking about how to make sure your order hits orderbook once you have price and amount calculated. The issue is that if the order is under limits then it will trigger InvalidOrder exception. If it exceeds your available balance it will trigger InsufficientFunds.

If you use the orderbook as a measurement tool, it could still be that by the time you post it, it could still be outdated compared to an order arriving just before you

Sure. It happens all the time.

failing your entire order?

No. The part that hits other orders will get executed immediately. The rest of your order will remain resting in the orderbook. So, technically, your order won’t fail, it will be just partly executed.

You may want to read more details here: https://github.com/ccxt/ccxt/wiki/Manual#how-orders-are-related-to-trades

Oh… I see, this is my first experience of using a library for trading… BTW, any suggestion on the best way to compute the amount of ETH when I want to buy using market buy method?

Currently, I did this:

let orderbook = await exchange.fetchOrderBook ('ETH/USDT')
bid = orderbook.bids.length ? orderbook.bids[0][0] : undefined
let coin = (balance.USDT.free / bid).toFixed(4) - 0.0001
exchange.createMarketBuyOrder ('ETH/USDT', (balance.USDT.free / bid).toFixed(4) - 0.0001)

I want to buy ETH with 18.87629041 USDT…

I found the problem, I thought the amount is in USDT which is incorrect… The weird part is that when I want to sell, say ETH to USDT, I just need to put the amount of ETH. However, if i want to buy ETH from USDT, I still need to put the amount of ETH. Shouldn’t I just need to put the USDT amount when I want to buy ETH? Because if I have to put the ETH amount, then I need to calculate the ETH amount that I can get with certain USDT amount, which so inconvenient. Is it possible to update the market buy method?