async def on_ticker(self, *args, **kwargs): """ 定时执行任务 """ if self.trader.assets is None: return if self.trader.position is None: return ts_diff = int(time.time() * 1000) - self.last_orderbook_timestamp if ts_diff > self.orderbook_invalid_seconds * 1000: logger.warn("received orderbook timestamp exceed:", self.strategy, self.symbol, ts_diff, caller=self) return # 获取标记价格,每次的挂单价格与指数价格进行比较。 success, error = await self.trader.rest_api.get_market_index( contract_code=self.symbol) if error: logger.error("Get swap market index faild:", error, caller=self) else: for item in success["data"]: if item["contract_code"] == self.symbol: self.mark_price = item["mark_price"] await self.cancel_orders() await self.place_orders()
async def sub_callback(self, data): if data["err-code"] != 0: e = Error("subscribe {} failed!".format(data["topic"])) logger.error(e, caller=self) SingleTask.run(self._init_success_callback, False, e) return if data["topic"] == self._order_channel: self._subscribe_order_ok = True elif data["topic"] == self._position_channel: self._subscribe_position_ok = True elif data["topic"] == self._asset_channel: self._subscribe_asset_ok = True if self._subscribe_order_ok and self._subscribe_position_ok \ and self._subscribe_asset_ok: success, error = await self._rest_api.get_open_orders(self._symbol) if error: e = Error("get open orders failed!") SingleTask.run(self._init_success_callback, False, e) elif "data" in success and "orders" in success["data"]: for order_info in success["data"]["orders"]: order_info["ts"] = order_info["created_at"] self._update_order(order_info) SingleTask.run(self._init_success_callback, True, None) else: logger.warn("get open orders:", success, caller=self) e = Error("Get Open Orders Unknown error") SingleTask.run(self._init_success_callback, False, e)
async def _send_heartbeat_msg(self, *args, **kwargs): """ 发送心跳给服务器 """ if not self.ws: logger.warn("websocket connection not connected yet!", caller=self) return data = {"pong": int(time.time()*1000)} await self.ws.send_json(data)
async def place_orders(self): """ 下单 """ orders_data = [] if self.trader.position and self.trader.position.short_quantity: # 平空单 price = round(self.mark_price - self.spread, 1) quantity = -self.trader.position.short_quantity action = ORDER_ACTION_BUY new_price = str(price) # 将价格转换为字符串,保持精度 if quantity: orders_data.append({"price": new_price, "quantity": quantity, "action": action, "order_type": ORDER_TYPE_LIMIT }) self.last_mark_price = self.mark_price if self.trader.position and self.trader.position.long_quantity: # 平多单 price = round(self.mark_price + self.spread, 1) quantity = self.trader.position.long_quantity action = ORDER_ACTION_SELL new_price = str(price) # 将价格转换为字符串,保持精度 if quantity: orders_data.append({"price": new_price, "quantity": quantity, "action": action, "order_type": ORDER_TYPE_LIMIT }) self.last_mark_price = self.mark_price if self.trader.assets and self.trader.assets.assets.get(self.raw_symbol).get("free"): # 开空单 if self.trader.position and self.trader.position.short_quantity and self.trader.position.short_quantity >= self.max_quantity: logger.warn("option short position exceeds the max quantity: ", self.symbol, self.trader.position.short_quantity, self.max_quantity, caller=self) else: price = round(self.mark_price + self.spread, 1) volume = self.volume if volume: quantity = - volume # 空张 action = ORDER_ACTION_SELL new_price = str(price) # 将价格转换为字符串,保持精度 if quantity: orders_data.append({"price": new_price, "quantity": quantity, "action": action, "order_type": ORDER_TYPE_LIMIT }) self.last_mark_price = self.mark_price if self.trader.assets and self.trader.assets.assets.get(self.partition_symbol).get("free"): # 开多单 if self.trader.position and self.trader.position.long_quantity and self.trader.position.long_quantity >= self.max_quantity: logger.warn("option long position exceeds the max quantity: ", self.symbol, self.trader.position.long_quantity, self.max_quantity, caller=self) else: price = round(self.mark_price - self.spread, 1) volume = self.volume if volume: quantity = volume # 多张 action = ORDER_ACTION_BUY new_price = str(price) # 将价格转换为字符串,保持精度 if quantity: orders_data.append({"price": new_price, "quantity": quantity, "action": action, "order_type": ORDER_TYPE_LIMIT }) self.last_mark_price = self.mark_price if orders_data: order_nos, error = await self.trader.create_orders(orders_data) if error: logger.error(self.strategy, "create future order error! error:", error, caller=self) logger.info(self.strategy, "create future orders success:", order_nos, caller=self)
async def on_ticker(self, *args, **kwargs): """ 定时执行任务 """ ts_diff = int(time.time()*1000) - self.last_orderbook_timestamp if ts_diff > self.orderbook_invalid_seconds * 1000: logger.warn("received orderbook timestamp exceed:", self.strategy, self.symbol, ts_diff, caller=self) return await self.cancel_orders() await self.place_orders()
async def _check_connection(self, *args, **kwargs): """ 检查连接是否正常 """ # 检查websocket连接是否关闭,如果关闭,那么立即重连 if not self.ws: logger.warn("websocket connection not connected yet!", caller=self) return if self.ws.closed: await asyncio.get_event_loop().create_task(self._reconnect()) return
async def _send_heartbeat_msg(self, *args, **kwargs): """ 发送心跳给服务器 """ if not self.ws: logger.warn("websocket connection not connected yet!", caller=self) return data = {"pong": int(time.time() * 1000)} try: await self.ws.send_json(data) except ConnectionResetError: await asyncio.get_event_loop().create_task(self._reconnect())
async def place_orders(self): """ 下单 """ orders_data = [] if self.trader.position and self.trader.position.short_quantity: # 平空单 price = round(self.ask1_price - 0.1, 1) #quantity = -self.trader.position.short_quantity quantity = -1 action = ORDER_ACTION_BUY new_price = str(price) # 将价格转换为字符串,保持精度 if quantity: orders_data.append({ "price": new_price, "quantity": quantity, "action": action, "order_type": ORDER_TYPE_LIMIT, "lever_rate": 5 }) self.last_ask_price = self.ask1_price if self.trader.assets and self.trader.assets.assets.get( self.raw_symbol): # 开空单 price = round(self.bid1_price + 0.1, 1) #volume = int(float(self.trader.assets.assets.get(self.raw_symbol).get("free")) * 5/ price / self.contract_size) volume = 1 if volume >= 1: quantity = -volume # 空1张 action = ORDER_ACTION_SELL new_price = str(price) # 将价格转换为字符串,保持精度 if quantity: orders_data.append({ "price": new_price, "quantity": quantity, "action": action, "order_type": ORDER_TYPE_LIMIT, "lever_rate": 5 }) self.last_bid_price = self.bid1_price if orders_data: order_nos, error = await self.trader.create_orders(orders_data) if error: logger.warn(self.strategy, "create future order error! error:", error, caller=self) logger.info(self.strategy, "create future orders success:", order_nos, caller=self)
async def receive(self): """ 接收消息 """ async for msg in self.ws: if msg.type == aiohttp.WSMsgType.TEXT: try: data = json.loads(msg.data) except: data = msg.data await asyncio.get_event_loop().create_task(self.process(data)) elif msg.type == aiohttp.WSMsgType.BINARY: await asyncio.get_event_loop().create_task( self.process_binary(msg.data)) elif msg.type == aiohttp.WSMsgType.CLOSED: logger.warn("receive event CLOSED:", msg, caller=self) await asyncio.get_event_loop().create_task(self._reconnect()) elif msg.type == aiohttp.WSMsgType.CLOSE: logger.warn("receive event CLOSE:", msg, caller=self) await asyncio.get_event_loop().create_task(self._reconnect()) elif msg.type == aiohttp.WSMsgType.CLOSING: logger.warn("receive event CLOSING:", msg, caller=self) await asyncio.get_event_loop().create_task(self._reconnect()) elif msg.type == aiohttp.WSMsgType.ERROR: logger.error("receive event ERROR:", msg, caller=self) await asyncio.get_event_loop().create_task(self._reconnect()) else: logger.warn("unhandled msg:", msg, caller=self)
async def on_ticker(self, *args, **kwargs): """ 定时执行任务 """ success, error = await self.trader.rest_api.get_hisopen_orders("ETH") import ipdb ipdb.set_trace() ts_diff = int(time.time() * 1000) - self.last_orderbook_timestamp if ts_diff > self.orderbook_invalid_seconds * 1000: logger.warn("received orderbook timestamp exceed:", self.strategy, self.symbol, ts_diff, caller=self) return await self.cancel_orders() await self.place_orders()
async def _send_heartbeat_msg(self, *args, **kwargs): """ 发送心跳给服务器 """ if not self.ws: logger.warn("websocket connection not connected yet!", caller=self) return if self.heartbeat_msg: try: if isinstance(self.heartbeat_msg, dict): await self.ws.send_json(self.heartbeat_msg) elif isinstance(self.heartbeat_msg, str): await self.ws.send_str(self.heartbeat_msg) else: logger.error("send heartbeat msg failed! heartbeat msg:", self.heartbeat_msg, caller=self) return logger.debug("send ping message:", self.heartbeat_msg, caller=self) except ConnectionResetError: traceback.print_exc() await asyncio.get_event_loop().create_task(self._reconnect())
async def _reconnect(self): """ 重新建立websocket连接 """ logger.warn("reconnecting websocket right now!", caller=self) await self._connect()
async def fetch(cls, method, url, params=None, body=None, data=None, headers=None, timeout=30, **kwargs): """ Create a HTTP request. Args: method: HTTP request method. (GET/POST/PUT/DELETE) url: Request url. params: HTTP query params. body: HTTP request body, string or bytes format. data: HTTP request body, dict format. headers: HTTP request header. timeout: HTTP request timeout(seconds), default is 30s. kwargs: proxy: HTTP proxy. Return: code: HTTP response code. success: HTTP response data. If something wrong, this field is None. error: If something wrong, this field will holding a Error information, otherwise it's None. Raises: HTTP request exceptions or response data parse exceptions. All the exceptions will be captured and return Error information. """ session = cls._get_session(url) if not kwargs.get("proxy"): kwargs["proxy"] = config.proxy try: if method == "GET": response = await session.get(url, params=params, headers=headers, timeout=timeout, **kwargs) elif method == "POST": response = await session.post(url, params=params, data=body, json=data, headers=headers, timeout=timeout, **kwargs) elif method == "PUT": response = await session.put(url, params=params, data=body, json=data, headers=headers, timeout=timeout, **kwargs) elif method == "DELETE": response = await session.delete(url, params=params, data=body, json=data, headers=headers, timeout=timeout, **kwargs) else: error = "http method error!" return None, None, error except Exception as e: logger.error("method:", method, "url:", url, "headers:", headers, "params:", params, "body:", body, "data:", data, "Error:", e, caller=cls) return None, None, e code = response.status if code not in (200, 201, 202, 203, 204, 205, 206): text = await response.text() logger.error("method:", method, "url:", url, "headers:", headers, "params:", params, "body:", body, "data:", data, "code:", code, "result:", text, caller=cls) return code, None, text try: result = await response.json() except: result = await response.text() logger.warn("response data is not json format!", "method:", method, "url:", url, "headers:", headers, "params:", params, "body:", body, "data:", data, "code:", code, "result:", result, caller=cls) logger.debug("method:", method, "url:", url, "headers:", headers, "params:", params, "body:", body, "data:", data, "code:", code, "result:", json.dumps(result), caller=cls) return code, result, None