区块键量化交易学习笔记(四)

火币官方的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版本签名步骤相似,具体区别如下:

  1. 生成参与签名的字符串时,请求方法固定使用GET,请求地址固定为/ws/v2

  2. 生成参与签名的固定参数名替换为:accessKey,signatureMethod,signatureVersion,timestamp

  3. signatureVersion版本升级为2.1

  4. 参数有变化详细实现代码修改如下(无数据压缩)

    #!/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)

     

你可能感兴趣的:(区块键量化交易学习笔记(四))