pythonpython-requestsrequestbinancebinance-api-client

ERROR API Binance convert limit placeOrder


I'm trying to make a limit order of convert using binance api. The Postman doc tell us that should be pass as parameter in the POST like we do with user_saldo that works just fine.

The error returned content: b'{"code":345214,"msg":"Placing a limit order has failed. Please try again later. Error code: 345124"}'

so the methods conversao don't work. I also tried to ajust the limitePrice value when it is a BUY and increase it when it's a SELL to avoid open a dead limit order, still same error.

Fixed using only 8 decimal units instead of 15 Another issue that give a diffent error is when I try to pass the quant_de_cpt it says this value is malformed.

What I'm doing wrong?

#!/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}&timestamp={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}'
        
        #&quoteAmount={quant_de_cpt}
        query_string = f'baseAsset={de}&quoteAsset={para}&limitPrice={preco_limite}&baseAmount={quantidade}&side={lado}&expiredType=1_H&recvWindow=60000&timestamp={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&timestamp={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()

Show Url value


Solution

  • The issue was that the baseAmount should be what return the exchangeInfo endpoint '/sapi/v1/convert/exchangeInfo'

    when you define the baseAsset it should be the asset valid as base like this

            exchange_info=self.exchange_info(from_asset=de, to_asset=para)
            if exchange_info[0]['fromIsBase']:
                query_string = f'baseAsset={de}&quoteAsset={para}&limitPrice={preco_limite}&quoteAmount={quantidade}&side={lado}&walletType={tipo_carteira}&expiredType=1_D&recvWindow=60000&timestamp={timestamp}'
            else:
                query_string = f'baseAsset={para}&quoteAsset={de}&limitPrice={preco_limite}&baseAmount={quantidade_de_crypto}&side={lado}&walletType={tipo_carteira}&expiredType=1_D&recvWindow=60000&timestamp={timestamp}'
            signature = self._generate_signature(query_string)