Order cancelation does not seem to be immediate/blocking and keeps assets locked after returning

It happened to me that I successfully canceled an order through API:

{'symbol': 'ADAUSDT', 'origClientOrderId': 'lfyN1QHuCGgSAryQfAHGmx', 'orderId': 4946707934, 'orderListId': -1, 'clientOrderId': 'dsvfMuFqAxn4Rly2wfLZw6', 'transactTime': 1724768554180, 'price': '0.38750000', 'origQty': '421.90000000', 'executedQty': '0.00000000', 'cummulativeQuoteQty': '0.00000000', 'status': 'CANCELED', 'timeInForce': 'GTC', 'type': 'LIMIT', 'side': 'SELL', 'selfTradePreventionMode': 'EXPIRE_MAKER'}

But when I asked about the available balance right after (by using client.get_asset_balance(asset=‘ADA’) from python-binance library), I got the following:
Current balance for asset ADA: {'asset': 'ADA', 'free': '0.03800000', 'locked': '421.90000000'}
WARNING: Non-zero locked balance 421.90000000 for asset ADA.

The order cancelation does not seem to block until the assets are released (i.e. there is some asynchronicity and the assets are only released later after the cancellation call is finished). What is the best way to tackle this problem? I need the assets to be free after the order is canceled.

I’ve now discovered there is the same/similar problem for market order vs. asking for available resources right after:

{'symbol': 'ADAUSDT', 'orderId': 4946491822, 'orderListId': -1, 'clientOrderId': 'YsZHIa0HjoV3MlryuojEtp', 'transactTime': 1724718158377, 'price': '0.00000000', 'origQty': '422.30000000', 'executedQty': '422.30000000', 'cummulativeQuoteQty': '155.27971000', 'status': 'FILLED', 'timeInForce': 'GTC', 'type': 'MARKET', 'side': 'BUY', 'workingTime': 1724718158377, 'fills': [{'price': '0.36770000', 'qty': '422.30000000', 'commission': '0.42230000', 'commissionAsset': 'ADA', 'tradeId': 502106561}], 'selfTradePreventionMode': 'EXPIRE_MAKER'}

and right after:

Current balance for asset ADA: {'asset': 'ADA', 'free': '0.08260000', 'locked': '0.00000000'}

What’s the cleanest way to solve this issue?

The assets are available immediately after you get a response to DELETE /api/v3/order request.

GET /api/v3/account response with account balance can be more delayed than the actual state in the matching engine. This endpoint it’s documented to be updated from memory and database.

If you want account balance updates with lower delay, please try WebSocket user data stream, specifically the "outboundAccountPosition" events.

Thanks! If I don’t want to switch to websockets right now, I think my best option is to try the /api/v3/account multiple times after order cancelation or market order, is that right?

Yes. In that case you can only retry /api/v3/account, the balance should update soon. (But do note that this endpoint has rather high weight, so don’t spam it too much.)

You can compare "updateTime" in the /api/v3/account response with "transactTime" in the order cancellation response. Once updateTime >= transactTime, the balance will reflect the cancellation.

2 Likes