使用KuCoin API买入BTC时遇Funds increment invalid错误求助
我使用Python 3.12.3调用KuCoin API查询USDT余额并兑换为BTC,针对交易金额需匹配API提供的quoteIncrement倍数、以及价格波动问题,已设置0.01 USDT缓冲,并通过usdt_amount = (usdt_amount // quote_increment) * quote_increment调整金额,但执行时仍触发错误:
Order failed: 200-{"msg":"Funds increment invalid.","code":"400100"}
原代码如下:
from kucoin.client import Trade, User, Market # Replace with your actual API credentials api_key = 'my key' api_secret = 'my secret' api_passphrase = 'my passphrase' # Initialize the KuCoin clients trade_client = Trade(key=api_key, secret=api_secret, passphrase=api_passphrase) user_client = User(key=api_key, secret=api_secret, passphrase=api_passphrase) market_client = Market(key=api_key, secret=api_secret, passphrase=api_passphrase) # Get account balances account_balances = user_client.get_account_list() # Find the USDT balance usdt_balance = next((item for item in account_balances if item['currency'] == 'USDT' and item['type'] == 'trade'), None) # Check if there is enough USDT balance if usdt_balance and float(usdt_balance['balance']) > 0: total_usdt_amount = float(usdt_balance['balance']) buffer_amount = 0.01 # Leaving 0.01 USDT as buffer usdt_amount = total_usdt_amount - buffer_amount # Get the symbol info to find the quote increment and minimum size symbol_info = market_client.get_symbol_list() btc_usdt_info = next(item for item in symbol_info if item['symbol'] == 'BTC-USDT') quote_increment = float(btc_usdt_info['quoteIncrement']) quote_min_size = float(btc_usdt_info['quoteMinSize']) # Adjust USDT amount to be a multiple of quote_increment usdt_amount = (usdt_amount // quote_increment) * quote_increment if usdt_amount < quote_min_size: print(f"Order amount is too small, minimum required is {quote_min_size} USDT") else: # Create the market order to trade all USDT for BTC try: order = trade_client.create_market_order('BTC-USDT', 'buy', funds=str(usdt_amount)) print(f"Order successful: Traded {usdt_amount} USDT for BTC") except Exception as e: print(f"Order failed: {e}") else: print("Insufficient USDT balance or USDT balance not found")
问题原因及修复方案
1. 浮点数精度误差
Python的浮点数运算存在精度丢失问题,比如100.01 - 0.01理论上是100.0,但实际可能存储为99.99999999999999,后续的倍数调整无法完全修正这个误差,导致最终金额不符合quoteIncrement要求。
修复:使用decimal模块进行精确的小数运算,避免精度丢失:
from decimal import Decimal, getcontext # 设置精度,匹配KuCoin的小数位数 getcontext().prec = 10 # 替换原金额计算部分 total_usdt_amount = Decimal(usdt_balance['balance']) buffer_amount = Decimal('0.01') usdt_amount = total_usdt_amount - buffer_amount quote_increment = Decimal(btc_usdt_info['quoteIncrement']) # 调整为quote_increment的倍数 usdt_amount = (usdt_amount // quote_increment) * quote_increment
2. 字符串格式化问题
将浮点数直接转为字符串时,可能出现多余的小数位(如100.0变成100.0000000001),KuCoin API无法识别这种格式。
修复:根据quoteIncrement的小数位数格式化字符串,比如BTC-USDT的quoteIncrement是0.01,则保留2位小数:
# 获取quoteIncrement的小数位数 decimal_places = len(quote_increment.split('.')[1]) if '.' in quote_increment else 0 # 格式化金额字符串 formatted_usdt_amount = f"{usdt_amount:.{decimal_places}f}" # 传入API时使用格式化后的字符串 order = trade_client.create_market_order('BTC-USDT', 'buy', funds=formatted_usdt_amount)
3. 验证quoteIncrement的正确性
确认从get_symbol_list()获取的quoteIncrement值是否正确,比如BTC-USDT的quoteIncrement应为0.01,可以在代码中打印验证:
print(f"Quote Increment: {btc_usdt_info['quoteIncrement']}")
4. 缓冲后金额的边界检查
确保减去缓冲后的金额调整为倍数后,仍大于等于quoteMinSize,避免因缓冲导致金额过小。
修改后的完整代码
from kucoin.client import Trade, User, Market from decimal import Decimal, getcontext # Replace with your actual API credentials api_key = 'my key' api_secret = 'my secret' api_passphrase = 'my passphrase' # Initialize the KuCoin clients trade_client = Trade(key=api_key, secret=api_secret, passphrase=api_passphrase) user_client = User(key=api_key, secret=api_secret, passphrase=api_passphrase) market_client = Market(key=api_key, secret=api_secret, passphrase=api_passphrase) # Get account balances account_balances = user_client.get_account_list() # Find the USDT balance usdt_balance = next((item for item in account_balances if item['currency'] == 'USDT' and item['type'] == 'trade'), None) # Check if there is enough USDT balance if usdt_balance and Decimal(usdt_balance['balance']) > 0: getcontext().prec = 10 total_usdt_amount = Decimal(usdt_balance['balance']) buffer_amount = Decimal('0.01') # Leaving 0.01 USDT as buffer usdt_amount = total_usdt_amount - buffer_amount # Get the symbol info to find the quote increment and minimum size symbol_info = market_client.get_symbol_list() btc_usdt_info = next(item for item in symbol_info if item['symbol'] == 'BTC-USDT') quote_increment_str = btc_usdt_info['quoteIncrement'] quote_increment = Decimal(quote_increment_str) quote_min_size = Decimal(btc_usdt_info['quoteMinSize']) # Adjust USDT amount to be a multiple of quote_increment usdt_amount = (usdt_amount // quote_increment) * quote_increment if usdt_amount < quote_min_size: print(f"Order amount is too small, minimum required is {quote_min_size} USDT") else: # Format the amount to match quote increment's decimal places decimal_places = len(quote_increment_str.split('.')[1]) if '.' in quote_increment_str else 0 formatted_usdt_amount = f"{usdt_amount:.{decimal_places}f}" # Create the market order to trade all USDT for BTC try: order = trade_client.create_market_order('BTC-USDT', 'buy', funds=formatted_usdt_amount) print(f"Order successful: Traded {formatted_usdt_amount} USDT for BTC") except Exception as e: print(f"Order failed: {e}") else: print("Insufficient USDT balance or USDT balance not found")
内容的提问来源于stack exchange,提问作者Ramy Al Zuhouri

