本节先从介绍基类开始讲起
上一节我们提到了我们需要设计一个基类OkexBaseClient
此处完全可以借鉴github上的一个人的实践,主要是为了封装一些基本的操作。
该类初始化的时候需要传入交易用的key和secret,最后的代理可以默认不传。
类里具体的方法主要是通过key进行签名,构造post的payload,封装get和post方法。除非api的方法大改版,短期内这个基类没有需要更改的地方。直接引用就行。
class OkexBaseClient (object):
def __init__(self, key, secret, proxies=None):
self.URL = "{0:s}://{1:s}/{2:s}".format(PROTOCOL, HOST, VERSION)
self.KEY = key
self.SECRET = secret
self.PROXIES = proxies
@property
def _nonce(self):
"""
Returns a nonce
Used in authentication
"""
return str(int(time.time() * 1000))
def _build_parameters(self, parameters):
# sort the keys so we can test easily in Python 3.3 (dicts are not
# ordered)
keys = list(parameters.keys())
keys.sort()
return '&'.join(["%s=%s" % (k, parameters[k]) for k in keys])
def url_for(self, path, path_arg=None, parameters=None):
url = "%s/%s" % (self.URL, path)
# If there is a path_arh, interpolate it into the URL.
# In this case the path that was provided will need to have string
# interpolation characters in it
if path_arg:
url = url % (path_arg)
# Append any parameters to the URL.
if parameters:
url = "%s?%s" % (url, self._build_parameters(parameters))
return url
def _sign_payload(self, payload):
sign = ''
for key in sorted(payload.keys()):
sign += key + '=' + str(payload[key]) +'&'
data = sign+'secret_key='+self.SECRET
return hashlib.md5(data.encode("utf8")).hexdigest().upper()
def _convert_to_floats(self, data):
"""
Convert all values in a dict to floats at first level
"""
for key, value in data.items():
data[key] = float(value)
return data
def _get(self, url, timeout=TIMEOUT):
req = requests.get(url, timeout=timeout, proxies=self.PROXIES)
if req.status_code/100 != 2:
logging.error(u"Failed to request:%s %d headers:%s", url, req.status_code, req.headers)
try:
return req.json()
except Exception as e:
logging.exception('Failed to GET:%s result:%s', url, req.text)
raise e
def _post(self, url, params=None, needsign=True, headers=None, timeout=TIMEOUT):
req_params = {'api_key' : self.KEY}
if params and needsign:
req_params.update(params)
req_params['sign'] = self._sign_payload(req_params)
req_headers = {
"Content-type" : "application/x-www-form-urlencoded",
}
if headers:
req_headers.update(headers)
logging.info("%s %s", req_headers, req_params)
req = requests.post(url, headers=req_headers, data=urllib.urlencode(req_params), timeout=TIMEOUT, proxies=self.PROXIES)
if req.status_code/100 != 2:
logging.error(u"Failed to request:%s %d headers:%s", url, req.status_code, req.headers)
try:
return req.json()
except Exception as e:
logging.exception('Failed to POST:%s result:%s', url, req.text)
raise e
基类封装好之后,我们就可以调用基类发送请求了。
#在前面先声明url的变量
PROTOCOL = "https"
HOST = "www.okex.com/api"
VERSION = "v1"
PATH_SYMBOLS = "symbols"
PATH_TICKER = "future_ticker.do" #获取OKEx合约行情
class OkexClient(OkexBaseClient):
"""
Client for the Okex.com API.
See https://www.okex.com/rest_api.html for API documentation.
"""
def ticker(self, symbol, contract_type):
return self._get(self.url_for(PATH_TICKER, parameters={'symbol' : symbol, 'contract_type' : contract_type}))
上述例子就是发送一个获取合约行情的示例,仅仅是一个简单的get请求,触发后就会通过get请求向服务器请求合约的行情,这个HTTP get请求的response就是我们想要的返回结果。
最简单的例子,我们将client.py写好之后,直接在命令行启动python,引入客户端,调用ticker方法,传参btc_usd,this_week,取当周合约的比特币的行情。
>>> from client import OkexClient
>>> client = OkexClient(None, None)
>>> client.ticker('btc_usd','this_week')
{u'date': u'1533958338', u'ticker': {u'sell': 6071.2, u'day_low': 0, u'buy': 6067.81, u'last': 6067.81, u'contract_id': 201808170000013, u'vol': 3116946, u'high': 6496.21, u'low': 5950, u'unit_amount': 100, u'coin_vol': 0, u'day_high': 0}}
我们返回结果就和api中预期的一致
{u’date’: u’1533958338’, u’ticker’: {u’sell’: 6071.2, u’day_low’: 0, u’buy’: 6067.81, u’last’: 6067.81, u’contract_id’: 201808170000013, u’vol’: 3116946, u’high’: 6496.21, u’low’: 5950, u’unit_amount’: 100, u’coin_vol’: 0, u’day_high’: 0}}
其中日期是Unix时间戳的格式,s为单位。1533958338就是2018/8/11 11:32:18。这个可以通过Python的时间函数处理,自己查的话推荐http://tool.chinaz.com/Tools/unixtime.aspx这个网址。
下一节我们实验怎么实现自动化