火币官方的HTTP_API:HuobiDMUtil.py HuobiDMService.py demo.py
参考说明:https://blog.csdn.net/uu564237933/article/details/100037850
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Date : 20180917
# @Author : zhaobo
# @github :
import base64
import hmac
import hashlib
import json
import urllib
import datetime
import requests
#import urlparse # urllib.parse in python 3
# timeout in 5 seconds:
TIMEOUT = 5
#各种请求,获取数据方式
def http_get_request(url, params, add_to_headers=None):
headers = {
"Content-type": "application/x-www-form-urlencoded",
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0'
}
if add_to_headers:
headers.update(add_to_headers)
postdata = urllib.parse.urlencode(params)
try:
response = requests.get(url, postdata, headers=headers, timeout=TIMEOUT)
if response.status_code == 200:
return response.json()
else:
return {"status":"fail"}
except Exception as e:
print("httpGet failed, detail is:%s" %e)
return {"status":"fail","msg": "%s"%e}
def http_post_request(url, params, add_to_headers=None):
headers = {
"Accept": "application/json",
'Content-Type': 'application/json',
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0'
}
if add_to_headers:
headers.update(add_to_headers)
postdata = json.dumps(params)
try:
response = requests.post(url, postdata, headers=headers, timeout=TIMEOUT)
if response.status_code == 200:
return response.json()
else:
return response.json()
except Exception as e:
print("httpPost failed, detail is:%s" % e)
return {"status":"fail","msg": "%s"%e}
def api_key_get(url, request_path, params, ACCESS_KEY, SECRET_KEY):
method = 'GET'
timestamp = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S')
params.update({'AccessKeyId': ACCESS_KEY,
'SignatureMethod': 'HmacSHA256',
'SignatureVersion': '2',
'Timestamp': timestamp})
host_name = host_url = url
#host_name = urlparse.urlparse(host_url).hostname
host_name = urllib.parse.urlparse(host_url).hostname
host_name = host_name.lower()
params['Signature'] = createSign(params, method, host_name, request_path, SECRET_KEY)
url = host_url + request_path
return http_get_request(url, params)
def api_key_post(url, request_path, params, ACCESS_KEY, SECRET_KEY):
method = 'POST'
timestamp = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S')
params_to_sign = {'AccessKeyId': ACCESS_KEY,
'SignatureMethod': 'HmacSHA256',
'SignatureVersion': '2',
'Timestamp': timestamp}
host_url = url
#host_name = urlparse.urlparse(host_url).hostname
host_name = urllib.parse.urlparse(host_url).hostname
host_name = host_name.lower()
params_to_sign['Signature'] = createSign(params_to_sign, method, host_name, request_path, SECRET_KEY)
url = host_url + request_path + '?' + urllib.parse.urlencode(params_to_sign)
return http_post_request(url, params)
def createSign(pParams, method, host_url, request_path, secret_key):
sorted_params = sorted(pParams.items(), key=lambda d: d[0], reverse=False)
encode_params = urllib.parse.urlencode(sorted_params)
payload = [method, host_url, request_path, encode_params]
payload = '\n'.join(payload)
payload = payload.encode(encoding='UTF8')
secret_key = secret_key.encode(encoding='UTF8')
digest = hmac.new(secret_key, payload, digestmod=hashlib.sha256).digest()
signature = base64.b64encode(digest)
signature = signature.decode()
return signature
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 20180917
# @Author : zhaobo
# @github :
from HuobiDMUtil import http_get_request, api_key_post
class HuobiDM:
def __init__(self,url,access_key,secret_key):
self.__url = url
self.__access_key = access_key
self.__secret_key = secret_key
'''
======================
Market data API
======================
'''
# 获取合约信息
def get_contract_info(self, symbol='', contract_type='', contract_code=''):
"""
参数名称 参数类型 必填 描述
symbol string false "BTC","ETH"...
contract_type string false 合约类型: this_week:当周 next_week:下周 quarter:季度
contract_code string false BTC181228
备注:如果contract_code填了值,那就按照contract_code去查询,如果contract_code 没有填值,则按照symbol+contract_type去查询
"""
params = {}
if symbol:
params['symbol'] = symbol
if contract_type:
params['contract_type'] = contract_type
if contract_code:
params['contract_code'] = contract_code
url = self.__url + '/api/v1/contract_contract_info'
return http_get_request(url, params)
# 获取合约指数信息
def get_contract_index(self, symbol):
"""
:symbol "BTC","ETH"...
"""
params = {'symbol': symbol}
url = self.__url + '/api/v1/contract_index'
return http_get_request(url, params)
# 获取合约最高限价和最低限价
def get_contract_price_limit(self, symbol='', contract_type='', contract_code=''):
"""
:symbol "BTC","ETH"...
:contract_type 合约类型: this_week:当周 next_week:下周 quarter:季度
"contract_code BTC180928
备注:如果contract_code填了值,那就按照contract_code去查询,如果contract_code 没有填值,则按照symbol+contract_type去查询
"""
params = {}
if symbol:
params['symbol'] = symbol
if contract_type:
params['contract_type'] = contract_type
if contract_code:
params['contract_code'] = contract_code
url = self.__url + '/api/v1/contract_price_limit'
return http_get_request(url, params)
# 获取当前可用合约总持仓量
def get_contract_open_interest(self, symbol='', contract_type='', contract_code=''):
"""
:symbol "BTC","ETH"...
:contract_type 合约类型: this_week:当周 next_week:下周 quarter:季度
"contract_code BTC180928
备注:如果contract_code填了值,那就按照contract_code去查询,如果contract_code 没有填值,则按照symbol+contract_type去查询
"""
params = {'symbol': symbol,
'contract_type': contract_type,
'contract_code': contract_code}
url = self.__url + '/api/v1/contract_open_interest'
return http_get_request(url, params)
# 获取行情深度
def get_contract_depth(self, symbol, type):
"""
:param symbol: BTC_CW, BTC_NW, BTC_CQ , ...
:param type: 可选值:{ step0, step1, step2, step3, step4, step5 (合并深度0-5);step0时,不合并深度 }
:return:
"""
params = {'symbol': symbol,
'type': type}
url = self.__url + '/market/depth'
return http_get_request(url, params)
# 获取KLine
def get_contract_kline(self, symbol, period, size=150):
"""
:param symbol BTC_CW, BTC_NW, BTC_CQ , ...
:param period: 可选值:{1min, 5min, 15min, 30min, 60min, 4hour, 1day, 1week, 1mon }
:param size: [1,2000]
:return:
"""
params = {'symbol': symbol,
'period': period}
if size:
params['size'] = size
url = self.__url + '/market/history/kline'
return http_get_request(url, params)
# 获取聚合行情
def get_contract_market_merged(self, symbol):
"""
:symbol "BTC_CW","BTC_NW", "BTC_CQ" ...
"""
params = {'symbol': symbol}
url = self.__url + '/market/detail/merged'
return http_get_request(url, params)
# 获取市场最近成交记录
def get_contract_trade(self, symbol, size=1):
"""
:param symbol: 可选值:{ BTC_CW, BTC_NW, BTC_CQ, etc. }
:return:
"""
params = {'symbol': symbol,
'size' : size}
url = self.__url + '/market/trade'
return http_get_request(url, params)
# 批量获取最近的交易记录
def get_contract_batch_trade(self, symbol, size=1):
"""
:param symbol: 可选值:{ BTC_CW, BTC_NW, BTC_CQ, etc. }, size: int
:return:
"""
params = {'symbol': symbol,
'size' : size}
url = self.__url + '/market/history/trade'
return http_get_request(url, params)
'''
======================
Trade/Account API
======================
'''
# 获取用户账户信息
def get_contract_account_info(self, symbol=''):
"""
:param symbol: "BTC","ETH"...如果缺省,默认返回所有品种
:return:
"""
params = {}
if symbol:
params["symbol"] = symbol
request_path = '/api/v1/contract_account_info'
return api_key_post(self.__url, request_path, params, self.__access_key, self.__secret_key)
# 获取用户持仓信息
def get_contract_position_info(self, symbol=''):
"""
:param symbol: "BTC","ETH"...如果缺省,默认返回所有品种
:return:
"""
params = {}
if symbol:
params["symbol"] = symbol
request_path = '/api/v1/contract_position_info'
return api_key_post(self.__url, request_path, params, self.__access_key, self.__secret_key)
# 合约下单
def send_contract_order(self, symbol, contract_type, contract_code,
client_order_id, price,volume,direction,offset,
lever_rate,order_price_type):
"""
:symbol: "BTC","ETH"..
:contract_type: "this_week", "next_week", "quarter"
:contract_code: "BTC181228"
:client_order_id: 客户自己填写和维护,这次一定要大于上一次
:price 必填 价格
:volume 必填 委托数量(张)
:direction 必填 "buy" "sell"
:offset 必填 "open", "close"
:lever_rate 必填 杠杆倍数
:order_price_type 必填 "limit"限价, "opponent" 对手价
备注:如果contract_code填了值,那就按照contract_code去下单,如果contract_code没有填值,则按照symbol+contract_type去下单。
:
"""
params = {"price": price,
"volume": volume,
"direction": direction,
"offset": offset,
"lever_rate": lever_rate,
"order_price_type": order_price_type}
if symbol:
params["symbol"] = symbol
if contract_type:
params['contract_type'] = contract_type
if contract_code:
params['contract_code'] = contract_code
if client_order_id:
params['client_order_id'] = client_order_id
request_path = '/api/v1/contract_order'
return api_key_post(self.__url, request_path, params, self.__access_key, self.__secret_key)
# 合约批量下单
def send_contract_batchorder(self, orders_data):
"""
orders_data: example:
orders_data = {'orders_data': [
{'symbol': 'BTC', 'contract_type': 'quarter',
'contract_code':'BTC181228', 'client_order_id':'',
'price':1, 'volume':1, 'direction':'buy', 'offset':'open',
'leverRate':20, 'orderPriceType':'limit'},
{'symbol': 'BTC','contract_type': 'quarter',
'contract_code':'BTC181228', 'client_order_id':'',
'price':2, 'volume':2, 'direction':'buy', 'offset':'open',
'leverRate':20, 'orderPriceType':'limit'}]}
Parameters of each order: refer to send_contract_order
"""
params = orders_data
request_path = '/api/v1/contract_batchorder'
return api_key_post(self.__url, request_path, params, self.__access_key, self.__secret_key)
# 撤销订单
def cancel_contract_order(self, symbol, order_id='', client_order_id=''):
"""
参数名称 是否必须 类型 描述
symbol true string BTC, ETH, ...
order_id false string 订单ID( 多个订单ID中间以","分隔,一次最多允许撤消50个订单 )
client_order_id false string 客户订单ID(多个订单ID中间以","分隔,一次最多允许撤消50个订单)
备注: order_id 和 client_order_id都可以用来撤单,同时只可以设置其中一种,如果设置了两种,默认以order_id来撤单。
"""
params = {"symbol": symbol}
if order_id:
params["order_id"] = order_id
if client_order_id:
params["client_order_id"] = client_order_id
request_path = '/api/v1/contract_cancel'
return api_key_post(self.__url, request_path, params, self.__access_key, self.__secret_key)
# 全部撤单
def cancel_all_contract_order(self, symbol):
"""
symbol: BTC, ETH, ...
"""
params = {"symbol": symbol}
request_path = '/api/v1/contract_cancelall'
return api_key_post(self.__url, request_path, params, self.__access_key, self.__secret_key)
# 获取合约订单信息
def get_contract_order_info(self, symbol, order_id='', client_order_id=''):
"""
参数名称 是否必须 类型 描述
symbol true string BTC, ETH, ...
order_id false string 订单ID( 多个订单ID中间以","分隔,一次最多允许查询20个订单 )
client_order_id false string 客户订单ID(多个订单ID中间以","分隔,一次最多允许查询20个订单)
备注:order_id和client_order_id都可以用来查询,同时只可以设置其中一种,如果设置了两种,默认以order_id来查询。
"""
params = {"symbol": symbol}
if order_id:
params["order_id"] = order_id
if client_order_id:
params["client_order_id"] = client_order_id
request_path = '/api/v1/contract_order_info'
return api_key_post(self.__url, request_path, params, self.__access_key, self.__secret_key)
# 获取合约订单明细信息
def get_contract_order_detail(self, symbol, order_id, order_type, created_at, page_index=None, page_size=None):
"""
参数名称 是否必须 类型 描述
symbol true string "BTC","ETH"...
order_id true long 订单id
order_type true int 订单类型。1:报单, 2:撤单, 3:爆仓, 4:交割
created_at true number 订单创建时间
page_index false int 第几页,不填第一页
page_size false int 不填默认20,不得多于50
"""
params = {"symbol": symbol,
"order_id": order_id,
"order_type": order_type,
"created_at": created_at}
if page_index:
params["page_index"] = page_index
if page_size:
params["page_size"] = page_size
request_path = '/api/v1/contract_order_detail'
return api_key_post(self.__url, request_path, params, self.__access_key, self.__secret_key)
# 获取合约当前未成交委托
def get_contract_open_orders(self, symbol=None, page_index=None, page_size=None):
"""
参数名称 是否必须 类型 描述
symbol false string "BTC","ETH"...
page_index false int 第几页,不填第一页
page_size false int 不填默认20,不得多于50
"""
params = {}
if symbol:
params["symbol"] = symbol
if page_index:
params["page_index"] = page_index
if page_size:
params["page_size"] = page_size
request_path = '/api/v1/contract_openorders'
return api_key_post(self.__url, request_path, params, self.__access_key, self.__secret_key)
# 获取合约历史委托
def get_contract_history_orders(self, symbol, trade_type, type, status, create_date,
page_index=None, page_size=None):
"""
参数名称 是否必须 类型 描述 取值范围
symbol true string 品种代码 "BTC","ETH"...
trade_type true int 交易类型 0:全部,1:买入开多,2: 卖出开空,3: 买入平空,4: 卖出平多,5: 卖出强平,6: 买入强平,7:交割平多,8: 交割平空
type true int 类型 1:所有订单、2:结束汏订单
status true int 订单状态 0:全部,3:未成交, 4: 部分成交,5: 部分成交已撤单,6: 全部成交,7:已撤单
create_date true int 日期 7,90(7天或者90天)
page_index false int 页码,不填默认第1页
page_size false int 不填默认20,不得多于50
"""
params = {"symbol": symbol,
"trade_type": trade_type,
"type": type,
"status": status,
"create_date": create_date}
if page_index:
params["page_index"] = page_index
if page_size:
params["page_size"] = page_size
request_path = '/api/v1/contract_hisorders'
return api_key_post(self.__url, request_path, params, self.__access_key, self.__secret_key)
from HuobiDMService import HuobiDM
from pprint import pprint
#### input huobi dm url
URL = ''
#### input your access_key and secret_key below:
ACCESS_KEY = ''
SECRET_KEY = ''
dm = HuobiDM(URL, ACCESS_KEY, SECRET_KEY)
#### another account:
#dm2 = HuobiDM(URL, "ANOTHER ACCOUNT's ACCESS_KEY", "ANOTHER ACCOUNT's SECRET_KEY")
#%% market data api ===============
print (u' 获取合约信息 ')
pprint (dm.get_contract_info(symbol="BTC", contract_type="quarter"))
pprint (dm.get_contract_info(contract_code="BTC181228"))
print (u' 获取合约指数信息 ')
pprint (dm.get_contract_index("BTC"))
print (u' 获取合约最高限价和最低限价 ')
pprint (dm.get_contract_price_limit(symbol='BTC', contract_type='quarter'))
pprint (dm.get_contract_price_limit(contract_code='BTC181228'))
print (u' 获取当前可用合约总持仓量 ')
pprint (dm.get_contract_open_interest(symbol='BTC', contract_type='quarter'))
pprint (dm.get_contract_open_interest(contract_code='BTC181228'))
print (u' 获取行情深度数据 ')
pprint (dm.get_contract_depth(symbol='BTC_CW', type='step0'))
print (u' 获取K线数据 ')
pprint (dm.get_contract_kline(symbol='BTC_CW', period='60min', size=20))
print (u' 获取聚合行情 ')
pprint (dm.get_contract_market_merged('BTC_CW'))
print (u' 获取市场最近成交记录 ')
pprint (dm.get_contract_trade('BTC_CW'))
print (u' 批量获取最近的交易记录 ')
pprint (dm.get_contract_batch_trade(symbol='BTC_CW', size=3))
#%% trade / account api ===============
print (u' 获取用户账户信息 ')
pprint (dm.get_contract_account_info())
pprint (dm.get_contract_account_info("BTC"))
print (u' 获取用户持仓信息 ')
pprint (dm.get_contract_position_info())
pprint (dm.get_contract_position_info("BTC"))
print (u' 合约下单 ')
pprint(dm.send_contract_order(symbol='', contract_type='', contract_code='BTC181228',
client_order_id='', price=10000, volume=1, direction='sell',
offset='open', lever_rate=5, order_price_type='limit'))
print (u' 合约批量下单 ')
orders_data = {'orders_data': [
{'symbol': 'BTC', 'contract_type': 'quarter',
'contract_code':'BTC181228', 'client_order_id':'',
'price':10000, 'volume':1, 'direction':'sell', 'offset':'open',
'leverRate':5, 'orderPriceType':'limit'},
{'symbol': 'BTC','contract_type': 'quarter',
'contract_code':'BTC181228', 'client_order_id':'',
'price':20000, 'volume':2, 'direction':'sell', 'offset':'open',
'leverRate':5, 'orderPriceType':'limit'}]}
pprint(dm.send_contract_batchorder(orders_data))
print (u' 撤销订单 ')
pprint(dm.cancel_contract_order(symbol='BTC', order_id='42652161'))
print (u' 全部撤单 ')
pprint(dm.cancel_all_contract_order(symbol='BTC'))
print (u' 获取合约订单信息 ')
pprint(dm.get_contract_order_info(symbol='BTC', order_id='42652161'))
print (u' 获取合约订单明细信息 ')
pprint(dm.get_contract_order_detail(symbol='BTC', order_id='42652161', order_type=1, created_at=1542097630215))
print (u' 获取合约当前未成交委托 ')
pprint(dm.get_contract_open_orders(symbol='BTC'))
print (u' 获取合约历史委托 ')
pprint (dm.get_contract_history_orders(symbol='BTC', trade_type=0, type=1, status=0, create_date=7))
WebSocket API(现货)
#!/usr/bin/env python
import datetime
import uuid
import urllib
import asyncio
import websockets
import json
import hmac
import base64
import hashlib
import gzip
import traceback
def generate_signature(host, method, params, request_path, secret_key):
"""Generate signature of huobi future.
Args:
host: api domain url.PS: colo user should set this host as 'api.hbdm.com',not colo domain.
method: request method.
params: request params.
request_path: "/notification"
secret_key: api secret_key
Returns:
singature string.
"""
host_url = urllib.parse.urlparse(host).hostname.lower()
sorted_params = sorted(params.items(), key=lambda d: d[0], reverse=False)
encode_params = urllib.parse.urlencode(sorted_params)
payload = [method, host_url, request_path, encode_params]
payload = "\n".join(payload)
payload = payload.encode(encoding="UTF8")
secret_key = secret_key.encode(encoding="utf8")
digest = hmac.new(secret_key, payload, digestmod=hashlib.sha256).digest()
signature = base64.b64encode(digest)
signature = signature.decode()
return signature
async def subscribe(url, access_key, secret_key, subs, callback=None, auth=False):
""" Huobi Future subscribe websockets.
Args:
url: the url to be signatured.
access_key: API access_key.
secret_key: API secret_key.
subs: the data list to subscribe.
callback: the callback function to handle the ws data received.
auth: True: Need to be signatured. False: No need to be signatured.
"""
async with websockets.connect(url) as websocket:
if auth:
timestamp = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S")
data = {
"AccessKeyId": access_key,
"SignatureMethod": "HmacSHA256",
"SignatureVersion": "2",
"Timestamp": timestamp
}
sign = generate_signature(url, "GET", data, "/ws/v1", secret_key)
data["op"] = "auth"
data["type"] = "api"
data["Signature"] = sign
msg_str = json.dumps(data)
await websocket.send(msg_str)
print(f"send: {msg_str}")
for sub in subs:
sub_str = json.dumps(sub)
await websocket.send(sub_str)
print(f"send: {sub_str}")
while True:
rsp = await websocket.recv()
data = json.loads(gzip.decompress(rsp).decode())
# print(f"recevie<--: {data}")
if "op" in data and data.get("op") == "ping":
pong_msg = {"op": "pong", "ts": data.get("ts")}
await websocket.send(json.dumps(pong_msg))
print(f"send: {pong_msg}")
continue
if "ping" in data:
pong_msg = {"pong": data.get("ping")}
await websocket.send(json.dumps(pong_msg))
print(f"send: {pong_msg}")
continue
rsp = await callback(data)
async def handle_ws_data(*args, **kwargs):
""" callback function
Args:
args: values
kwargs: key-values.
"""
print("callback param", *args, **kwargs)
if __name__ == "__main__":
#### input your access_key and secret_key below:
access_key = ""
secret_key = ""
market_url = 'wss://api.huobi.de.com/ws'
order_url = 'wss://api.huobi.de.com/ws/v1'
market_subs = [
{
"sub": "market.btcusdt.kline.1min",
"id": str(uuid.uuid1())
},
{
"sub": "market.btcusdt.depth.step6",
"id": str(uuid.uuid1())
},
{
"sub": "market.btcusdt.detail",
"id": str(uuid.uuid1())
}
]
order_subs = [
{
"op": "sub",
"cid": str(uuid.uuid1()),
"topic": "orders.btcusdt.update"
},
{
"op": "req",
"cid": str(uuid.uuid1()),
"topic": "accounts.list"
},
{
"op": "sub",
"cid": str(uuid.uuid1()),
"topic": "accounts"
}
]
while True:
try:
# asyncio.get_event_loop().run_until_complete(subscribe(market_url, access_key, secret_key, market_subs, handle_ws_data, auth=False))
asyncio.get_event_loop().run_until_complete(subscribe(order_url, access_key, secret_key, order_subs, handle_ws_data, auth=True))
# except (websockets.exceptions.ConnectionClosed):
except Exception as e:
traceback.print_exc()
print('websocket connection error. reconnect rightnow')
# -*- coding: utf-8 -*-
from websocket import create_connection
import gzip
import time
if __name__ == '__main__':
while(1):
try:
ws = create_connection("wss://www.hbdm.com/ws")
break
except:
print('connect ws error,retry...')
time.sleep(5)
# 订阅 KLine 数据
tradeStr_kline="""
{"sub": "market.BTC_CQ.kline.1min", "id": "id1"}
"""
# 订阅 Market Detail 数据
tradeStr_marketDetail="""
{"sub": "market.BTC_CQ.detail", "id": "id6" }
"""
# 订阅 Trade Detail 数据
tradeStr_tradeDetail="""
{"sub": "market.BTC_CQ.trade.detail", "id": "id7"}
"""
# 请求 KLine 数据
tradeStr_klinereq="""
{"req": "market.BTC_CQ.kline.1min", "id": "id4"}
"""
# 请求 Trade Detail 数据
tradeStr_tradeDetail_req="""
{"req": "market.BTC_CQ.trade.detail", "id": "id5"}
"""
# 订阅 Market Depth 数据
tradeStr_marketDepth="""
{
"sub": "market.BTC_CQ.depth.step0", "id": "id9"
}
"""
ws.send(tradeStr_marketDepth)
trade_id = ''
while(1):
compressData=ws.recv()
result=gzip.decompress(compressData).decode('utf-8')
if result[:7] == '{"ping"':
ts=result[8:21]
pong='{"pong":'+ts+'}'
ws.send(pong)
ws.send(tradeStr_kline)
else:
try:
if trade_id == result['data']['id']:
print('重复的id')
break
else:
trade_id = result['data']['id']
except Exception:
pass
print(result)
Websocket资产及订单(v2)
v2.1版本签名与v2.0版本签名步骤相似,具体区别如下:
生成参与签名的字符串时,请求方法固定使用GET,请求地址固定为/ws/v2
生成参与签名的固定参数名替换为:accessKey,signatureMethod,signatureVersion,timestamp
signatureVersion版本升级为2.1
参数有变化详细实现代码修改如下(无数据压缩)
#!/usr/bin/env python
import datetime
import uuid
import urllib
import asyncio
import websockets
import json
import hmac
import base64
import hashlib
import traceback
def generate_signature(host, method, params, request_path, secret_key):
"""Generate signature of huobi future.
Args:
host: api domain url.PS: colo user should set this host as 'api.hbdm.com',not colo domain.
method: request method.
params: request params.
request_path: "/notification"
secret_key: api secret_key
Returns:
singature string.
"""
host_url = urllib.parse.urlparse(host).hostname.lower()
sorted_params = sorted(params.items(), key=lambda d: d[0], reverse=False)
encode_params = urllib.parse.urlencode(sorted_params)
payload = [method, host_url, request_path, encode_params]
payload = "\n".join(payload)
payload = payload.encode(encoding="UTF8")
secret_key = secret_key.encode(encoding="utf8")
digest = hmac.new(secret_key, payload, digestmod=hashlib.sha256).digest()
signature = base64.b64encode(digest)
signature = signature.decode()
return signature
async def subscribe(url, access_key, secret_key, subs, callback=None, auth=False):
""" Huobi Future subscribe websockets.
Args:
url: the url to be signatured.
access_key: API access_key.
secret_key: API secret_key.
subs: the data list to subscribe.
callback: the callback function to handle the ws data received.
auth: True: Need to be signatured. False: No need to be signatured.
"""
async with websockets.connect(url) as websocket:
if auth:
timestamp = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S")
data = {
"accessKey": access_key,
"signatureMethod": "HmacSHA256",
"signatureVersion": "2.1",
"timestamp": timestamp
}
sign = generate_signature(url, "GET", data, "/ws/v2", secret_key)
data["authType"] = "api"
data["signature"] = sign
params = {
'action': 'req',
'ch': 'auth',
'params': data
}
msg_str = json.dumps(params)
await websocket.send(msg_str)
print(f"send: {msg_str}")
for sub in subs:
sub_str = json.dumps(sub)
await websocket.send(sub_str)
print(f"send: {sub_str}")
while True:
rsp = await websocket.recv()
# print(f"recevie-->: {rsp}")
data = json.loads(rsp)
if "action" in data and data.get("action") == "ping":
pong_msg = {"action": "pong", "ts": data['data'].get("ts")}
await websocket.send(json.dumps(pong_msg))
print(f"send: {pong_msg}")
continue
if "ping" in data:
pong_msg = {"pong": data.get("ping")}
await websocket.send(json.dumps(pong_msg))
print(f"send: {pong_msg}")
continue
rsp = await callback(data)
async def handle_ws_data(*args, **kwargs):
""" callback function
Args:
args: values
kwargs: key-values.
"""
print("callback param", *args, **kwargs)
if __name__ == "__main__":
#### input your access_key and secret_key below:
access_key = ""
secret_key = ""
market_url = 'wss://api.huobi.de.com/ws'
order_url = 'wss://api.huobi.de.com/ws/v2'
market_subs = [
{
"sub": "market.btcusdt.kline.1min",
"id": str(uuid.uuid1())
},
{
"sub": "market.btcusdt.depth.step6",
"id": str(uuid.uuid1())
},
{
"sub": "market.btcusdt.detail",
"id": str(uuid.uuid1())
}
]
order_subs = [
{
"action": "sub",
"ch": "trade.clearing#ethusdt"
},
{
"action": "sub",
"ch": "accounts.update"
}
]
while True:
try:
# asyncio.get_event_loop().run_until_complete(subscribe(market_url, access_key, secret_key, market_subs, handle_ws_data, auth=False))
asyncio.get_event_loop().run_until_complete(subscribe(order_url, access_key, secret_key, order_subs, handle_ws_data, auth=True))
# except (websockets.exceptions.ConnectionClosed):
except Exception as e:
traceback.print_exc()
print('websocket connection error. reconnect rightnow')
BitMex(签名)
import time, urllib, hmac, hashlib
def generate_nonce():
return int(round(time.time() + 3600))
# Generates an API signature.
# A signature is HMAC_SHA256(secret, verb + path + nonce + data), hex encoded.
# Verb must be uppercased, url is relative, nonce must be an increasing 64-bit integer
# and the data, if present, must be JSON without whitespace between keys.
#
# For example, in psuedocode (and in real code below):
#
# verb=POST
# url=/api/v1/order
# nonce=1416993995705
# data={"symbol":"XBTZ14","quantity":1,"price":395.01}
# signature = HEX(HMAC_SHA256(secret, 'POST/api/v1/order1416993995705{"symbol":"XBTZ14","quantity":1,"price":395.01}'))
def generate_signature(secret, verb, url, nonce, data):
"""Generate a request signature compatible with BitMEX."""
# Parse the url so we can remove the base and extract just the path.
parsedURL = urllib.parse.urlparse(url)
path = parsedURL.path
if parsedURL.query:
path = path + '?' + parsedURL.query
# print "Computing HMAC: %s" % verb + path + str(nonce) + data
message = (verb + path + str(nonce) + data).encode('utf-8')
signature = hmac.new(secret.encode('utf-8'), message, digestmod=hashlib.sha256).hexdigest()
return signature
火币(签名)
import base64
import hashlib
import hmac
import datetime
from urllib import parse
import urllib.parse
import json
def print_builder(builder):
print("params in builder", builder.param_map)
print("params in builder build_urls", builder.build_url())
class UrlParamsBuilder(object):
def __init__(self):
self.param_map = dict()
self.post_map = dict()
def put_url(self, name, value):
if value is not None:
if isinstance(value, list):
self.param_map[name] = value
else:
self.param_map[name] = str(value)
def put_post(self, name, value):
if value is not None:
if isinstance(value, list):
self.post_map[name] = value
else:
self.post_map[name] = str(value)
def build_url(self):
if len(self.param_map) == 0:
return ""
encoded_param = urllib.parse.urlencode(self.param_map)
return "?" + encoded_param
def build_url_to_json(self):
return json.dumps(self.param_map)
def create_signature(api_key, secret_key, method, url, builder):
ret = {
"code" : 0,
"message" : ""
}
if api_key is None or secret_key is None or api_key == "" or secret_key == "":
ret["code"] = -1
ret["message"] = "API key and secret key are required"
return ret
timestamp = utc_now()
builder.put_url("AccessKeyId", api_key)
builder.put_url("SignatureVersion", "2")
builder.put_url("SignatureMethod", "HmacSHA256")
builder.put_url("Timestamp", timestamp)
host = urllib.parse.urlparse(url).hostname
path = urllib.parse.urlparse(url).path
# 对参数进行排序:
keys = sorted(builder.param_map.keys())
# 加入&
qs0 = '&'.join(['%s=%s' % (key, parse.quote(builder.param_map[key], safe='')) for key in keys])
# 请求方法,域名,路径,参数 后加入`\n`
payload0 = '%s\n%s\n%s\n%s' % (method, host, path, qs0)
dig = hmac.new(secret_key.encode('utf-8'), msg=payload0.encode('utf-8'), digestmod=hashlib.sha256).digest()
# 进行base64编码
s = base64.b64encode(dig).decode()
builder.put_url("Signature", s)
return ret
def utc_now():
return datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S')
if __name__ == "__main__":
api_key_test = "api_key_xxxxxxx"
secret_key_test = "secret_key_xxxxxxx"
method_test = "GET"
url_test = "www.huobi.pro"
builder = UrlParamsBuilder()
builder.put_url("symbol", "usdtbtc")
builder.put_url("types", "market,limit,margin")
create_signature(api_key=api_key_test, secret_key=secret_key_test, method=method_test, url=url_test, builder=builder)
print_builder(builder)