使用 Python 与 Binance API 进行交易的问题
Issues Placing a Trade with Binance API using Python
我正在尝试在不使用外部库的情况下在美国版 Binance API 上进行交易。
我可以使用 GET 请求和 urllib
成功获取价格并显示我的帐户余额。第一个示例代码有效,我可以毫无问题地传递我的 API_KEY
和 SECRET_KEY
(这些值是私有的,它们未在此处显示,位于 settings.py
)。
进行交易需要 POST,我不确定哪里出错了,我的 POST 请求不起作用,但 GET 请求可以正常工作。根据我对 docs 发出 POST 请求的理解,我应该使用 urllib.parse.urlencode()
对参数进行编码并将其传递到 urllib.request.Request()
中的 data
参数.
这样做不会引发错误,但是当我尝试使用 urllib.request.urlopen()
打开请求时,出现错误:
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
HTTP 5XX return codes are used for internal errors; the issue is on
Binance's side. It is important to NOT treat this as a failure
operation; the execution status is UNKNOWN and could have been a
success.
但是我不相信会是这样,因为我可以 运行 其他代码的函数 get_account_balance()
而不会出现问题。我不确定我做错了什么,除了发出 GET 与 POST 请求外,这两个代码几乎相同。
获取账户余额的代码 - 工作正常:
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, side, 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, urllib.parse.urlencode(params).encode('utf-8'), 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, data, 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', side='BUY', order_type='MARKET', quantity=1)
参考资料
-
-
-
-
-
示例中使用了此端点,但两个端点的功能相同且错误相同
我还查看了图书馆 python-binance
的例子
编辑
我可以使用 requests
库成功下单。我查看了库的源代码,但无法弄清楚如何使用 urllib
正确格式化 POST 请求
使用 requests
库进行交易的代码 - 有效:
import hmac
import time
import hashlib
import requests
import settings
import urllib.parse
session = requests.session()
session.headers.update({'X-MBX-APIKEY': settings.API_KEY})
url = 'https://api.binance.us/api/v3/order/test'
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
result = session.post(url, params)
print(result)
print(result.text)
问题出在以下几行:
# 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 请求
post 没有外部库的交易的工作代码:
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, data=data, headers=headers)
response = urllib.request.urlopen(req)
response_str = response.read().decode('utf-8')
response_json = json.loads(response_str)
print(response_json)
我正在尝试在不使用外部库的情况下在美国版 Binance API 上进行交易。
我可以使用 GET 请求和 urllib
成功获取价格并显示我的帐户余额。第一个示例代码有效,我可以毫无问题地传递我的 API_KEY
和 SECRET_KEY
(这些值是私有的,它们未在此处显示,位于 settings.py
)。
进行交易需要 POST,我不确定哪里出错了,我的 POST 请求不起作用,但 GET 请求可以正常工作。根据我对 docs 发出 POST 请求的理解,我应该使用 urllib.parse.urlencode()
对参数进行编码并将其传递到 urllib.request.Request()
中的 data
参数.
这样做不会引发错误,但是当我尝试使用 urllib.request.urlopen()
打开请求时,出现错误:
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
HTTP 5XX return codes are used for internal errors; the issue is on Binance's side. It is important to NOT treat this as a failure operation; the execution status is UNKNOWN and could have been a success.
但是我不相信会是这样,因为我可以 运行 其他代码的函数 get_account_balance()
而不会出现问题。我不确定我做错了什么,除了发出 GET 与 POST 请求外,这两个代码几乎相同。
获取账户余额的代码 - 工作正常:
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, side, 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, urllib.parse.urlencode(params).encode('utf-8'), 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, data, 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', side='BUY', order_type='MARKET', quantity=1)
参考资料
示例中使用了此端点,但两个端点的功能相同且错误相同
我还查看了图书馆 python-binance
的例子
编辑
我可以使用 requests
库成功下单。我查看了库的源代码,但无法弄清楚如何使用 urllib
使用 requests
库进行交易的代码 - 有效:
import hmac
import time
import hashlib
import requests
import settings
import urllib.parse
session = requests.session()
session.headers.update({'X-MBX-APIKEY': settings.API_KEY})
url = 'https://api.binance.us/api/v3/order/test'
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
result = session.post(url, params)
print(result)
print(result.text)
问题出在以下几行:
# 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
post 没有外部库的交易的工作代码:
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, data=data, headers=headers)
response = urllib.request.urlopen(req)
response_str = response.read().decode('utf-8')
response_json = json.loads(response_str)
print(response_json)