def sign(self, request: Request) -> Request: """ Generate OKEXo signature. """ # Sign timestamp = get_timestamp() request.data = json.dumps(request.data) if request.params: path = request.path + "?" + urlencode(request.params) else: path = request.path msg = timestamp + request.method + path + request.data signature = generate_signature(msg, self.secret) # Add headers request.headers = { "OK-ACCESS-KEY": self.key, "OK-ACCESS-SIGN": signature, "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": self.passphrase, "Content-Type": "application/json" } return request
def sign(self, request: Request) -> Request: """生成欧易V5签名""" # 签名 timestamp: str = generate_timestamp() request.data = json.dumps(request.data) if request.params: path: str = request.path + "?" + urlencode(request.params) else: path: str = request.path msg: str = timestamp + request.method + path + request.data signature: bytes = generate_signature(msg, self.secret) # 添加请求头 request.headers = { "OK-ACCESS-KEY": self.key, "OK-ACCESS-SIGN": signature, "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": self.passphrase, "Content-Type": "application/json" } if self.simulated: request.headers["x-simulated-trading"] = "1" return request
def sign(self, request: Request): request.headers = {"Content-Type": "application/json"} if request.method == "POST": if request.data: request.json_data = request.data request.data = json.dumps(request.data) return request
def closeAll(self, symbol, standard_token=None): """以市价单的方式全平某个合约的当前仓位,若交易所支持批量下单,使用批量下单接口 Parameters ---------- symbols : str 所要平仓的合约代码,多个合约代码用逗号分隔开。 direction : str, optional 账户统一到某个币本位上 Return ------ vtOrderIDs: list of str 包含平仓操作发送的所有订单ID的列表 """ if not standard_token: return [] vtOrderIDs = [] base_currency, quote_currency = symbol.split("-") if base_currency == standard_token: path = f'/api/spot/v3/accounts/{str.lower(quote_currency)}' side = 'buy' elif quote_currency == standard_token: path = f'/api/spot/v3/accounts/{str.lower(base_currency)}' side = 'sell' else: return [] # 币对双方都不是指定的本位 request = Request('GET', path, params=None, callback=None, data=None, headers=None) request = self.sign2(request) request.extra = {"instrument_id": symbol, "side": side} url = self.makeFullUrl(request.path) response = requests.get(url, headers=request.headers, params=request.params) data = response.json() rsp = self.onCloseAll(data, request) # rsp: [{'client_oid': '', 'order_id': '2433076975049728', 'result': True}] # failed: [{'code': 30024, 'message': 'Parameter value filling error'}] for result in rsp: if "code" in result.keys(): self.gateway.writeLog(f'换币失败:{result}', logging.ERROR) elif "result" in result.keys(): if result['result']: vtOrderIDs.append(result['order_id']) self.gateway.writeLog(f'换币成功:{result}') return vtOrderIDs
def cancelAll(self, symbol=None, orders=None): """撤销所有挂单,若交易所支持批量撤单,使用批量撤单接口 Parameters ---------- symbol : str, optional 用逗号隔开的多个合约代码,表示只撤销这些合约的挂单(默认为None,表示撤销所有合约的所有挂单) orders : str, optional 用逗号隔开的多个vtOrderID. 若为None,先从交易所先查询所有未完成订单作为待撤销订单列表进行撤单; 若不为None,则对给出的对应订单中和symbol参数相匹配的订单作为待撤销订单列表进行撤单。 Return ------ vtOrderIDs: list of str 包含本次所有撤销的订单ID的列表 """ vtOrderIDs = [] # 未完成(未成交和部分成交) req = { 'instrument_id': symbol, } path = f'/api/spot/v3/orders_pending' request = Request('GET', path, params=req, callback=None, data=None, headers=None) request = self.sign2(request) request.extra = orders url = self.makeFullUrl(request.path) response = requests.get(url, headers=request.headers, params=request.params) data = response.json() if data: rsp = self.onCancelAll(data, request) # failed rsp: {'code': 33027, 'message': 'Order has been revoked or revoked'} if "code" in rsp.keys(): self.gateway.writeLog(f"交易所返回{symbol}撤单失败:{rsp['message']}", logging.ERROR) return [] # rsp: {'eth-usdt': # {'result': True, 'client_oid': '', # 'order_id': ['2432470701654016', '2432470087389184', '2432469715472384']}} for sym, result in rsp.items(): if result['result']: vtOrderIDs += result['order_id'] self.gateway.writeLog( f"交易所返回{sym}撤单成功: ids: {result['order_id']}") return vtOrderIDs
def onCancelAll(self, data, request): orderids = [ str(order['order_id']) for order in data if str(order['state']) in ['0', '1', '3'] ] if request.extra: orderids = list( set(orderids).intersection(set(request.extra.split(",")))) for i in range(len(orderids) // 10 + 1): orderid = orderids[i * 10:(i + 1) * 10] req = { 'instrument_id': request.params['instrument_id'], 'order_ids': orderid } path = f"/api/futures/v3/cancel_batch_orders/{request.params['instrument_id']}" # self.addRequest('POST', path, data=req, callback=self.onCancelAll) request = Request('POST', path, params=None, callback=None, data=req, headers=None) request = self.sign(request) url = self.makeFullUrl(request.path) response = requests.post(url, headers=request.headers, data=request.data) return response.json()
def onCloseAll(self, data, request): l = [] def _response(request, l): request = self.sign(request) url = self.makeFullUrl(request.path) response = requests.post(url, headers=request.headers, data=request.data) l.append(response.json()) return l for holding in data['holding']: path = '/api/swap/v3/order' closeDirectionMap = {"long": 3, "short": 4} req = { 'client_oid': None, 'instrument_id': holding['instrument_id'], 'type': closeDirectionMap[holding['side']], 'price': holding['avg_cost'], 'size': holding['avail_position'], 'match_price': '1' } request = Request('POST', path, params=None, callback=None, data=req, headers=None) l = _response(request, l) return l
def sign(self, request: Request): """ Generate ByBit signature. """ request.headers = {"Referer": "vn.py"} if request.method == "GET": api_params = request.params if api_params is None: api_params = request.params = {} else: api_params = request.data if api_params is None: api_params = request.data = {} api_params["api_key"] = self.key api_params["recv_window"] = 30 * 1000 api_params["timestamp"] = generate_timestamp(-5) data2sign = "&".join( [f"{k}={v}" for k, v in sorted(api_params.items())]) signature = sign(self.secret, data2sign.encode()) api_params["sign"] = signature return request
def onCloseAll(self, data, request): l = [] def _response(request, l): request = self.sign(request) url = self.makeFullUrl(request.path) response = requests.post(url, headers=request.headers, data=request.data) l.append(response.json()) return l req = { 'client_oid': None, 'instrument_id': request.extra['instrument_id'], 'type': "market", 'side': request.extra['side'], 'notional': data['available'], # buy amount 'size': data['available'] # sell quantity } if self.leverage > 0: req["margin_trading"] = 2 else: req["margin_trading"] = 1 path = '/api/spot/v3/orders' request = Request('POST', path, params=None, callback=None, data=req, headers=None) l = _response(request, l) return l
def onCancelAll(self, data, request): orderids = [ str(order['order_id']) for order in data if order['status'] == 'open' or order['status'] == 'part_filled' ] if request.extra: orderids = list( set(orderids).intersection(set(request.extra.split(",")))) for i in range(len(orderids) // 10 + 1): orderid = orderids[i * 10:(i + 1) * 10] req = [{ 'instrument_id': str.lower(request.params['instrument_id']), 'order_ids': orderid }] path = "/api/spot/v3/cancel_batch_orders" # self.addRequest('POST', path, data=req, callback=self.onCancelAll) request = Request('POST', path, params=None, callback=None, data=req, headers=None) request = self.sign(request) url = self.makeFullUrl(request.path) response = requests.post(url, headers=request.headers, data=request.data) return response.json()
def closeAll(self, symbol, direction=None): """以市价单的方式全平某个合约的当前仓位,若交易所支持批量下单,使用批量下单接口 Parameters ---------- symbols : str 所要平仓的合约代码,多个合约代码用逗号分隔开。 direction : str, optional 所要平仓的方向,() 默认为None,即在两个方向上都进行平仓,否则只在给出的方向上进行平仓 Return ------ vtOrderIDs: list of str 包含平仓操作发送的所有订单ID的列表 """ vtOrderIDs = [] req = { 'instrument_id': symbol, } path = f'/api/swap/v3/{symbol}/position/' request = Request('GET', path, params=req, callback=None, data=None, headers=None) request = self.sign2(request) request.extra = direction url = self.makeFullUrl(request.path) response = requests.get(url, headers=request.headers, params=request.params) data = response.json() if data['holding']: rsp = self.onCloseAll(data, request) # failed:{'error_message': 'Incorrect order size', 'result': 'true', # 'error_code': '35012', 'order_id': '-1'} # rsp: {'error_message': '', 'result': 'true', 'error_code': '0', # 'order_id': '66-a-4ec048f15-0'} for result in rsp: if not result['error_message']: vtOrderIDs.append(result['order_id']) self.gateway.writeLog(f'平仓成功:{result}') else: self.gateway.writeLog(f'平仓失败:{result}', logging.ERROR) return vtOrderIDs
def sign(self, request: Request): """ Sign Bitstamp request. """ if request.method == "GET": return request timestamp = str(int(round(time.time() * 1000))) nonce = str(uuid.uuid4()) content_type = "application/x-www-form-urlencoded" # Empty post data leads to API0020 error, # so use this offset dict instead. if not request.data: request.data = {"offset": "1"} payload_str = urlencode(request.data) message = "BITSTAMP " + self.key + \ request.method + \ "www.bitstamp.net/api/v2" + \ request.path + \ "" + \ content_type + \ nonce + \ timestamp + \ "v2" + \ payload_str message = message.encode("utf-8") signature = hmac.new( self.secret, msg=message, digestmod=hashlib.sha256 ).hexdigest().upper() request.headers = { "X-Auth": "BITSTAMP " + self.key, "X-Auth-Signature": signature, "X-Auth-Nonce": nonce, "X-Auth-Timestamp": timestamp, "X-Auth-Version": "v2", "Content-Type": content_type } request.data = payload_str return request
def _process_request( self, request: Request ): """ Bistamp API server does not support keep-alive connection. So when using session.request will cause header related error. Reimplement this method to use requests.request instead. """ try: request = self.sign(request) url = self.make_full_url(request.path) response = requests.request( request.method, url, headers=request.headers, params=request.params, data=request.data, proxies=self.proxies, ) request.response = response status_code = response.status_code if status_code // 100 == 2: # 2xx codes are all successful if status_code == 204: json_body = None else: json_body = response.json() request.callback(json_body, request) request.status = RequestStatus.success else: request.status = RequestStatus.failed if request.on_failed: request.on_failed(status_code, request) else: self.on_failed(status_code, request) except Exception: request.status = RequestStatus.error t, v, tb = sys.exc_info() if request.on_error: request.on_error(t, v, tb, request) else: self.on_error(t, v, tb, request)
def cancelAll(self, symbol=None, orders=None): """撤销所有挂单,若交易所支持批量撤单,使用批量撤单接口 Parameters ---------- symbol : str, optional 用逗号隔开的多个合约代码,表示只撤销这些合约的挂单(默认为None,表示撤销所有合约的所有挂单) orders : str, optional 用逗号隔开的多个vtOrderID. 若为None,先从交易所先查询所有未完成订单作为待撤销订单列表进行撤单; 若不为None,则对给出的对应订单中和symbol参数相匹配的订单作为待撤销订单列表进行撤单。 Return ------ vtOrderIDs: list of str 包含本次所有撤销的订单ID的列表 """ vtOrderIDs = [] symbol = self.contractMapReverse[symbol] # 未完成(包含未成交和部分成交) req = {'instrument_id': symbol, 'state': 6} path = f'/api/futures/v3/orders/{symbol}' request = Request('GET', path, params=req, callback=None, data=None, headers=None) request = self.sign2(request) request.extra = orders url = self.makeFullUrl(request.path) response = requests.get(url, headers=request.headers, params=request.params) data = response.json() if data['result'] and data['order_info']: data = self.onCancelAll(data['order_info'], request) #{'result': True, # 'order_ids': ['2432685818596352', '2432686510479360'], # 'instrument_id': 'ETH-USD-190329'} if data['result']: vtOrderIDs += str(data['order_ids']) self.gateway.writeLog( f"交易所返回{str(data['instrument_id'])} 撤单成功: ids: {str(data['order_ids'])}" ) return vtOrderIDs
def cancelAll(self, symbol=None, orders=None): """撤销所有挂单,若交易所支持批量撤单,使用批量撤单接口 Parameters ---------- symbol : str, optional 用逗号隔开的多个合约代码,表示只撤销这些合约的挂单(默认为None,表示撤销所有合约的所有挂单) orders : str, optional 用逗号隔开的多个vtOrderID. 若为None,先从交易所先查询所有未完成订单作为待撤销订单列表进行撤单; 若不为None,则对给出的对应订单中和symbol参数相匹配的订单作为待撤销订单列表进行撤单。 Return ------ vtOrderIDs: list of str 包含本次所有撤销的订单ID的列表 """ vtOrderIDs = [] # 未完成(包含未成交和部分成交) req = {'state': 6} path = f'/api/swap/v3/orders/{symbol}' request = Request('GET', path, params=req, callback=None, data=None, headers=None) request = self.sign2(request) request.extra = orders url = self.makeFullUrl(request.path) response = requests.get(url, headers=request.headers, params=request.params) data = response.json() if data['order_info']: data = self.onCancelAll(data['order_info'], request) # {'client_oids': [], # 'ids': ['66-7-4ebc9281f-0', '66-8-4ebc91cfa-0'], # 'instrument_id': 'ETH-USD-SWAP', 'result': 'true'} if data['result'] == 'true': vtOrderIDs += data['ids'] self.gateway.writeLog(f"交易所返回{symbol}撤单成功: ids: {data['ids']}") return vtOrderIDs
def sign(self, request: Request) -> Request: """ Generate HUOBI signature. """ request.headers = { "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36" } params_with_signature = create_signature(self.key, request.method, self.host, request.path, self.secret, request.params) request.params = params_with_signature if request.method == "POST": request.headers["Content-Type"] = "application/json" if request.data: request.data = json.dumps(request.data) return request
def closeAll(self, symbol, direction=None): """以市价单的方式全平某个合约的当前仓位,若交易所支持批量下单,使用批量下单接口 Parameters ---------- symbols : str 所要平仓的合约代码,多个合约代码用逗号分隔开。 direction : str, optional 所要平仓的方向,(默认为None,即在两个方向上都进行平仓,否则只在给出的方向上进行平仓) Return ------ vtOrderIDs: list of str 包含平仓操作发送的所有订单ID的列表 """ vtOrderIDs = [] symbol = self.contractMapReverse[symbol] req = { 'instrument_id': symbol, } path = f'/api/futures/v3/{symbol}/position/' request = Request('GET', path, params=req, callback=None, data=None, headers=None) request = self.sign2(request) request.extra = direction url = self.makeFullUrl(request.path) response = requests.get(url, headers=request.headers, params=request.params) data = response.json() if data['result'] and data['holding']: data = self.onCloseAll(data, request) for result in data: if result['result']: vtOrderIDs.append(result['order_id']) self.gateway.writeLog(f'平仓成功:{result}') return vtOrderIDs
def sign(self, request: Request) -> Request: """ Generate SUGAR signature. """ signature = self.create_signature(request.data) request_time = datetime.strftime(datetime.now(),"%Y-%m-%d %H:%M:%S.%f") request_data = { "requestHeader":{ "token": self.token, "sign": signature, "yqMemberId": self.open_account, "merRequestNo": request_time, "merRequestTime": request_time[:-7] }, "requestBody": request.data } request.headers = {"Content-Type": "application/json"} request.data = json.dumps(request_data) return request
def sign(self, request: Request) -> Request: """ Generate BINANCE signature. """ security = request.data["security"] if security == Security.NONE: request.data = None return request if request.params: path = request.path + "?" + urllib.parse.urlencode(request.params) else: request.params = dict() path = request.path if security == Security.SIGNED: timestamp = int(time.time() * 1000) if self.time_offset > 0: timestamp -= abs(self.time_offset) elif self.time_offset < 0: timestamp += abs(self.time_offset) request.params["timestamp"] = timestamp query = urllib.parse.urlencode(sorted(request.params.items())) signature = hmac.new(self.secret, query.encode("utf-8"), hashlib.sha256).hexdigest() query += "&signature={}".format(signature) path = request.path + "?" + query request.path = path request.params = {} request.data = {} # Add headers headers = { "Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json", "X-MBX-APIKEY": self.key, "Connection": "close" } if security in [Security.SIGNED, Security.API_KEY]: request.headers = headers return request
def onCloseAll(self, data, request): l = [] def _response(request, l): request = self.sign(request) url = self.makeFullUrl(request.path) response = requests.post(url, headers=request.headers, data=request.data) l.append(response.json()) return l for holding in data['holding']: path = '/api/futures/v3/order' req_long = { 'client_oid': None, 'instrument_id': holding['instrument_id'], 'type': '3', 'price': holding['long_avg_cost'], 'size': str(holding['long_avail_qty']), 'match_price': '1', 'leverage': self.leverage, } req_short = { 'client_oid': None, 'instrument_id': holding['instrument_id'], 'type': '4', 'price': holding['short_avg_cost'], 'size': str(holding['short_avail_qty']), 'match_price': '1', 'leverage': self.leverage, } if request.extra and request.extra == constant.DIRECTION_LONG and int( holding['long_avail_qty']) > 0: # 多仓可平 request = Request('POST', path, params=None, callback=None, data=req_long, headers=None) l = _response(request, l) elif request.extra and request.extra == constant.DIRECTION_SHORT and int( holding['short_avail_qty']) > 0: # 空仓可平 request = Request('POST', path, params=None, callback=None, data=req_short, headers=None) l = _response(request, l) elif request.extra is None: if int(holding['long_avail_qty']) > 0: # 多仓可平 request = Request('POST', path, params=None, callback=None, data=req_long, headers=None) l = _response(request, l) if int(holding['short_avail_qty']) > 0: # 空仓可平 request = Request('POST', path, params=None, callback=None, data=req_short, headers=None) l = _response(request, l) return l