使用 Python 与 Binance API 进行交易的问题

问题描述

我正在尝试在不使用外部库的情况下对美国版 Binance API 进行交易。

我可以使用 GET 请求和 color: $some-color !important 成功获取价格并显示我的帐户余额。第一个示例代码有效,我可以毫无问题地传递我的 urllibAPI_KEY(这些值是私有的,它们不会在此处显示,而是位于 SECRET_KEY 中)。

进行交易需要 POST,但我不确定我哪里出错了,我的 POST 请求不起作用但 GET 请求工作正常。根据我对 docs 发出 POST 请求的理解,我应该使用 settings.py 对参数进行编码并将其传递到 urllib.parse.urlencode() 中的 data 参数中。

这样做不会引发错误,但是当我尝试使用 urllib.request.Request() 打开请求时,出现错误

urllib.request.urlopen()

HTTP Return Codes 状态:

HTTP 5XX 返回码用于内部错误;问题是 币安方面。重要的是不要将此视为失败 手术;执行状态为 UNKNowN,可能是 成功。

但是,我不认为是这种情况,因为我可以毫无问题地运行其他代码函数 Traceback (most recent call last): File "C:\Users\user\PycharmProjects\test\test.py",line 80,in <module> place_Trade(symbol='BTCUSD',side='BUY',order_type='MARKET',quantity=1) File "C:\Users\user\PycharmProjects\test\test.py",line 73,in place_Trade response = urllib.request.urlopen(req) File "C:\Users\user\AppData\Local\Programs\Python\python39\lib\urllib\request.py",line 214,in urlopen return opener.open(url,data,timeout) File "C:\Users\user\AppData\Local\Programs\Python\python39\lib\urllib\request.py",line 523,in open response = meth(req,response) File "C:\Users\user\AppData\Local\Programs\Python\python39\lib\urllib\request.py",line 632,in http_response response = self.parent.error( File "C:\Users\user\AppData\Local\Programs\Python\python39\lib\urllib\request.py",line 561,in error return self._call_chain(*args) File "C:\Users\user\AppData\Local\Programs\Python\python39\lib\urllib\request.py",line 494,in _call_chain result = func(*args) File "C:\Users\user\AppData\Local\Programs\Python\python39\lib\urllib\request.py",line 641,in http_error_default raise HTTPError(req.full_url,code,msg,hdrs,fp) urllib.error.HTTPError: HTTP Error 500: Internal Server Error 。我不确定我做错了什么,除了发出 GET 与 POST 请求外,这两个代码几乎相同。

获取帐户余额的代码 - 工作正常:

get_account_balance()

进行交易的代码 - 不起作用:

import json
import time
import hmac
import settings
import hashlib
import urllib.parse
import urllib.request


def get_account_balance():

    # Setup header with API_KEY
    headers = {'X-MBX-APIKEY': settings.API_KEY}

    # Params requires timestamp in MS
    params = {'timestamp': int(time.time() * 1000)}

    # Encode params into url
    url = 'https://api.binance.us/api/v3/account?' + urllib.parse.urlencode(params)

    # Create a HMAC SHA256 signature
    secret = bytes(settings.SECRET_KEY.encode('utf-8'))
    signature = hmac.new(secret,urllib.parse.urlencode(params).encode('utf-8'),hashlib.sha256).hexdigest()

    # Add signature to url
    url += f'&signature={signature}'

    # Make a request
    req = urllib.request.Request(url,headers=headers)
    
    # Read and decode response
    response = urllib.request.urlopen(req).read().decode('utf-8')
    
    # Convert to json
    response_json = json.loads(response)

    # Print balances for all coins not at 0
    for entry in response_json['balances']:
        if entry['free'] == '0.00000000':
            continue
        print(entry)


get_account_balance()

参考资料

示例中使用了此端点,但两个端点的功能相同且错误相同

我还查看了图书馆 import json import time import hmac import settings import hashlib import urllib.parse import urllib.request def place_Trade(symbol,side,order_type,quantity): # Setup header with API_KEY headers = {'X-MBX-APIKEY': settings.API_KEY} # Params require symbol,type,quantity and timestamp (for market orders) params = { 'symbol': symbol,'side': side,'type': order_type,'quantity': quantity,'timestamp': int(time.time() * 1000) } # Encode params into url url = 'https://api.binance.us/api/v3/order/test?' + urllib.parse.urlencode(params) # Create a HMAC SHA256 signature secret = bytes(settings.SECRET_KEY.encode('utf-8')) signature = hmac.new(secret,hashlib.sha256).hexdigest() # Add signature to url url += f'&signature={signature}' # Encode params data = urllib.parse.urlencode(params).encode('ascii') # Make a POST request req = urllib.request.Request(url,headers) # Open request and convert to string and then to json response = urllib.request.urlopen(req) # <- line with error response_str = response.read().decode('utf-8') response_json = json.loads(response_str) print(response_json) place_Trade(symbol='BTCUSD',quantity=1) 的示例

编辑

我可以使用 python-binance 库成功下单。我浏览了库的源代码,但无法弄清楚如何使用 requests

正确格式化 POST 请求

使用 urllib 库进行交易的代码 - 有效:

requests

解决方法

问题在于以下几行:

# Encode params into url
url = 'https://api.binance.us/api/v3/order/test?' + urllib.parse.urlencode(params)

# Add signature to url
url += f'&signature={signature}'

显然,在使用 urllib 时,GET 请求负载必须编码到 url 本身中,但是 POST 请求要求您将它们传递到 data 参数中:

data = urllib.parse.urlencode(params).encode('ascii')
req = urllib.request.Request(url,data=data,headers=headers)

在我的问题中,我通过 url 和 data 参数传递我的负载。删除 url 有效负载可解决此问题。任何绊倒这一点的人的旁注,在 url 后面放置一个问号 ? 对于 POST 请求是可选的,但在使用 urllib

时不是 GET 请求

无需外部库即可发布交易的工作代码:

import json
import time
import hmac
import hashlib
import settings
import urllib.parse
import urllib.request

params = {
        'symbol': 'BTCUSD','side': 'BUY','type': 'MARKET','quantity': 1,'timestamp': int(time.time() * 1000)
}

secret = bytes(settings.SECRET_KEY.encode('utf-8'))
signature = hmac.new(secret,urllib.parse.urlencode(params).encode('utf-8'),hashlib.sha256).hexdigest()

params['signature'] = signature

url = 'https://api.binance.us/api/v3/order/test'
headers = {'X-MBX-APIKEY': settings.API_KEY}

data = urllib.parse.urlencode(params).encode('ascii')
req = urllib.request.Request(url,headers=headers)

response = urllib.request.urlopen(req)
response_str = response.read().decode('utf-8')
response_json = json.loads(response_str)

print(response_json)