Binance Convert Limit Order API调用报错及参数格式问题求助
通过Binance API创建Convert限价订单失败的问题排查
我尝试通过Binance API创建Convert限价订单,按照Postman文档,参数和正常工作的user_saldo接口一样用POST传递,但调用conversao方法时返回错误:
content: b'{"code":345214,"msg":"Placing a limit order has failed. Please try again later. Error code: 345124"}'
我调整过limitPrice(买入调低、卖出调高避免无效订单),但错误依旧。后来把小数位数从15位改成8位解决了部分问题,但传入quant_de_cpt时又提示格式错误。请问哪里操作有误?
以下是相关Python代码:
#!/usr/bin/env python import os import requests import time import hmac import hashlib class OperadorBinanceClient: def __init__(self, api_key=None, api_secret=None): self.api_key = api_key or os.environ.get('binance_api_key') self.api_secret = api_secret or os.environ.get('binance_api_secret') self.recv_window = 60000 # Valor em milissegundos self.base_url = 'https://api.binance.com' self.user_endpoint = '/sapi/v3/asset/getUserAsset' self.conversao_endpoint = '/sapi/v1/convert/limit/placeOrder' self.conversao_status_endpoint = '/sapi/v1/convert/orderStatus' def _get_timestamp(self): return str(int(time.time() * 1000)) def _generate_signature(self, query_string:str): signature = hmac.new(self.api_secret.encode('utf-8'), query_string.encode('utf-8'), hashlib.sha256).hexdigest() return signature def user_saldo(self, coin='BRL'): timestamp = self._get_timestamp() query_string = f'recvWindow={self.recv_window}×tamp={timestamp}' signature = self._generate_signature(query_string) url = f'{self.base_url}{self.user_endpoint}?{query_string}&signature={signature}' headers = {'X-MBX-APIKEY': self.api_key} response = requests.post(url, headers=headers) all_balances = response.json() if coin == '': return all_balances filtered_balance = [item for item in all_balances if item['asset'] == coin] # empty list coin not exist return filtered_balance if len(filtered_balance) > 0 else None def conversao2(self, de='BRL', para='ETH', quantidade=1, quantidade_de_crypto=0.1, preco_limite=None, lado='BUY', tipo_carteira='SPOT'): timestamp = self._get_timestamp() quant_de_cpt = f'{quantidade_de_crypto:.15f}' data = { 'baseAsset': de, 'quoteAsset': para, 'limitPrice': preco_limite or '', 'baseAmount': quantidade, 'quoteAmount': quant_de_cpt, 'side': lado, 'expiredType': '1_H', 'recvWindow': 60000, 'timestamp': timestamp } signature = self._generate_signature('&'.join([f'{key}={data[key]}' for key in data])) data['signature'] = signature url = f'{self.base_url}{self.conversao_endpoint}' headers = {'X-MBX-APIKEY': self.api_key, 'Content-Type': 'application/json'} response = requests.post(url, headers=headers, data=data) return response.json() def conversao(self, de= 'BRL', para='ETH', quantidade=1, quantidade_de_crypto=0.1,preco_limite=None, lado='BUY', tipo_carteira='SPOT'): timestamp = self._get_timestamp() quant_de_cpt = f'{quantidade_de_crypto:.15f}' #"eAmount={quant_de_cpt} query_string = f'baseAsset={de}"eAsset={para}&limitPrice={preco_limite}&baseAmount={quantidade}&side={lado}&expiredType=1_H&recvWindow=60000×tamp={timestamp}' signature = self._generate_signature(query_string) url = f'{self.base_url}{self.conversao_endpoint}?{query_string}&signature={signature}' headers = {'X-MBX-APIKEY': self.api_key, 'Content-Type': 'application/json'} response = requests.post(url, headers=headers) return response.json() def conversao_status(self, id_conversao): timestamp = self._get_timestamp() query_string = f'orderId={id_conversao}&recvWindow=60000×tamp={timestamp}' signature = self._generate_signature(query_string) url = f'{self.base_url}{self.conversao_status_endpoint}?{query_string}&signature={signature}' headers = {'X-MBX-APIKEY': self.api_key} response = requests.get(url, headers=headers) return response.json()

问题排查与解决方案
1. 参数传递格式错误
Binance的Convert限价订单接口要求参数通过**表单格式(application/x-www-form-urlencoded)**传递,而非代码中设置的JSON格式。你在conversao和conversao2方法里指定了Content-Type: application/json,这会导致接口无法正确解析参数,直接触发345124错误。
2. 数量参数精度不匹配
Binance对不同交易对的数量精度有严格限制,不能统一用15位或8位小数。必须先通过/api/v3/exchangeInfo接口获取目标交易对的精度规则:
- 找到对应交易对(如ETHBRL)的
baseAssetPrecision(基础资产精度)和quoteAssetPrecision(报价资产精度) - 根据返回的精度值格式化金额参数,避免多余小数位导致格式错误
3. 冗余参数冲突
Convert限价订单中,baseAmount和quoteAmount是互斥的:
- 当
side=BUY时,只需传入quoteAmount(用报价资产的金额购买基础资产,比如用BRL买ETH时传BRL的金额) - 当
side=SELL时,只需传入baseAmount(卖出基础资产的数量,比如卖出ETH时传ETH的数量)
同时传入两个参数会导致接口报错。
修正后的代码示例
def conversao_corrigida(self, de='BRL', para='ETH', quantidade=None, preco_limite=None, lado='BUY'): timestamp = self._get_timestamp() # 获取交易对精度规则 exchange_info = requests.get(f"{self.base_url}/api/v3/exchangeInfo").json() symbol = f"{para}{de}" if lado == 'BUY' else f"{de}{para}" target_symbol = next(item for item in exchange_info['symbols'] if item['symbol'] == symbol) params = { 'baseAsset': de, 'quoteAsset': para, 'limitPrice': preco_limite, 'side': lado, 'expiredType': '1_H', 'recvWindow': 60000, 'timestamp': timestamp } # 根据交易方向添加对应数量参数,并按精度格式化 if lado == 'BUY': precision = target_symbol['quoteAssetPrecision'] params['quoteAmount'] = f"{quantidade:.{precision}f}" else: precision = target_symbol['baseAssetPrecision'] params['baseAmount'] = f"{quantidade:.{precision}f}" # 按排序后的参数生成签名,避免顺序问题导致签名无效 sorted_params = sorted(params.items()) query_string = '&'.join([f'{key}={value}' for key, value in sorted_params]) signature = self._generate_signature(query_string) params['signature'] = signature url = f'{self.base_url}{self.conversao_endpoint}' headers = {'X-MBX-APIKEY': self.api_key} # 使用表单格式传递参数,无需手动设置Content-Type response = requests.post(url, headers=headers, data=params) return response.json()
额外注意事项
limitPrice的精度同样需要参考exchangeInfo中的pricePrecision字段- 签名生成时必须保证参数顺序和实际传递的一致,建议排序后拼接
- 测试优先使用Binance测试网,避免真实资产损失
内容的提问来源于stack exchange,提问作者Joao Victor
相关产品推荐
相关产品推荐

