#!/usr/bin/python
# -*- coding: utf-8 -*-
import json, datetime, hmac, base64, zlib, threading, requests, time
from common.Common import Common
from common.WebSocketProtocol import WebSocketProtocol
from retrying import retry
CONTENT_TYPE = 'Content-Type'
OK_ACCESS_KEY = 'OK-ACCESS-KEY'
OK_ACCESS_SIGN = 'OK-ACCESS-SIGN'
OK_ACCESS_TIMESTAMP = 'OK-ACCESS-TIMESTAMP'
OK_ACCESS_PASSPHRASE = 'OK-ACCESS-PASSPHRASE'
APPLICATION_JSON = 'application/json'
BASE_URL = 'https://www.okex.com'
BASE_DEBUG_URL = 'https://www.okex.me'
WS_URL = 'wss://real.okex.com:8443/ws/v3'
API_KEY = ''
SECRET_KEY = ''
PASS_PHRASE = ''
class OkAPI:
def __init__(self, client):
self.client = client
self.__baseUrl = BASE_URL if RUN_MODE == ConstantUtil.LIVING else BASE_DEBUG_URL
self.__apikey = API_KEY
self.__secretkey = SECRET_KEY
self.__passphrase = PASS_PHRASE
self.__sub = None
self.__ws_subs = dict()
self.__direct = None
def get_header(self, api_key, sign, timestamp, passphrase):
header = dict()
header[CONTENT_TYPE] = APPLICATION_JSON
header[OK_ACCESS_KEY] = api_key
header[OK_ACCESS_SIGN] = sign
header[OK_ACCESS_TIMESTAMP] = str(timestamp)
header[OK_ACCESS_PASSPHRASE] = passphrase
return header
def parse_params_to_str(seff, params):
url = '?'
for key, value in params.items():
url = url + str(key) + '=' + str(value) + '&'
return url[0:-1]
def timestamp(self):
timestamp = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%f')
timestamp = timestamp[0:-3] + 'Z'
return timestamp
def transfer(self, coin, fund, amount):
path = '/api/account/v3/transfer'
params = {'currency': fund, 'amount': amount, 'from': '1', 'to': '5',
'instrument_id': '{}-{}'.format(coin, fund)}
return self.httpPost(path, params)
# -----------------------------交割合约api-----------------------------
def f_ticker(self, coin):
path = '/api/futures/v3/instruments/{}/ticker'.format(coin)
return self.httpGet(path)
def f_depth(self, coin):
path = '/api/futures/v3/instruments/{}/book'.format(coin)
params = {'instrument_id': coin, 'size': 10}
return self.httpGet(path, params)
def f_position(self, pair=None):
path = '/api/futures/v3/{}/position'.format(pair) if pair else '/api/futures/v3/position'
return self.httpGet(path)
def f_coin_pair(self):
path = '/api/futures/v3/instruments'
return self.httpGet(path)
def f_trade(self, coin, side, price, amount, client_oid=''):
path = '/api/futures/v3/order'
params = {'instrument_id': coin, 'type': side, 'price': price, 'size': amount, 'match_price': '0',
'client_oid': client_oid}
return self.httpPost(path, params)
def f_kline(self, coin, interval, end=''):
path = '/api/futures/v3/instruments/{}/candles'.format(coin)
params = {'granularity': interval, 'end': end}
return self.httpGet(path, params)
def f_account(self, coin):
path = '/api/futures/v3/accounts/{}'.format(coin)
return self.httpGet(path)
def f_cancel_order(self, coin, client_oid):
path = '/api/futures/v3/cancel_order/{}/{}'.format(coin, client_oid)
params = {'instrument_id': coin, 'client_oid': client_oid}
return self.httpPost(path, params)
# -----------------------------永续合约api-----------------------------
def sf_ticker(self, coin):
path = '/api/swap/v3/instruments/{}/ticker'.format(coin)
return self.httpGet(path)
def sf_position(self, pair=None):
path = '/api/swap/v3/{}/position'.format(pair) if pair else '/api/swap/v3/position'
return self.httpGet(path)
def sf_trade(self, coin, side, price, amount, client_oid=''):
path = '/api/swap/v3/order'
params = {'instrument_id': coin, 'type': side, 'price': price, 'size': amount, 'match_price': '0',
'client_oid': client_oid}
return self.httpPost(path, params)
def sf_kline(self, coin, interval, end=''):
path = '/api/swap/v3/instruments/{}/candles'.format(coin)
params = {'granularity': interval, 'end': end}
return self.httpGet(path, params)
def sf_cancel_order(self, coin, client_oid):
path = '/api/swap/v3/cancel_order/{}/{}'.format(coin, client_oid)
params = {'instrument_id': coin, 'client_oid': client_oid}
return self.httpPost(path, params)
# -----------------------------币币api-----------------------------
def ticker(self, coin):
path = '/api/spot/v3/instruments/{}/ticker'.format(coin)
return self.httpGet(path)
def tickers(self):
path = '/api/spot/v3/instruments/ticker'
return self.httpGet(path)
def coin_pair(self):
path = '/api/spot/v3/instruments'
return self.httpGet(path)
def trade(self, side, coin, price, amount):
path = '/api/spot/v3/orders'
params = {'type': 'limit', 'side': side, 'instrument_id': coin, 'size': amount, 'price': price,
'margin_trading': 1}
return self.httpPost(path, params)
def order(self, coin, orderid):
path = '/api/spot/v3/orders/' + orderid
params = {'instrument_id': coin}
return self.httpGet(path, params)
def orders(self):
path = '/api/spot/v3/orders_pending'
return self.httpGet(path)
def kline(self, coin, interval, start='', end=''):
path = '/api/spot/v3/instruments/{}/candles'.format(coin)
params = {'granularity': interval, 'start': start, 'end': end}
return self.httpGet(path, params)
def account(self, coin):
path = '/api/spot/v3/accounts/' + coin
return self.httpGet(path)
def cancelOrder(self, coin, orderid):
path = '/api/spot/v3/cancel_orders/' + orderid
params = {'instrument_id': coin}
return self.httpPost(path, params)
# -----------------------------币币杠杆api-----------------------------
def l_trade(self, side, coin, price, amount):
path = '/api/margin/v3/orders'
params = {'type': 'limit', 'side': side, 'instrument_id': coin, 'size': amount, 'price': price,
'margin_trading': 2}
return self.httpPost(path, params)
def l_borrow(self, coin, currency, amount):
path = '/api/margin/v3/accounts/borrow'
params = {'instrument_id': coin, 'currency': currency, 'amount': amount}
return self.httpPost(path, params)
def l_borrowed(self, coin, status=0):
path = '/api/margin/v3/accounts/{}/borrowed'.format(coin)
params = {'status': status}
return self.httpGet(path, params)
def l_repay(self, coin, currency, amount, borrow_id=None):
path = '/api/margin/v3/accounts/repayment'
params = {'instrument_id': coin, 'currency': currency, 'amount': str(amount)}
if borrow_id:
params['borrow_id'] = borrow_id
return self.httpPost(path, params)
def l_order(self, coin, orderid):
path = '/api/margin/v3/orders/' + orderid
params = {'instrument_id': coin}
return self.httpGet(path, params)
def l_accounts(self):
path = '/api/margin/v3/accounts'
return self.httpGet(path)
def l_account(self, coin):
path = '/api/margin/v3/accounts/' + coin
return self.httpGet(path)
def l_availability(self, coin):
path = '/api/margin/v3/accounts/{}/availability'.format(coin)
return self.httpGet(path)
def l_cancelOrder(self, coin, orderid):
path = '/api/margin/v3/cancel_orders/' + orderid
params = {'instrument_id': coin, 'order_id': orderid}
return self.httpPost(path, params)
def signature(self, timestamp, method, request_path, body, secret_key):
if str(body) == '{}' or str(body) == 'None':
body = ''
message = str(timestamp) + str.upper(method) + request_path + str(body)
mac = hmac.new(bytes(secret_key, encoding='utf8'), bytes(message, encoding='utf-8'), digestmod='sha256')
d = mac.digest()
return base64.b64encode(d)
@retry(stop_max_attempt_number=3)
def httpGet(self, path, data=None):
if data:
path = path + self.parse_params_to_str(data)
url = self.__baseUrl + path
timestamp = self.timestamp()
header = self.get_header(self.__apikey, self.signature(timestamp, 'GET', path, '', self.__secretkey),
timestamp, self.__passphrase)
try:
response = requests.get(url, headers=header, timeout=15)
except Exception as e:
raise Exception(e)
return response.json()
@retry(stop_max_attempt_number=3)
def httpPost(self, path, data):
url = self.__baseUrl + path
body = json.dumps(data)
timestamp = self.timestamp()
header = self.get_header(self.__apikey, self.signature(timestamp, 'POST', path, body, self.__secretkey),
timestamp, self.__passphrase)
try:
response = requests.post(url, data=body, headers=header)
except Exception as e:
raise Exception(e)
return response.json()
def httpDelete(self, path, data):
if data: path = path + self.parse_params_to_str(data)
url = self.__baseUrl + path
timestamp = self.timestamp()
header = self.get_header(self.__apikey, self.signature(timestamp, 'DELETE', path, '', self.__secretkey),
timestamp, self.__passphrase)
try:
response = requests.delete(url, headers=header)
except Exception as e:
raise Exception(e)
return response.json()
def inflate(self, data):
decompress = zlib.decompressobj(
-zlib.MAX_WBITS # see above
)
inflated = decompress.decompress(data)
inflated += decompress.flush()
return inflated
def on_open(self, ws):
print('ok_on_open', self.__ws_subs)
if not ConstantUtil.is_analyze:
ts = str(int(datetime.datetime.now().timestamp()))
sign = self.signature(ts, 'GET', '/users/self/verify', None, self.__secretkey)
sub = {'op': 'login', 'args': [self.__apikey, self.__passphrase, ts, sign.decode("utf-8")]}
ws.send(json.dumps(sub))
time.sleep(1)
s = []
for p_k, p_v in self.__ws_subs.items():
for k, v in p_v.items():
if k == ConstantUtil.ws_ticker:
s.append('spot/ticker:{}'.format(p_k))
elif k == ConstantUtil.ws_kline:
s.append('spot/candle{}s:{}'.format(v, p_k))
elif k == ConstantUtil.ws_trade:
s.append('spot/trade:{}'.format(p_k))
elif k == ConstantUtil.ws_f_ticker:
s.append('futures/ticker:{}'.format(p_k))
elif k == ConstantUtil.ws_f_kline:
for k_v in v:
s.append('futures/candle{}s:{}'.format(k_v, p_k))
elif k == ConstantUtil.ws_sf_ticker:
s.append('swap/ticker:{}'.format(p_k))
elif k == ConstantUtil.ws_sf_kline:
for k_v in v:
s.append('swap/candle{}s:{}'.format(k_v, p_k))
ws.send(json.dumps({'op': 'subscribe', 'args': s}))
def on_message(self, ws, message):
data = json.loads(self.inflate(message))
if 'table' in data:
table = data['table']
if table.find('spot/ticker') != -1:
if self.__direct:
self.client.d_ws_ticker(data['data'])
else:
self.client.ws_ticker(data['data'])
elif table.find('futures/ticker') != -1:
self.client.ws_f_ticker(data['data'])
elif table.find('spot/candle') != -1:
self.client.ws_kline(data)
elif table.find('futures/candle') != -1:
self.client.ws_f_kline(data)
elif table.find('swap/candle') != -1:
self.client.ws_sf_kline(data)
elif table.find('spot/trade') != -1:
if self.__direct:
self.client.d_ws_trade(data['data'])
else:
self.client.ws_trade(data['data'])
elif table.find('spot/account') != -1:
if self.__direct:
self.client.d_ws_account(data['data'])
else:
self.client.ws_account(data['data'])
elif table.find('spot/margin_account') != -1:
self.client.ws_l_account(data['data'])
elif table.find('futures/account') != -1:
self.client.ws_f_account(data['data'])
elif table.find('swap/account') != -1:
self.client.ws_sf_account(data['data'])
elif table.find('spot/order') != -1:
if self.__direct:
self.client.d_ws_order(data['data'])
else:
self.client.ws_order(data['data'])
elif table.find('futures/order') != -1:
self.client.ws_f_order(data['data'])
elif table.find('swap/order') != -1:
self.client.ws_sf_order(data['data'])
elif table.find('futures/position') != -1:
self.client.ws_f_position(data['data'])
elif table.find('swap/position') != -1:
self.client.ws_sf_position(data['data'])
elif table.find('depth') != -1:
self.client.ws_depth(data['data'])
elif table.find('depth5') != -1:
pass
elif 'event' in data:
print(data)
if data['event'] == 'login':
s = []
for p_k, p_v in self.__ws_subs.items():
for k, v in p_v.items():
if k == ConstantUtil.ws_order:
s.append('spot/order:{}'.format(p_k))
elif k == ConstantUtil.ws_account:
c, f = p_k.split('-')
s.extend(['spot/account:{}'.format(c), 'spot/account:{}'.format(f)])
elif k == ConstantUtil.ws_l_account:
s.append('spot/margin_account:{}'.format(p_k))
elif k == ConstantUtil.ws_f_account:
s.append('futures/account:{}'.format(p_k.split('-')[0]))
elif k == ConstantUtil.ws_f_order:
s.append('futures/order:{}'.format(p_k))
elif k == ConstantUtil.ws_f_position:
s.append('futures/position:{}'.format(p_k))
elif k == ConstantUtil.ws_sf_account:
s.append('swap/account:{}'.format(p_k.split('-')[0]))
elif k == ConstantUtil.ws_sf_order:
s.append('swap/order:{}'.format(p_k))
elif k == ConstantUtil.ws_sf_position:
s.append('swap/position:{}'.format(p_k))
ws.send(json.dumps({'op': 'subscribe', 'args': s}))
def on_close(self, ws):
print('ok_on_close', ws, self.__ws_subs)
self.__sub = None
if len(self.__ws_subs) > 0:
time.sleep(1)
self.__ws_sub_create()
def ws_sub(self, pair, subs):
s = []
for k, v in subs.items():
if pair in self.__ws_subs.keys():
if k in self.__ws_subs[pair].keys():
if k == ConstantUtil.ws_f_kline and self.__ws_subs[pair][k] != v:
self.__ws_subs[pair][k].extend(v)
s.append(k)
continue
else:
self.__ws_subs[pair][k] = v
s.append(k)
else:
self.__ws_subs[pair] = {k: v}
s.append(k)
if self.__sub:
w_s = []
for k in s:
if k == ConstantUtil.ws_ticker:
w_s.append('spot/ticker:{}'.format(pair))
elif k == ConstantUtil.ws_trade:
w_s.append('spot/trade:{}'.format(pair))
elif k == ConstantUtil.ws_kline:
w_s.append('spot/candle{}s:{}'.format(subs[k], pair))
elif k == ConstantUtil.ws_order:
w_s.append('spot/order:{}'.format(pair))
elif k == ConstantUtil.ws_account:
c, f = pair.split('-')
w_s.extend(['spot/account:{}'.format(c), 'spot/account:{}'.format(f)])
elif k == ConstantUtil.ws_l_account:
w_s.append('spot/margin_account:{}'.format(pair))
elif k == ConstantUtil.ws_f_ticker:
w_s.append('futures/ticker:{}'.format(pair))
elif k == ConstantUtil.ws_f_kline:
for k_v in subs[k]:
w_s.append('futures/candle{}s:{}'.format(k_v, pair))
elif k == ConstantUtil.ws_f_account:
w_s.append('futures/account:{}'.format(pair.split('-')[0]))
elif k == ConstantUtil.ws_f_position:
w_s.append('futures/position:{}'.format(pair))
elif k == ConstantUtil.ws_f_order:
w_s.append('futures/order:{}'.format(pair))
elif k == ConstantUtil.ws_sf_ticker:
w_s.append('swap/ticker:{}'.format(pair))
elif k == ConstantUtil.ws_sf_kline:
for k_v in subs[k]:
w_s.append('swap/candle{}s:{}'.format(k_v, pair))
elif k == ConstantUtil.ws_sf_account:
w_s.append('swap/account:{}'.format(pair.split('-')[0]))
elif k == ConstantUtil.ws_sf_position:
w_s.append('swap/position:{}'.format(pair))
elif k == ConstantUtil.ws_sf_order:
w_s.append('swap/order:{}'.format(pair))
self.__sub.send(json.dumps({'op': 'subscribe', 'args': w_s}))
else:
# threading.stack_size(1024 * 1024 * 100)
t = threading.Thread(target=self.__ws_sub_create)
t.start()
def d_ws_sub(self, coins, subs):
self.__direct = 1
subs.update({ConstantUtil.ws_order: ''})
for i in coins:
pair = i.replace('_', '-')
self.__ws_subs[pair] = subs
t = threading.Thread(target=self.__ws_sub_create)
t.start()
def ws_unsub(self, pair, subs):
exist_subs = self.__ws_subs[pair]
s = []
for k, v in subs.items():
exist_subs.pop(k)
if k == ConstantUtil.ws_ticker:
s.append('spot/ticker:{}'.format(pair))
if k == ConstantUtil.ws_trade:
s.append('spot/trade:{}'.format(pair))
elif k == ConstantUtil.ws_kline:
s.append('spot/candle{}s:{}'.format(v, pair))
self.__sub.send(json.dumps({'op': 'unsubscribe', 'args': s}))
if len(exist_subs) == 0:
self.__ws_subs.pop(pair)
if len(self.__ws_subs) == 0:
self.__sub.close()
# self.__sub.close_connection()
def __ws_sub_create(self):
try:
self.__sub = WebSocketProtocol(WS_URL, self.on_open, self.on_message, self.on_close)
self.__sub.connect()
self.__sub.run_forever(ping_interval=25)
except Exception as e:
print('异常了--ok--__ws_sub_create', e)
time.sleep(5)
self.__ws_sub_create()
from ws4py.client.threadedclient import WebSocketClient
import threading
class WebSocketProtocol(WebSocketClient):
def __init__(self,url,on_open,on_message,on_closed):
super().__init__(url)
self._ping_interval = None
self._event = None
self._flag = None
self.on_open = on_open
self.on_message = on_message
self.on_closed = on_closed
self.on_ping = None
def _send_ping(self):
while self._flag:
if not self._event.wait(self._ping_interval):
if self.on_ping:
self.on_ping(self)
else:
self.ping('ping')
else:
self._event.clear()
def opened(self):
self.on_open(self)
if self._ping_interval:
thread = threading.Thread(target=self._send_ping)
thread.setDaemon(True)
thread.start()
def received_message(self, message):
if self._ping_interval:
self._event.set()
self.on_message(self,message.data)
def closed(self, code, reason=None):
if self._ping_interval:
self._flag = False
self._event.set()
self.on_closed(self)
def ponged(self, pong):
print('ponged:',pong)
def run_forever(self,ping_interval=None,on_ping=None):
if ping_interval:
self._ping_interval = ping_interval
self._event = threading.Event()
self._flag = True
self.on_ping = on_ping
super().run_forever()